From e5f933f78f5c46dbc2fced882d8163b0c45cea4d Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Fri, 8 Dec 2017 15:59:55 +0100 Subject: [PATCH] Added the latest changes to the third-party projects. --- Sming/third-party/ESP8266_NONOS_SDK | 1 - Sming/third-party/ESP8266_NONOS_SDK/License | 24 + Sming/third-party/ESP8266_NONOS_SDK/Makefile | 396 + Sming/third-party/ESP8266_NONOS_SDK/README.md | 3 + Sming/third-party/ESP8266_NONOS_SDK/VERSION | 23 + .../bin/at/1024+1024/user1.2048.new.5.bin | Bin 0 -> 427060 bytes .../bin/at/1024+1024/user2.2048.new.5.bin | Bin 0 -> 427060 bytes .../bin/at/512+512/user1.1024.new.2.bin | Bin 0 -> 427060 bytes .../bin/at/512+512/user2.1024.new.2.bin | Bin 0 -> 427060 bytes .../ESP8266_NONOS_SDK/bin/at/README.md | 81 + .../at_sdio/1024+1024/user1.2048.new.5.bin | Bin 0 -> 428980 bytes .../at_sdio/1024+1024/user2.2048.new.5.bin | Bin 0 -> 428980 bytes .../bin/at_sdio/512+512/user1.1024.new.2.bin | Bin 0 -> 428980 bytes .../bin/at_sdio/512+512/user2.1024.new.2.bin | Bin 0 -> 428980 bytes .../ESP8266_NONOS_SDK/bin/at_sdio/README.md | 81 + .../ESP8266_NONOS_SDK/bin/blank.bin | 1 + .../ESP8266_NONOS_SDK/bin/boot_v1.2.bin | Bin 0 -> 1936 bytes .../ESP8266_NONOS_SDK/bin/boot_v1.6.bin | Bin 0 -> 3856 bytes .../ESP8266_NONOS_SDK/bin/boot_v1.7.bin | Bin 0 -> 4080 bytes .../bin/esp_init_data_default.bin | Bin 0 -> 128 bytes .../ESP8266_NONOS_SDK/documents/readme.txt | 2 + .../ESP8266_NONOS_SDK/driver_lib/Makefile | 124 + .../ESP8266_NONOS_SDK/driver_lib/README.md | 22 + .../driver_lib/driver/Makefile | 44 + .../driver_lib/driver/gpio16.c | 66 + .../driver_lib/driver/hw_timer.c | 162 + .../driver_lib/driver/i2c_master.c | 330 + .../ESP8266_NONOS_SDK/driver_lib/driver/key.c | 177 + .../driver_lib/driver/sdio_slv.c | 457 + .../ESP8266_NONOS_SDK/driver_lib/driver/spi.c | 487 ++ .../driver_lib/driver/spi_interface.c | 502 ++ .../driver_lib/driver/spi_overlap.c | 422 + .../driver_lib/driver/uart.c | 796 ++ .../driver_lib/include/driver/gpio16.h | 33 + .../driver_lib/include/driver/i2c_master.h | 81 + .../driver_lib/include/driver/key.h | 51 + .../driver_lib/include/driver/sdio_slv.h | 40 + .../driver_lib/include/driver/slc_register.h | 300 + .../driver_lib/include/driver/spi.h | 74 + .../driver_lib/include/driver/spi_interface.h | 353 + .../driver_lib/include/driver/spi_overlap.h | 85 + .../driver_lib/include/driver/spi_register.h | 222 + .../driver_lib/include/driver/uart.h | 229 + .../driver_lib/include/driver/uart_register.h | 159 + .../ESP8266_NONOS_SDK/driver_lib/make_lib.sh | 14 + .../examples/IoT_Demo/Makefile | 127 + .../examples/IoT_Demo/driver/Makefile | 44 + .../examples/IoT_Demo/driver/i2c_master.c | 330 + .../examples/IoT_Demo/driver/key.c | 177 + .../examples/IoT_Demo/gen_misc.bat | 147 + .../examples/IoT_Demo/gen_misc.sh | 163 + .../IoT_Demo/include/driver/i2c_master.h | 81 + .../examples/IoT_Demo/include/driver/key.h | 51 + .../examples/IoT_Demo/include/ssl/cert.h | 60 + .../IoT_Demo/include/ssl/private_key.h | 54 + .../examples/IoT_Demo/include/user_config.h | 88 + .../IoT_Demo/include/user_devicefind.h | 30 + .../IoT_Demo/include/user_esp_platform.h | 57 + .../include/user_esp_platform_timer.h | 30 + .../IoT_Demo/include/user_iot_version.h | 67 + .../examples/IoT_Demo/include/user_json.h | 41 + .../examples/IoT_Demo/include/user_light.h | 88 + .../IoT_Demo/include/user_light_adj.h | 57 + .../examples/IoT_Demo/include/user_plug.h | 67 + .../examples/IoT_Demo/include/user_sensor.h | 56 + .../IoT_Demo/include/user_webserver.h | 69 + .../examples/IoT_Demo/user/Makefile | 45 + .../examples/IoT_Demo/user/user_devicefind.c | 134 + .../IoT_Demo/user/user_esp_platform.c | 1396 +++ .../IoT_Demo/user/user_esp_platform_timer.c | 358 + .../examples/IoT_Demo/user/user_json.c | 177 + .../examples/IoT_Demo/user/user_light.c | 155 + .../examples/IoT_Demo/user/user_light_adj.c | 357 + .../examples/IoT_Demo/user/user_main.c | 128 + .../examples/IoT_Demo/user/user_plug.c | 173 + .../examples/IoT_Demo/user/user_sensor.c | 244 + .../examples/IoT_Demo/user/user_webserver.c | 1804 ++++ .../examples/at/!!!readme!!!.txt | 42 + .../ESP8266_NONOS_SDK/examples/at/Makefile | 154 + .../examples/at/gen_misc.bat | 147 + .../ESP8266_NONOS_SDK/examples/at/gen_misc.sh | 165 + .../examples/at/include/user_config.h | 36 + .../examples/at/user/Makefile | 45 + .../examples/at/user/at_upgrade.c | 304 + .../examples/at/user/user_main.c | 187 + .../examples/at_espconn/!!!readme!!!.txt | 42 + .../examples/at_espconn/Makefile | 150 + .../examples/at_espconn/gen_misc.bat | 147 + .../examples/at_espconn/gen_misc.sh | 165 + .../examples/at_espconn/include/user_config.h | 36 + .../examples/at_espconn/user/Makefile | 45 + .../examples/at_espconn/user/at_upgrade.c | 304 + .../examples/at_espconn/user/user_main.c | 215 + .../examples/at_sdio/Makefile | 157 + .../examples/at_sdio/driver/Makefile | 44 + .../examples/at_sdio/driver/sdio_slv.c | 493 ++ .../examples/at_sdio/gen_misc.bat | 27 + .../examples/at_sdio/gen_misc.sh | 165 + .../at_sdio/include/driver/sdio_slv.h | 43 + .../at_sdio/include/driver/slc_register.h | 299 + .../examples/at_sdio/include/user_config.h | 36 + .../examples/at_sdio/include/version.h | 23 + .../examples/at_sdio/user/Makefile | 45 + .../examples/at_sdio/user/at_upgrade.c | 304 + .../examples/at_sdio/user/user_main.c | 230 + .../examples/esp_mqtt_proj/Makefile | 131 + .../examples/esp_mqtt_proj/README.md | 77 + .../examples/esp_mqtt_proj/gen_misc.bat | 147 + .../examples/esp_mqtt_proj/gen_misc.sh | 165 + .../esp_mqtt_proj/include/driver/uart.h | 125 + .../include/driver/uart_register.h | 147 + .../esp_mqtt_proj/include/modules/config.h | 61 + .../esp_mqtt_proj/include/modules/wifi.h | 15 + .../esp_mqtt_proj/include/mqtt/debug.h | 23 + .../esp_mqtt_proj/include/mqtt/mqtt.h | 148 + .../esp_mqtt_proj/include/mqtt/mqtt_msg.h | 130 + .../esp_mqtt_proj/include/mqtt/proto.h | 32 + .../esp_mqtt_proj/include/mqtt/queue.h | 44 + .../esp_mqtt_proj/include/mqtt/ringbuf.h | 19 + .../esp_mqtt_proj/include/mqtt/typedef.h | 17 + .../esp_mqtt_proj/include/mqtt/utils.h | 9 + .../esp_mqtt_proj/include/mqtt_config.h | 46 + .../esp_mqtt_proj/include/user_config.h | 7 + .../examples/esp_mqtt_proj/modules/Makefile | 44 + .../examples/esp_mqtt_proj/modules/config.c | 110 + .../examples/esp_mqtt_proj/modules/wifi.c | 100 + .../examples/esp_mqtt_proj/mqtt/Makefile | 44 + .../esp_mqtt_proj/mqtt/include/debug.h | 23 + .../esp_mqtt_proj/mqtt/include/mqtt.h | 148 + .../esp_mqtt_proj/mqtt/include/mqtt_msg.h | 130 + .../esp_mqtt_proj/mqtt/include/proto.h | 32 + .../esp_mqtt_proj/mqtt/include/queue.h | 44 + .../esp_mqtt_proj/mqtt/include/ringbuf.h | 19 + .../esp_mqtt_proj/mqtt/include/typedef.h | 17 + .../esp_mqtt_proj/mqtt/include/utils.h | 9 + .../examples/esp_mqtt_proj/mqtt/mqtt.c | 894 ++ .../examples/esp_mqtt_proj/mqtt/mqtt_msg.c | 473 + .../examples/esp_mqtt_proj/mqtt/proto.c | 129 + .../examples/esp_mqtt_proj/mqtt/queue.c | 57 + .../examples/esp_mqtt_proj/mqtt/ringbuf.c | 67 + .../examples/esp_mqtt_proj/mqtt/utils.c | 149 + .../examples/esp_mqtt_proj/user/Makefile | 44 + .../examples/esp_mqtt_proj/user/user_main.c | 192 + .../examples/peripheral_test/Makefile | 121 + .../examples/peripheral_test/gen_misc.bat | 147 + .../examples/peripheral_test/gen_misc.sh | 165 + .../peripheral_test/include/spi_test.h | 52 + .../peripheral_test/include/user_config.h | 29 + .../examples/peripheral_test/user/Makefile | 45 + .../examples/peripheral_test/user/spi_test.c | 268 + .../examples/peripheral_test/user/user_main.c | 94 + .../ESP8266_NONOS_SDK/examples/readme.txt | 40 + .../examples/simple_pair/Makefile | 121 + .../examples/simple_pair/gen_misc.bat | 147 + .../examples/simple_pair/gen_misc.sh | 165 + .../simple_pair/include/user_config.h | 29 + .../examples/simple_pair/user/Makefile | 45 + .../examples/simple_pair/user/user_main.c | 345 + .../examples/smart_config/!!!readme!!!.txt | 8 + .../examples/smart_config/Makefile | 125 + .../examples/smart_config/gen_misc.bat | 147 + .../examples/smart_config/gen_misc.sh | 165 + .../smart_config/include/user_config.h | 29 + .../smart_config/model two-dimension code.rar | Bin 0 -> 15386 bytes .../examples/smart_config/user/Makefile | 45 + .../examples/smart_config/user/user_main.c | 260 + .../examples/wpa2_enterprise/Makefile | 122 + .../examples/wpa2_enterprise/gen_misc.bat | 147 + .../examples/wpa2_enterprise/gen_misc.sh | 165 + .../wpa2_enterprise/include/user_config.h | 29 + .../wpa2_enterprise/include/wpa2_pki/ca.h | 89 + .../include/wpa2_pki/certs/ca.der | Bin 0 -> 992 bytes .../include/wpa2_pki/certs/ca.key | 16 + .../include/wpa2_pki/certs/ca.pem | 23 + .../include/wpa2_pki/certs/client.crt | 70 + .../include/wpa2_pki/certs/client.key | 27 + .../include/wpa2_pki/certs/client.p12 | Bin 0 -> 2453 bytes .../include/wpa2_pki/certs/client.pem | 57 + .../wpa2_enterprise/include/wpa2_pki/certs/dh | 5 + .../include/wpa2_pki/certs/server.crt | 70 + .../include/wpa2_pki/certs/server.key | 27 + .../include/wpa2_pki/certs/server.p12 | Bin 0 -> 2461 bytes .../include/wpa2_pki/certs/server.pem | 57 + .../include/wpa2_pki/client_crt.h | 237 + .../include/wpa2_pki/client_key.h | 106 + .../include/wpa2_pki/import_ca_crt_key.sh | 23 + .../wpa2_enterprise/include/wpa2_pki/str2hex | Bin 0 -> 8778 bytes .../examples/wpa2_enterprise/user/Makefile | 45 + .../examples/wpa2_enterprise/user/user_main.c | 145 + .../ESP8266_NONOS_SDK/examples/wps/Makefile | 123 + .../examples/wps/driver/Makefile | 44 + .../examples/wps/driver/key.c | 177 + .../examples/wps/gen_misc.bat | 147 + .../examples/wps/gen_misc.sh | 165 + .../examples/wps/include/driver/key.h | 51 + .../examples/wps/include/user_config.h | 29 + .../examples/wps/user/Makefile | 45 + .../examples/wps/user/user_main.c | 131 + .../ESP8266_NONOS_SDK/include/airkiss.h | 122 + .../ESP8266_NONOS_SDK/include/at_custom.h | 172 + .../ESP8266_NONOS_SDK/include/c_types.h | 114 + .../ESP8266_NONOS_SDK/include/eagle_soc.h | 279 + .../ESP8266_NONOS_SDK/include/espconn.h | 747 ++ .../ESP8266_NONOS_SDK/include/espnow.h | 73 + .../ESP8266_NONOS_SDK/include/ets_sys.h | 130 + .../ESP8266_NONOS_SDK/include/gpio.h | 119 + .../ESP8266_NONOS_SDK/include/ip_addr.h | 87 + .../ESP8266_NONOS_SDK/include/json/json.h | 70 + .../include/json/jsonparse.h | 94 + .../ESP8266_NONOS_SDK/include/json/jsontree.h | 145 + .../ESP8266_NONOS_SDK/include/mem.h | 88 + .../ESP8266_NONOS_SDK/include/mesh.h | 341 + .../ESP8266_NONOS_SDK/include/os_type.h | 37 + .../ESP8266_NONOS_SDK/include/osapi.h | 94 + .../ESP8266_NONOS_SDK/include/ping.h | 56 + .../ESP8266_NONOS_SDK/include/pwm.h | 58 + .../ESP8266_NONOS_SDK/include/queue.h | 236 + .../ESP8266_NONOS_SDK/include/simple_pair.h | 64 + .../ESP8266_NONOS_SDK/include/smartconfig.h | 50 + .../ESP8266_NONOS_SDK/include/sntp.h | 68 + .../ESP8266_NONOS_SDK/include/spi_flash.h | 61 + .../ESP8266_NONOS_SDK/include/upgrade.h | 74 + .../include/user_interface.h | 654 ++ .../include/wpa2_enterprise.h | 65 + .../ESP8266_NONOS_SDK/ld/eagle.app.v6.ld | 230 + .../ld/eagle.app.v6.new.1024.app1.ld | 230 + .../ld/eagle.app.v6.new.1024.app2.ld | 230 + .../ld/eagle.app.v6.new.2048.ld | 231 + .../ld/eagle.app.v6.new.512.app1.ld | 230 + .../ld/eagle.app.v6.new.512.app2.ld | 230 + .../ld/eagle.app.v6.old.1024.app1.ld | 230 + .../ld/eagle.app.v6.old.1024.app2.ld | 230 + .../ld/eagle.app.v6.old.512.app1.ld | 230 + .../ld/eagle.app.v6.old.512.app2.ld | 230 + .../ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld | 350 + .../ESP8266_NONOS_SDK/lib/libairkiss.a | Bin 0 -> 11298 bytes .../third-party/ESP8266_NONOS_SDK/lib/libat.a | Bin 0 -> 394948 bytes .../third-party/ESP8266_NONOS_SDK/lib/libc.a | Bin 0 -> 5001068 bytes .../ESP8266_NONOS_SDK/lib/libcrypto.a | Bin 0 -> 135458 bytes .../ESP8266_NONOS_SDK/lib/libdriver.a | Bin 0 -> 67252 bytes .../ESP8266_NONOS_SDK/lib/libespnow.a | Bin 0 -> 72138 bytes .../ESP8266_NONOS_SDK/lib/libgcc.a | Bin 0 -> 603000 bytes .../ESP8266_NONOS_SDK/lib/libjson.a | Bin 0 -> 18334 bytes .../ESP8266_NONOS_SDK/lib/liblwip.a | Bin 0 -> 321736 bytes .../ESP8266_NONOS_SDK/lib/liblwip_536.a | Bin 0 -> 354288 bytes .../ESP8266_NONOS_SDK/lib/libmain.a | Bin 0 -> 228174 bytes .../ESP8266_NONOS_SDK/lib/libmbedtls.a | Bin 0 -> 666800 bytes .../ESP8266_NONOS_SDK/lib/libmesh.a | Bin 0 -> 198260 bytes .../ESP8266_NONOS_SDK/lib/libnet80211.a | Bin 0 -> 330530 bytes .../ESP8266_NONOS_SDK/lib/libphy.a | Bin 0 -> 156962 bytes .../third-party/ESP8266_NONOS_SDK/lib/libpp.a | Bin 0 -> 237994 bytes .../ESP8266_NONOS_SDK/lib/libpwm.a | Bin 0 -> 28298 bytes .../ESP8266_NONOS_SDK/lib/libsmartconfig.a | Bin 0 -> 118416 bytes .../ESP8266_NONOS_SDK/lib/libssl.a | Bin 0 -> 275704 bytes .../ESP8266_NONOS_SDK/lib/libupgrade.a | Bin 0 -> 41158 bytes .../ESP8266_NONOS_SDK/lib/libwpa.a | Bin 0 -> 170764 bytes .../ESP8266_NONOS_SDK/lib/libwpa2.a | Bin 0 -> 475218 bytes .../ESP8266_NONOS_SDK/lib/libwps.a | Bin 0 -> 322676 bytes .../ESP8266_NONOS_SDK/lib/readme.md | 59 + .../lib/strip_libc_funcs.txt | 15 + .../lib/strip_libgcc_funcs.txt | 25 + .../ESP8266_NONOS_SDK/third_party/Makefile | 127 + .../third_party/include/arch/cc.h | 117 + .../third_party/include/arch/perf.h | 40 + .../third_party/include/arch/sys_arch.h | 0 .../third_party/include/lwip/api.h | 284 + .../third_party/include/lwip/api_msg.h | 174 + .../third_party/include/lwip/app/dhcpserver.h | 115 + .../third_party/include/lwip/app/espconn.h | 687 ++ .../include/lwip/app/espconn_buf.h | 60 + .../include/lwip/app/espconn_tcp.h | 58 + .../include/lwip/app/espconn_udp.h | 64 + .../third_party/include/lwip/app/ping.h | 85 + .../third_party/include/lwip/app/time.h | 49 + .../third_party/include/lwip/arch.h | 238 + .../third_party/include/lwip/autoip.h | 119 + .../third_party/include/lwip/debug.h | 98 + .../third_party/include/lwip/def.h | 127 + .../third_party/include/lwip/dhcp.h | 252 + .../third_party/include/lwip/dns.h | 124 + .../third_party/include/lwip/err.h | 86 + .../third_party/include/lwip/icmp.h | 115 + .../third_party/include/lwip/igmp.h | 106 + .../third_party/include/lwip/inet.h | 107 + .../third_party/include/lwip/inet_chksum.h | 90 + .../third_party/include/lwip/init.h | 73 + .../third_party/include/lwip/ip.h | 215 + .../third_party/include/lwip/ip_addr.h | 256 + .../third_party/include/lwip/ip_frag.h | 88 + .../third_party/include/lwip/mdns.h | 114 + .../third_party/include/lwip/mem.h | 166 + .../third_party/include/lwip/memp.h | 116 + .../third_party/include/lwip/memp_std.h | 126 + .../third_party/include/lwip/netbuf.h | 101 + .../third_party/include/lwip/netdb.h | 124 + .../third_party/include/lwip/netif.h | 320 + .../third_party/include/lwip/netifapi.h | 108 + .../third_party/include/lwip/opt.h | 2043 +++++ .../third_party/include/lwip/pbuf.h | 160 + .../third_party/include/lwip/puck_def.h | 44 + .../third_party/include/lwip/raw.h | 98 + .../third_party/include/lwip/sio.h | 141 + .../third_party/include/lwip/snmp.h | 367 + .../third_party/include/lwip/snmp_asn1.h | 101 + .../third_party/include/lwip/snmp_msg.h | 315 + .../third_party/include/lwip/snmp_structs.h | 268 + .../third_party/include/lwip/sntp.h | 60 + .../third_party/include/lwip/sockets.h | 376 + .../third_party/include/lwip/stats.h | 292 + .../third_party/include/lwip/sys.h | 337 + .../third_party/include/lwip/tcp.h | 377 + .../third_party/include/lwip/tcp_impl.h | 472 + .../third_party/include/lwip/tcpip.h | 159 + .../third_party/include/lwip/timers.h | 98 + .../third_party/include/lwip/udp.h | 171 + .../third_party/include/lwipopts.h | 2068 +++++ .../third_party/include/mbedtls/aes.h | 297 + .../third_party/include/mbedtls/aesni.h | 111 + .../third_party/include/mbedtls/arc4.h | 113 + .../third_party/include/mbedtls/asn1.h | 342 + .../third_party/include/mbedtls/asn1write.h | 239 + .../third_party/include/mbedtls/base64.h | 88 + .../third_party/include/mbedtls/bignum.h | 717 ++ .../third_party/include/mbedtls/blowfish.h | 203 + .../third_party/include/mbedtls/bn_mul.h | 876 ++ .../third_party/include/mbedtls/camellia.h | 235 + .../third_party/include/mbedtls/ccm.h | 141 + .../third_party/include/mbedtls/certs.h | 103 + .../include/mbedtls/check_config.h | 540 ++ .../third_party/include/mbedtls/cipher.h | 698 ++ .../include/mbedtls/cipher_internal.h | 109 + .../third_party/include/mbedtls/compat-1.3.h | 2634 ++++++ .../third_party/include/mbedtls/config.h | 2511 ++++++ .../third_party/include/mbedtls/config_esp.h | 2524 ++++++ .../third_party/include/mbedtls/ctr_drbg.h | 290 + .../third_party/include/mbedtls/debug.h | 125 + .../third_party/include/mbedtls/des.h | 306 + .../third_party/include/mbedtls/dhm.h | 305 + .../third_party/include/mbedtls/ecdh.h | 214 + .../third_party/include/mbedtls/ecdsa.h | 248 + .../third_party/include/mbedtls/ecjpake.h | 238 + .../third_party/include/mbedtls/ecp.h | 669 ++ .../third_party/include/mbedtls/entropy.h | 252 + .../include/mbedtls/entropy_poll.h | 89 + .../third_party/include/mbedtls/error.h | 107 + .../third_party/include/mbedtls/gcm.h | 220 + .../third_party/include/mbedtls/havege.h | 74 + .../third_party/include/mbedtls/hmac_drbg.h | 299 + .../include/mbedtls/mbedtls_debug.h | 13 + .../third_party/include/mbedtls/md.h | 353 + .../third_party/include/mbedtls/md2.h | 136 + .../third_party/include/mbedtls/md4.h | 136 + .../third_party/include/mbedtls/md5.h | 136 + .../third_party/include/mbedtls/md_internal.h | 114 + .../include/mbedtls/memory_buffer_alloc.h | 146 + .../third_party/include/mbedtls/net.h | 225 + .../third_party/include/mbedtls/oid.h | 570 ++ .../third_party/include/mbedtls/padlock.h | 107 + .../third_party/include/mbedtls/pem.h | 129 + .../third_party/include/mbedtls/pk.h | 615 ++ .../third_party/include/mbedtls/pk_internal.h | 114 + .../third_party/include/mbedtls/pkcs11.h | 173 + .../third_party/include/mbedtls/pkcs12.h | 119 + .../third_party/include/mbedtls/pkcs5.h | 94 + .../third_party/include/mbedtls/platform.h | 217 + .../third_party/include/mbedtls/ripemd160.h | 138 + .../third_party/include/mbedtls/rsa.h | 652 ++ .../third_party/include/mbedtls/sha1.h | 136 + .../third_party/include/mbedtls/sha256.h | 141 + .../third_party/include/mbedtls/sha512.h | 141 + .../third_party/include/mbedtls/ssl.h | 2393 ++++++ .../third_party/include/mbedtls/ssl_cache.h | 143 + .../include/mbedtls/ssl_ciphersuites.h | 321 + .../third_party/include/mbedtls/ssl_cookie.h | 108 + .../include/mbedtls/ssl_internal.h | 495 ++ .../third_party/include/mbedtls/ssl_ticket.h | 135 + .../include/mbedtls/sys/espconn_mbedtls.h | 278 + .../third_party/include/mbedtls/sys/socket.h | 343 + .../third_party/include/mbedtls/threading.h | 104 + .../third_party/include/mbedtls/timing.h | 141 + .../third_party/include/mbedtls/version.h | 111 + .../third_party/include/mbedtls/x509.h | 331 + .../third_party/include/mbedtls/x509_crl.h | 173 + .../third_party/include/mbedtls/x509_crt.h | 645 ++ .../third_party/include/mbedtls/x509_csr.h | 292 + .../third_party/include/mbedtls/xtea.h | 139 + .../third_party/include/netif/etharp.h | 254 + .../third_party/include/netif/if_llc.h | 173 + .../third_party/include/netif/ppp_oe.h | 190 + .../third_party/include/netif/wlan_lwip_if.h | 25 + .../include/ssl/app/espconn_secure.h | 46 + .../third_party/include/ssl/app/espconn_ssl.h | 156 + .../third_party/include/ssl/ssl_bigint.h | 99 + .../third_party/include/ssl/ssl_bigint_impl.h | 131 + .../third_party/include/ssl/ssl_cert.h | 43 + .../third_party/include/ssl/ssl_config.h | 130 + .../third_party/include/ssl/ssl_crypto.h | 266 + .../third_party/include/ssl/ssl_crypto_misc.h | 177 + .../third_party/include/ssl/ssl_os_int.h | 67 + .../third_party/include/ssl/ssl_os_port.h | 106 + .../third_party/include/ssl/ssl_private_key.h | 54 + .../third_party/include/ssl/ssl_ssl.h | 503 ++ .../third_party/include/ssl/ssl_tls1.h | 303 + .../third_party/include/ssl/ssl_version.h | 1 + .../third_party/include/user_config.h | 0 .../third_party/lwip/Makefile | 51 + .../third_party/lwip/api/Makefile | 46 + .../third_party/lwip/api/api_lib.c | 740 ++ .../third_party/lwip/api/api_msg.c | 1540 ++++ .../third_party/lwip/api/err.c | 75 + .../third_party/lwip/api/netbuf.c | 245 + .../third_party/lwip/api/netdb.c | 352 + .../third_party/lwip/api/netifapi.c | 160 + .../third_party/lwip/api/sockets.c | 2343 +++++ .../third_party/lwip/api/tcpip.c | 460 + .../third_party/lwip/app/Makefile | 46 + .../third_party/lwip/app/dhcpserver.c | 1179 +++ .../third_party/lwip/app/espconn.c | 1366 +++ .../third_party/lwip/app/espconn_buf.c | 222 + .../third_party/lwip/app/espconn_mdns.c | 134 + .../third_party/lwip/app/espconn_tcp.c | 1553 ++++ .../third_party/lwip/app/espconn_udp.c | 425 + .../third_party/lwip/app/netio.c | 369 + .../third_party/lwip/app/ping.c | 329 + .../third_party/lwip/core/Makefile | 46 + .../third_party/lwip/core/def.c | 108 + .../third_party/lwip/core/dhcp.c | 1818 ++++ .../third_party/lwip/core/dns.c | 988 +++ .../third_party/lwip/core/init.c | 325 + .../third_party/lwip/core/ipv4/Makefile | 46 + .../third_party/lwip/core/ipv4/autoip.c | 536 ++ .../third_party/lwip/core/ipv4/icmp.c | 354 + .../third_party/lwip/core/ipv4/igmp.c | 845 ++ .../third_party/lwip/core/ipv4/inet.c | 42 + .../third_party/lwip/core/ipv4/inet_chksum.c | 450 + .../third_party/lwip/core/ipv4/ip.c | 920 ++ .../third_party/lwip/core/ipv4/ip_addr.c | 329 + .../third_party/lwip/core/ipv4/ip_frag.c | 863 ++ .../third_party/lwip/core/mdns.c | 1136 +++ .../third_party/lwip/core/mem.c | 644 ++ .../third_party/lwip/core/memp.c | 490 ++ .../third_party/lwip/core/netif.c | 762 ++ .../third_party/lwip/core/pbuf.c | 1257 +++ .../third_party/lwip/core/raw.c | 358 + .../third_party/lwip/core/sntp.c | 1165 +++ .../third_party/lwip/core/stats.c | 176 + .../third_party/lwip/core/sys.c | 66 + .../third_party/lwip/core/sys_arch.c | 13 + .../third_party/lwip/core/tcp.c | 1671 ++++ .../third_party/lwip/core/tcp_in.c | 1637 ++++ .../third_party/lwip/core/tcp_out.c | 1531 ++++ .../third_party/lwip/core/timers.c | 513 ++ .../third_party/lwip/core/udp.c | 977 +++ .../third_party/lwip/netif/Makefile | 46 + .../third_party/lwip/netif/etharp.c | 1413 +++ .../ESP8266_NONOS_SDK/third_party/make_lib.sh | 26 + .../third_party/mbedtls/Makefile | 49 + .../third_party/mbedtls/app/Makefile | 46 + .../third_party/mbedtls/app/espconn_mbedtls.c | 1270 +++ .../third_party/mbedtls/app/espconn_secure.c | 397 + .../third_party/mbedtls/app/lwIPFile.c | 123 + .../third_party/mbedtls/app/lwIPSocket.c | 1011 +++ .../third_party/mbedtls/library/Makefile | 46 + .../third_party/mbedtls/library/aes.c | 1491 ++++ .../third_party/mbedtls/library/aesni.c | 464 + .../third_party/mbedtls/library/arc4.c | 205 + .../third_party/mbedtls/library/asn1parse.c | 392 + .../third_party/mbedtls/library/asn1write.c | 361 + .../third_party/mbedtls/library/base64.c | 289 + .../third_party/mbedtls/library/bignum.c | 2433 ++++++ .../third_party/mbedtls/library/blowfish.c | 656 ++ .../third_party/mbedtls/library/camellia.c | 1072 +++ .../third_party/mbedtls/library/ccm.c | 464 + .../third_party/mbedtls/library/certs.c | 357 + .../third_party/mbedtls/library/cipher.c | 886 ++ .../third_party/mbedtls/library/cipher_wrap.c | 1451 ++++ .../third_party/mbedtls/library/ctr_drbg.c | 593 ++ .../third_party/mbedtls/library/debug.c | 367 + .../third_party/mbedtls/library/des.c | 1061 +++ .../third_party/mbedtls/library/dhm.c | 624 ++ .../third_party/mbedtls/library/ecdh.c | 264 + .../third_party/mbedtls/library/ecdsa.c | 448 + .../third_party/mbedtls/library/ecjpake.c | 1103 +++ .../third_party/mbedtls/library/ecp.c | 2090 +++++ .../third_party/mbedtls/library/ecp_curves.c | 1325 +++ .../third_party/mbedtls/library/entropy.c | 493 ++ .../mbedtls/library/entropy_poll.c | 216 + .../third_party/mbedtls/library/error.c | 700 ++ .../third_party/mbedtls/library/gcm.c | 953 ++ .../third_party/mbedtls/library/havege.c | 243 + .../third_party/mbedtls/library/hmac_drbg.c | 529 ++ .../third_party/mbedtls/library/md.c | 471 + .../third_party/mbedtls/library/md2.c | 288 + .../third_party/mbedtls/library/md4.c | 384 + .../third_party/mbedtls/library/md5.c | 407 + .../third_party/mbedtls/library/md_wrap.c | 575 ++ .../mbedtls/library/memory_buffer_alloc.c | 750 ++ .../third_party/mbedtls/library/net.c | 575 ++ .../third_party/mbedtls/library/oid.c | 650 ++ .../third_party/mbedtls/library/padlock.c | 170 + .../third_party/mbedtls/library/pem.c | 447 + .../third_party/mbedtls/library/pk.c | 374 + .../third_party/mbedtls/library/pk_wrap.c | 495 ++ .../third_party/mbedtls/library/pkcs11.c | 240 + .../third_party/mbedtls/library/pkcs12.c | 365 + .../third_party/mbedtls/library/pkcs5.c | 405 + .../third_party/mbedtls/library/pkparse.c | 1293 +++ .../third_party/mbedtls/library/pkwrite.c | 439 + .../third_party/mbedtls/library/platform.c | 193 + .../third_party/mbedtls/library/ripemd160.c | 464 + .../third_party/mbedtls/library/rsa.c | 1705 ++++ .../third_party/mbedtls/library/sha1.c | 451 + .../third_party/mbedtls/library/sha256.c | 449 + .../third_party/mbedtls/library/sha512.c | 505 ++ .../third_party/mbedtls/library/ssl_cache.c | 326 + .../mbedtls/library/ssl_ciphersuites.c | 1853 ++++ .../third_party/mbedtls/library/ssl_cli.c | 3393 ++++++++ .../third_party/mbedtls/library/ssl_cookie.c | 260 + .../third_party/mbedtls/library/ssl_srv.c | 3884 +++++++++ .../third_party/mbedtls/library/ssl_ticket.c | 489 ++ .../third_party/mbedtls/library/ssl_tls.c | 7625 +++++++++++++++++ .../third_party/mbedtls/library/threading.c | 136 + .../third_party/mbedtls/library/timing.c | 520 ++ .../third_party/mbedtls/library/version.c | 50 + .../mbedtls/library/version_features.c | 635 ++ .../third_party/mbedtls/library/x509.c | 1024 +++ .../third_party/mbedtls/library/x509_create.c | 340 + .../third_party/mbedtls/library/x509_crl.c | 721 ++ .../third_party/mbedtls/library/x509_crt.c | 2412 ++++++ .../third_party/mbedtls/library/x509_csr.c | 417 + .../mbedtls/library/x509write_crt.c | 456 + .../mbedtls/library/x509write_csr.c | 256 + .../third_party/mbedtls/library/xtea.c | 281 + .../third_party/mbedtls/platform/Makefile | 46 + .../mbedtls/platform/esp_hardware.c | 51 + .../third_party/mbedtls/platform/net.c | 440 + .../ESP8266_NONOS_SDK/tools/README.md | 84 + .../ESP8266_NONOS_SDK/tools/gen_appbin.py | 286 + .../ESP8266_NONOS_SDK/tools/make_cacert.py | 64 + .../ESP8266_NONOS_SDK/tools/make_cert.py | 76 + .../ESP8266_NONOS_SDK/tools/makefile.sh | 198 + .../ESP8266_NONOS_SDK/tools/rmfile.sh | 16 + Sming/third-party/esp-gdbstub/gdbstub.c | 2 +- .../esp-open-lwip/include/arch/cc.h | 5 +- .../esp-open-lwip/include/user_config.h | 3 +- Sming/third-party/lwip2 | 1 - Sming/third-party/lwip2/Makefile.arduino | 8 + Sming/third-party/lwip2/Makefile.open | 18 + Sming/third-party/lwip2/Makefile.sming | 19 + Sming/third-party/lwip2/README.md | 87 + Sming/third-party/lwip2/build/api/api_lib.d | 12 + Sming/third-party/lwip2/build/api/api_lib.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/api/api_msg.d | 12 + Sming/third-party/lwip2/build/api/api_msg.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/api/err.d | 13 + Sming/third-party/lwip2/build/api/err.o | Bin 0 -> 2044 bytes Sming/third-party/lwip2/build/api/netbuf.d | 12 + Sming/third-party/lwip2/build/api/netbuf.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/api/netdb.d | 12 + Sming/third-party/lwip2/build/api/netdb.o | Bin 0 -> 2048 bytes Sming/third-party/lwip2/build/api/netifapi.d | 12 + Sming/third-party/lwip2/build/api/netifapi.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/api/sockets.d | 12 + Sming/third-party/lwip2/build/api/sockets.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/api/tcpip.d | 12 + Sming/third-party/lwip2/build/api/tcpip.o | Bin 0 -> 2048 bytes .../third-party/lwip2/build/apps/sntp/sntp.d | 21 + .../third-party/lwip2/build/apps/sntp/sntp.o | Bin 0 -> 32304 bytes Sming/third-party/lwip2/build/core/def.d | 13 + Sming/third-party/lwip2/build/core/def.o | Bin 0 -> 14992 bytes Sming/third-party/lwip2/build/core/dns.d | 20 + Sming/third-party/lwip2/build/core/dns.o | Bin 0 -> 47676 bytes .../lwip2/build/core/inet_chksum.d | 15 + .../lwip2/build/core/inet_chksum.o | Bin 0 -> 21132 bytes Sming/third-party/lwip2/build/core/init.d | 27 + Sming/third-party/lwip2/build/core/init.o | Bin 0 -> 4628 bytes Sming/third-party/lwip2/build/core/ip.d | 19 + Sming/third-party/lwip2/build/core/ip.o | Bin 0 -> 5344 bytes .../lwip2/build/core/ipv4/autoip.d | 12 + .../lwip2/build/core/ipv4/autoip.o | Bin 0 -> 2056 bytes .../third-party/lwip2/build/core/ipv4/dhcp.d | 22 + .../third-party/lwip2/build/core/ipv4/dhcp.o | Bin 0 -> 86196 bytes .../lwip2/build/core/ipv4/etharp.d | 22 + .../lwip2/build/core/ipv4/etharp.o | Bin 0 -> 46748 bytes .../third-party/lwip2/build/core/ipv4/icmp.d | 20 + .../third-party/lwip2/build/core/ipv4/icmp.o | Bin 0 -> 16476 bytes .../third-party/lwip2/build/core/ipv4/igmp.d | 20 + .../third-party/lwip2/build/core/ipv4/igmp.o | Bin 0 -> 36996 bytes Sming/third-party/lwip2/build/core/ipv4/ip4.d | 23 + Sming/third-party/lwip2/build/core/ipv4/ip4.o | Bin 0 -> 33820 bytes .../lwip2/build/core/ipv4/ip4_addr.d | 17 + .../lwip2/build/core/ipv4/ip4_addr.o | Bin 0 -> 19832 bytes .../lwip2/build/core/ipv4/ip4_frag.d | 20 + .../lwip2/build/core/ipv4/ip4_frag.o | Bin 0 -> 2060 bytes .../third-party/lwip2/build/core/ipv6/dhcp6.d | 12 + .../third-party/lwip2/build/core/ipv6/dhcp6.o | Bin 0 -> 2056 bytes .../lwip2/build/core/ipv6/ethip6.d | 12 + .../lwip2/build/core/ipv6/ethip6.o | Bin 0 -> 2056 bytes .../third-party/lwip2/build/core/ipv6/icmp6.d | 12 + .../third-party/lwip2/build/core/ipv6/icmp6.o | Bin 0 -> 2056 bytes .../third-party/lwip2/build/core/ipv6/inet6.d | 12 + .../third-party/lwip2/build/core/ipv6/inet6.o | Bin 0 -> 2056 bytes Sming/third-party/lwip2/build/core/ipv6/ip6.d | 12 + Sming/third-party/lwip2/build/core/ipv6/ip6.o | Bin 0 -> 2048 bytes .../lwip2/build/core/ipv6/ip6_addr.d | 12 + .../lwip2/build/core/ipv6/ip6_addr.o | Bin 0 -> 2060 bytes .../lwip2/build/core/ipv6/ip6_frag.d | 20 + .../lwip2/build/core/ipv6/ip6_frag.o | Bin 0 -> 2060 bytes .../third-party/lwip2/build/core/ipv6/mld6.d | 12 + .../third-party/lwip2/build/core/ipv6/mld6.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/core/ipv6/nd6.d | 12 + Sming/third-party/lwip2/build/core/ipv6/nd6.o | Bin 0 -> 2048 bytes Sming/third-party/lwip2/build/core/mem.d | 15 + Sming/third-party/lwip2/build/core/mem.o | Bin 0 -> 7152 bytes Sming/third-party/lwip2/build/core/memp.d | 29 + Sming/third-party/lwip2/build/core/memp.o | Bin 0 -> 14452 bytes Sming/third-party/lwip2/build/core/netif.d | 24 + Sming/third-party/lwip2/build/core/netif.o | Bin 0 -> 30220 bytes Sming/third-party/lwip2/build/core/pbuf.d | 16 + Sming/third-party/lwip2/build/core/pbuf.o | Bin 0 -> 55172 bytes Sming/third-party/lwip2/build/core/raw.d | 19 + Sming/third-party/lwip2/build/core/raw.o | Bin 0 -> 24776 bytes Sming/third-party/lwip2/build/core/stats.d | 12 + Sming/third-party/lwip2/build/core/stats.o | Bin 0 -> 2052 bytes Sming/third-party/lwip2/build/core/sys.d | 13 + Sming/third-party/lwip2/build/core/sys.o | Bin 0 -> 2044 bytes Sming/third-party/lwip2/build/core/tcp.d | 21 + Sming/third-party/lwip2/build/core/tcp.o | Bin 0 -> 98600 bytes Sming/third-party/lwip2/build/core/tcp_in.d | 21 + Sming/third-party/lwip2/build/core/tcp_in.o | Bin 0 -> 57356 bytes Sming/third-party/lwip2/build/core/tcp_out.d | 21 + Sming/third-party/lwip2/build/core/tcp_out.o | Bin 0 -> 62700 bytes Sming/third-party/lwip2/build/core/timeouts.d | 27 + Sming/third-party/lwip2/build/core/timeouts.o | Bin 0 -> 24108 bytes Sming/third-party/lwip2/build/core/udp.d | 22 + Sming/third-party/lwip2/build/core/udp.o | Bin 0 -> 42672 bytes .../lwip2/build/glue-esp/lwip-esp.d | 23 + .../lwip2/build/glue-esp/lwip-esp.o | Bin 0 -> 54820 bytes .../lwip2/build/glue-lwip/esp-dhcpserver.d | 33 + .../lwip2/build/glue-lwip/esp-dhcpserver.o | Bin 0 -> 66792 bytes .../lwip2/build/glue-lwip/esp-sntp.d | 19 + .../lwip2/build/glue-lwip/esp-sntp.o | Bin 0 -> 33548 bytes .../lwip2/build/glue-lwip/esp-time.d | 16 + .../lwip2/build/glue-lwip/esp-time.o | Bin 0 -> 5916 bytes .../lwip2/build/glue-lwip/lwip-git.d | 39 + .../lwip2/build/glue-lwip/lwip-git.o | Bin 0 -> 39592 bytes Sming/third-party/lwip2/build/glue/doprint.d | 10 + Sming/third-party/lwip2/build/glue/doprint.o | Bin 0 -> 14632 bytes Sming/third-party/lwip2/build/glue/uprint.d | 20 + Sming/third-party/lwip2/build/glue/uprint.o | Bin 0 -> 2036 bytes .../third-party/lwip2/build/netif/ethernet.d | 21 + .../third-party/lwip2/build/netif/ethernet.o | Bin 0 -> 13104 bytes Sming/third-party/lwip2/build/user_config.h | 0 .../lwip2/glue-esp/include-esp/README.md | 1 + .../lwip2/glue-esp/include-esp/arch/cc.h | 121 + .../lwip2/glue-esp/include-esp/arch/perf.h | 40 + .../glue-esp/include-esp/arch/sys_arch.h | 0 .../lwip2/glue-esp/include-esp/lwip/api.h | 284 + .../lwip2/glue-esp/include-esp/lwip/api_msg.h | 174 + .../include-esp/lwip/app/dhcpserver.h | 114 + .../glue-esp/include-esp/lwip/app/espconn.h | 678 ++ .../include-esp/lwip/app/espconn_buf.h | 60 + .../include-esp/lwip/app/espconn_tcp.h | 55 + .../include-esp/lwip/app/espconn_udp.h | 64 + .../glue-esp/include-esp/lwip/app/ping.h | 85 + .../glue-esp/include-esp/lwip/app/time.h | 53 + .../lwip2/glue-esp/include-esp/lwip/arch.h | 238 + .../lwip2/glue-esp/include-esp/lwip/autoip.h | 119 + .../lwip2/glue-esp/include-esp/lwip/debug.h | 98 + .../lwip2/glue-esp/include-esp/lwip/def.h | 127 + .../lwip2/glue-esp/include-esp/lwip/dhcp.h | 252 + .../lwip2/glue-esp/include-esp/lwip/dns.h | 124 + .../lwip2/glue-esp/include-esp/lwip/err.h | 86 + .../lwip2/glue-esp/include-esp/lwip/icmp.h | 115 + .../lwip2/glue-esp/include-esp/lwip/igmp.h | 106 + .../lwip2/glue-esp/include-esp/lwip/inet.h | 107 + .../glue-esp/include-esp/lwip/inet_chksum.h | 90 + .../lwip2/glue-esp/include-esp/lwip/init.h | 73 + .../lwip2/glue-esp/include-esp/lwip/ip.h | 215 + .../lwip2/glue-esp/include-esp/lwip/ip_addr.h | 256 + .../lwip2/glue-esp/include-esp/lwip/ip_frag.h | 88 + .../lwip2/glue-esp/include-esp/lwip/mdns.h | 114 + .../lwip2/glue-esp/include-esp/lwip/mem.h | 143 + .../lwip2/glue-esp/include-esp/lwip/memp.h | 116 + .../glue-esp/include-esp/lwip/memp_std.h | 126 + .../lwip2/glue-esp/include-esp/lwip/netbuf.h | 101 + .../lwip2/glue-esp/include-esp/lwip/netdb.h | 124 + .../lwip2/glue-esp/include-esp/lwip/netif.h | 320 + .../glue-esp/include-esp/lwip/netifapi.h | 108 + .../lwip2/glue-esp/include-esp/lwip/opt.h | 2043 +++++ .../lwip2/glue-esp/include-esp/lwip/pbuf.h | 160 + .../glue-esp/include-esp/lwip/puck_def.h | 44 + .../lwip2/glue-esp/include-esp/lwip/raw.h | 98 + .../lwip2/glue-esp/include-esp/lwip/sio.h | 141 + .../lwip2/glue-esp/include-esp/lwip/snmp.h | 367 + .../glue-esp/include-esp/lwip/snmp_asn1.h | 101 + .../glue-esp/include-esp/lwip/snmp_msg.h | 315 + .../glue-esp/include-esp/lwip/snmp_structs.h | 268 + .../lwip2/glue-esp/include-esp/lwip/sntp.h | 60 + .../lwip2/glue-esp/include-esp/lwip/sockets.h | 376 + .../lwip2/glue-esp/include-esp/lwip/stats.h | 292 + .../lwip2/glue-esp/include-esp/lwip/sys.h | 337 + .../lwip2/glue-esp/include-esp/lwip/tcp.h | 377 + .../glue-esp/include-esp/lwip/tcp_impl.h | 492 ++ .../lwip2/glue-esp/include-esp/lwip/tcpip.h | 159 + .../lwip2/glue-esp/include-esp/lwip/timers.h | 98 + .../lwip2/glue-esp/include-esp/lwip/udp.h | 184 + .../lwip2/glue-esp/include-esp/lwipopts.h | 2083 +++++ .../lwip2/glue-esp/include-esp/netif/etharp.h | 254 + .../lwip2/glue-esp/include-esp/netif/if_llc.h | 173 + .../lwip2/glue-esp/include-esp/netif/ppp_oe.h | 190 + .../glue-esp/include-esp/netif/wlan_lwip_if.h | 25 + Sming/third-party/lwip2/glue-esp/lwip-esp.c | 956 +++ Sming/third-party/lwip2/glue-lwip/arch/cc.h | 141 + .../lwip2/glue-lwip/arch/sys_arch.h | 5 + .../lwip2/glue-lwip/esp-dhcpserver.c | 1204 +++ Sming/third-party/lwip2/glue-lwip/esp-sntp.c | 411 + Sming/third-party/lwip2/glue-lwip/esp-time.c | 109 + .../lwip2/glue-lwip/lwip-git-hash.h | 6 + Sming/third-party/lwip2/glue-lwip/lwip-git.c | 398 + .../third-party/lwip2/glue-lwip/lwip-helper.h | 17 + .../glue-lwip/lwip/apps-esp/dhcpserver.h | 120 + Sming/third-party/lwip2/glue-lwip/lwipopts.h | 2991 +++++++ Sming/third-party/lwip2/glue/doprint.c | 179 + Sming/third-party/lwip2/glue/doprint.h | 27 + Sming/third-party/lwip2/glue/esp-missing.h | 45 + Sming/third-party/lwip2/glue/glue.h | 115 + Sming/third-party/lwip2/glue/uprint.c | 76 + Sming/third-party/lwip2/glue/uprint.h | 26 + Sming/third-party/lwip2/include/README.md | 1 + Sming/third-party/lwip2/include/arch/cc.h | 141 + .../third-party/lwip2/include/arch/sys_arch.h | 5 + Sming/third-party/lwip2/include/espconn.h | 0 .../third-party/lwip2/include/lwip-git-hash.h | 6 + Sming/third-party/lwip2/include/lwip/api.h | 400 + .../third-party/lwip2/include/lwip/apps/FILES | 2 + .../third-party/lwip2/include/lwip/apps/fs.h | 103 + .../lwip2/include/lwip/apps/httpd.h | 236 + .../lwip2/include/lwip/apps/httpd_opts.h | 323 + .../lwip2/include/lwip/apps/lwiperf.h | 84 + .../lwip2/include/lwip/apps/mdns.h | 69 + .../lwip2/include/lwip/apps/mdns_opts.h | 74 + .../lwip2/include/lwip/apps/mdns_priv.h | 66 + .../lwip2/include/lwip/apps/mqtt.h | 244 + .../lwip2/include/lwip/apps/mqtt_opts.h | 103 + .../lwip2/include/lwip/apps/netbiosns.h | 43 + .../lwip2/include/lwip/apps/netbiosns_opts.h | 59 + .../lwip2/include/lwip/apps/snmp.h | 128 + .../lwip2/include/lwip/apps/snmp_core.h | 364 + .../lwip2/include/lwip/apps/snmp_mib2.h | 78 + .../lwip2/include/lwip/apps/snmp_opts.h | 293 + .../lwip2/include/lwip/apps/snmp_scalar.h | 113 + .../lwip2/include/lwip/apps/snmp_table.h | 134 + .../lwip2/include/lwip/apps/snmp_threadsync.h | 114 + .../lwip2/include/lwip/apps/snmpv3.h | 90 + .../lwip2/include/lwip/apps/sntp.h | 76 + .../lwip2/include/lwip/apps/sntp_opts.h | 173 + .../lwip2/include/lwip/apps/tftp_opts.h | 105 + .../lwip2/include/lwip/apps/tftp_server.h | 94 + Sming/third-party/lwip2/include/lwip/arch.h | 319 + Sming/third-party/lwip2/include/lwip/autoip.h | 99 + Sming/third-party/lwip2/include/lwip/debug.h | 167 + Sming/third-party/lwip2/include/lwip/def.h | 142 + Sming/third-party/lwip2/include/lwip/dhcp.h | 143 + Sming/third-party/lwip2/include/lwip/dhcp6.h | 58 + Sming/third-party/lwip2/include/lwip/dns.h | 130 + Sming/third-party/lwip2/include/lwip/err.h | 119 + Sming/third-party/lwip2/include/lwip/errno.h | 193 + Sming/third-party/lwip2/include/lwip/etharp.h | 106 + Sming/third-party/lwip2/include/lwip/ethip6.h | 68 + Sming/third-party/lwip2/include/lwip/icmp.h | 110 + Sming/third-party/lwip2/include/lwip/icmp6.h | 70 + Sming/third-party/lwip2/include/lwip/igmp.h | 115 + Sming/third-party/lwip2/include/lwip/inet.h | 172 + .../lwip2/include/lwip/inet_chksum.h | 105 + Sming/third-party/lwip2/include/lwip/init.h | 100 + Sming/third-party/lwip2/include/lwip/ip.h | 319 + Sming/third-party/lwip2/include/lwip/ip4.h | 111 + .../third-party/lwip2/include/lwip/ip4_addr.h | 227 + .../third-party/lwip2/include/lwip/ip4_frag.h | 100 + Sming/third-party/lwip2/include/lwip/ip6.h | 93 + .../third-party/lwip2/include/lwip/ip6_addr.h | 285 + .../third-party/lwip2/include/lwip/ip6_frag.h | 120 + .../third-party/lwip2/include/lwip/ip_addr.h | 407 + Sming/third-party/lwip2/include/lwip/mem.h | 82 + Sming/third-party/lwip2/include/lwip/memp.h | 153 + Sming/third-party/lwip2/include/lwip/mld6.h | 99 + Sming/third-party/lwip2/include/lwip/nd6.h | 84 + Sming/third-party/lwip2/include/lwip/netbuf.h | 118 + Sming/third-party/lwip2/include/lwip/netdb.h | 150 + Sming/third-party/lwip2/include/lwip/netif.h | 474 + .../third-party/lwip2/include/lwip/netifapi.h | 140 + Sming/third-party/lwip2/include/lwip/opt.h | 2876 +++++++ Sming/third-party/lwip2/include/lwip/pbuf.h | 263 + .../lwip2/include/lwip/priv/api_msg.h | 216 + .../lwip2/include/lwip/priv/memp_priv.h | 183 + .../lwip2/include/lwip/priv/memp_std.h | 146 + .../lwip2/include/lwip/priv/nd6_priv.h | 144 + .../lwip2/include/lwip/priv/tcp_priv.h | 507 ++ .../lwip2/include/lwip/priv/tcpip_priv.h | 160 + .../lwip2/include/lwip/prot/autoip.h | 78 + .../lwip2/include/lwip/prot/dhcp.h | 183 + .../third-party/lwip2/include/lwip/prot/dns.h | 140 + .../lwip2/include/lwip/prot/etharp.h | 91 + .../lwip2/include/lwip/prot/ethernet.h | 170 + .../lwip2/include/lwip/prot/icmp.h | 91 + .../lwip2/include/lwip/prot/icmp6.h | 170 + .../lwip2/include/lwip/prot/igmp.h | 90 + .../third-party/lwip2/include/lwip/prot/ip.h | 51 + .../third-party/lwip2/include/lwip/prot/ip4.h | 127 + .../third-party/lwip2/include/lwip/prot/ip6.h | 169 + .../lwip2/include/lwip/prot/mld6.h | 70 + .../third-party/lwip2/include/lwip/prot/nd6.h | 277 + .../third-party/lwip2/include/lwip/prot/tcp.h | 97 + .../third-party/lwip2/include/lwip/prot/udp.h | 68 + Sming/third-party/lwip2/include/lwip/raw.h | 118 + Sming/third-party/lwip2/include/lwip/sio.h | 142 + Sming/third-party/lwip2/include/lwip/snmp.h | 213 + .../third-party/lwip2/include/lwip/sockets.h | 593 ++ Sming/third-party/lwip2/include/lwip/stats.h | 491 ++ Sming/third-party/lwip2/include/lwip/sys.h | 455 + Sming/third-party/lwip2/include/lwip/tcp.h | 433 + Sming/third-party/lwip2/include/lwip/tcpip.h | 106 + .../third-party/lwip2/include/lwip/timeouts.h | 121 + Sming/third-party/lwip2/include/lwip/udp.h | 182 + Sming/third-party/lwip2/include/lwipopts.h | 2996 +++++++ .../third-party/lwip2/include/netif/etharp.h | 3 + .../lwip2/include/netif/ethernet.h | 77 + .../third-party/lwip2/include/netif/lowpan6.h | 86 + .../lwip2/include/netif/lowpan6_opts.h | 70 + .../third-party/lwip2/include/netif/ppp/ccp.h | 156 + .../lwip2/include/netif/ppp/chap-md5.h | 36 + .../lwip2/include/netif/ppp/chap-new.h | 192 + .../lwip2/include/netif/ppp/chap_ms.h | 44 + .../third-party/lwip2/include/netif/ppp/eap.h | 169 + .../third-party/lwip2/include/netif/ppp/ecp.h | 50 + .../lwip2/include/netif/ppp/eui64.h | 94 + .../third-party/lwip2/include/netif/ppp/fsm.h | 175 + .../lwip2/include/netif/ppp/ipcp.h | 126 + .../lwip2/include/netif/ppp/ipv6cp.h | 183 + .../third-party/lwip2/include/netif/ppp/lcp.h | 171 + .../lwip2/include/netif/ppp/magic.h | 122 + .../lwip2/include/netif/ppp/mppe.h | 173 + .../lwip2/include/netif/ppp/polarssl/arc4.h | 81 + .../lwip2/include/netif/ppp/polarssl/des.h | 92 + .../lwip2/include/netif/ppp/polarssl/md4.h | 97 + .../lwip2/include/netif/ppp/polarssl/md5.h | 96 + .../lwip2/include/netif/ppp/polarssl/sha1.h | 96 + .../third-party/lwip2/include/netif/ppp/ppp.h | 690 ++ .../lwip2/include/netif/ppp/ppp_impl.h | 629 ++ .../lwip2/include/netif/ppp/ppp_opts.h | 593 ++ .../lwip2/include/netif/ppp/pppapi.h | 137 + .../lwip2/include/netif/ppp/pppcrypt.h | 136 + .../lwip2/include/netif/ppp/pppdebug.h | 80 + .../lwip2/include/netif/ppp/pppoe.h | 179 + .../lwip2/include/netif/ppp/pppol2tp.h | 201 + .../lwip2/include/netif/ppp/pppos.h | 118 + .../lwip2/include/netif/ppp/upap.h | 123 + .../third-party/lwip2/include/netif/ppp/vj.h | 161 + .../third-party/lwip2/include/netif/slipif.h | 87 + Sming/third-party/lwip2/include/posix/errno.h | 33 + Sming/third-party/lwip2/include/posix/netdb.h | 33 + .../lwip2/include/posix/sys/socket.h | 33 + Sming/third-party/lwip2/liblwip2.a | Bin 0 -> 1066588 bytes .../lwip2/lwip2-src/.gitattributes | 4 + Sming/third-party/lwip2/lwip2-src/.gitignore | 18 + Sming/third-party/lwip2/lwip2-src/CHANGELOG | 4276 +++++++++ Sming/third-party/lwip2/lwip2-src/COPYING | 33 + Sming/third-party/lwip2/lwip2-src/FILES | 5 + Sming/third-party/lwip2/lwip2-src/README | 100 + Sming/third-party/lwip2/lwip2-src/UPGRADING | 235 + Sming/third-party/lwip2/lwip2-src/doc/FILES | 9 + .../lwip2/lwip2-src/doc/NO_SYS_SampleCode.c | 117 + .../lwip2/lwip2-src/doc/contrib.txt | 58 + .../lwip2/lwip2-src/doc/doxygen/generate.bat | 1 + .../lwip2/lwip2-src/doc/doxygen/generate.sh | 3 + .../lwip2/lwip2-src/doc/doxygen/lwip.Doxyfile | 2505 ++++++ .../lwip2/lwip2-src/doc/doxygen/main_page.h | 132 + .../lwip2-src/doc/doxygen/output/index.html | 10 + .../third-party/lwip2/lwip2-src/doc/mdns.txt | 113 + .../lwip2/lwip2-src/doc/mqtt_client.txt | 162 + Sming/third-party/lwip2/lwip2-src/doc/ppp.txt | 529 ++ .../lwip2/lwip2-src/doc/rawapi.txt | 499 ++ .../lwip2/lwip2-src/doc/savannah.txt | 120 + .../lwip2/lwip2-src/doc/sys_arch.txt | 303 + Sming/third-party/lwip2/lwip2-src/src/FILES | 15 + .../lwip2/lwip2-src/src/Filelists.mk | 181 + .../lwip2/lwip2-src/src/api/api_lib.c | 1010 +++ .../lwip2/lwip2-src/src/api/api_msg.c | 1947 +++++ .../third-party/lwip2/lwip2-src/src/api/err.c | 115 + .../lwip2/lwip2-src/src/api/netbuf.c | 246 + .../lwip2/lwip2-src/src/api/netdb.c | 413 + .../lwip2/lwip2-src/src/api/netifapi.c | 221 + .../lwip2/lwip2-src/src/api/sockets.c | 2827 ++++++ .../lwip2/lwip2-src/src/api/tcpip.c | 518 ++ .../lwip2/lwip2-src/src/apps/httpd/fs.c | 179 + .../lwip2-src/src/apps/httpd/fs/404.html | 21 + .../lwip2-src/src/apps/httpd/fs/img/sics.gif | Bin 0 -> 724 bytes .../lwip2-src/src/apps/httpd/fs/index.html | 47 + .../lwip2/lwip2-src/src/apps/httpd/fsdata.c | 298 + .../lwip2/lwip2-src/src/apps/httpd/fsdata.h | 50 + .../lwip2/lwip2-src/src/apps/httpd/httpd.c | 2629 ++++++ .../lwip2-src/src/apps/httpd/httpd_structs.h | 114 + .../src/apps/httpd/makefsdata/makefsdata | 97 + .../src/apps/httpd/makefsdata/makefsdata.c | 1033 +++ .../src/apps/httpd/makefsdata/readme.txt | 13 + .../lwip2-src/src/apps/lwiperf/lwiperf.c | 661 ++ .../lwip2/lwip2-src/src/apps/mdns/mdns.c | 2028 +++++ .../lwip2/lwip2-src/src/apps/mqtt/mqtt.c | 1341 +++ .../lwip2-src/src/apps/netbiosns/netbiosns.c | 367 + .../lwip2/lwip2-src/src/apps/snmp/snmp_asn1.c | 749 ++ .../lwip2/lwip2-src/src/apps/snmp/snmp_asn1.h | 108 + .../lwip2/lwip2-src/src/apps/snmp/snmp_core.c | 1349 +++ .../lwip2-src/src/apps/snmp/snmp_core_priv.h | 76 + .../lwip2/lwip2-src/src/apps/snmp/snmp_mib2.c | 116 + .../lwip2-src/src/apps/snmp/snmp_mib2_icmp.c | 182 + .../src/apps/snmp/snmp_mib2_interfaces.c | 375 + .../lwip2-src/src/apps/snmp/snmp_mib2_ip.c | 743 ++ .../lwip2-src/src/apps/snmp/snmp_mib2_snmp.c | 227 + .../src/apps/snmp/snmp_mib2_system.c | 377 + .../lwip2-src/src/apps/snmp/snmp_mib2_tcp.c | 594 ++ .../lwip2-src/src/apps/snmp/snmp_mib2_udp.c | 357 + .../lwip2/lwip2-src/src/apps/snmp/snmp_msg.c | 1668 ++++ .../lwip2/lwip2-src/src/apps/snmp/snmp_msg.h | 194 + .../lwip2-src/src/apps/snmp/snmp_netconn.c | 121 + .../src/apps/snmp/snmp_pbuf_stream.c | 156 + .../src/apps/snmp/snmp_pbuf_stream.h | 73 + .../lwip2/lwip2-src/src/apps/snmp/snmp_raw.c | 100 + .../lwip2-src/src/apps/snmp/snmp_scalar.c | 220 + .../lwip2-src/src/apps/snmp/snmp_table.c | 343 + .../lwip2-src/src/apps/snmp/snmp_threadsync.c | 219 + .../lwip2-src/src/apps/snmp/snmp_traps.c | 445 + .../lwip2/lwip2-src/src/apps/snmp/snmpv3.c | 136 + .../lwip2-src/src/apps/snmp/snmpv3_dummy.c | 145 + .../lwip2-src/src/apps/snmp/snmpv3_mbedtls.c | 331 + .../lwip2-src/src/apps/snmp/snmpv3_priv.h | 66 + .../lwip2/lwip2-src/src/apps/sntp/sntp.c | 727 ++ .../lwip2-src/src/apps/tftp/tftp_server.c | 417 + .../lwip2/lwip2-src/src/core/def.c | 222 + .../lwip2/lwip2-src/src/core/dns.c | 1573 ++++ .../lwip2/lwip2-src/src/core/inet_chksum.c | 609 ++ .../lwip2/lwip2-src/src/core/init.c | 385 + .../third-party/lwip2/lwip2-src/src/core/ip.c | 124 + .../lwip2/lwip2-src/src/core/ipv4/autoip.c | 527 ++ .../lwip2/lwip2-src/src/core/ipv4/dhcp.c | 1950 +++++ .../lwip2/lwip2-src/src/core/ipv4/etharp.c | 1206 +++ .../lwip2/lwip2-src/src/core/ipv4/icmp.c | 397 + .../lwip2/lwip2-src/src/core/ipv4/igmp.c | 800 ++ .../lwip2/lwip2-src/src/core/ipv4/ip4.c | 1086 +++ .../lwip2/lwip2-src/src/core/ipv4/ip4_addr.c | 331 + .../lwip2/lwip2-src/src/core/ipv4/ip4_frag.c | 831 ++ .../lwip2/lwip2-src/src/core/ipv6/dhcp6.c | 50 + .../lwip2/lwip2-src/src/core/ipv6/ethip6.c | 118 + .../lwip2/lwip2-src/src/core/ipv6/icmp6.c | 350 + .../lwip2/lwip2-src/src/core/ipv6/inet6.c | 53 + .../lwip2/lwip2-src/src/core/ipv6/ip6.c | 1122 +++ .../lwip2/lwip2-src/src/core/ipv6/ip6_addr.c | 292 + .../lwip2/lwip2-src/src/core/ipv6/ip6_frag.c | 805 ++ .../lwip2/lwip2-src/src/core/ipv6/mld6.c | 588 ++ .../lwip2/lwip2-src/src/core/ipv6/nd6.c | 2102 +++++ .../lwip2/lwip2-src/src/core/mem.c | 777 ++ .../lwip2/lwip2-src/src/core/memp.c | 496 ++ .../lwip2/lwip2-src/src/core/netif.c | 1265 +++ .../lwip2/lwip2-src/src/core/pbuf.c | 1442 ++++ .../lwip2/lwip2-src/src/core/raw.c | 521 ++ .../lwip2/lwip2-src/src/core/stats.c | 169 + .../lwip2/lwip2-src/src/core/sys.c | 106 + .../lwip2/lwip2-src/src/core/tcp.c | 2164 +++++ .../lwip2/lwip2-src/src/core/tcp_in.c | 1818 ++++ .../lwip2/lwip2-src/src/core/tcp_out.c | 1671 ++++ .../lwip2/lwip2-src/src/core/timeouts.c | 433 + .../lwip2/lwip2-src/src/core/udp.c | 1191 +++ .../lwip2/lwip2-src/src/include/lwip/api.h | 400 + .../lwip2-src/src/include/lwip/apps/FILES | 2 + .../lwip2-src/src/include/lwip/apps/fs.h | 103 + .../lwip2-src/src/include/lwip/apps/httpd.h | 236 + .../src/include/lwip/apps/httpd_opts.h | 323 + .../lwip2-src/src/include/lwip/apps/lwiperf.h | 84 + .../lwip2-src/src/include/lwip/apps/mdns.h | 69 + .../src/include/lwip/apps/mdns_opts.h | 74 + .../src/include/lwip/apps/mdns_priv.h | 66 + .../lwip2-src/src/include/lwip/apps/mqtt.h | 244 + .../src/include/lwip/apps/mqtt_opts.h | 103 + .../src/include/lwip/apps/netbiosns.h | 43 + .../src/include/lwip/apps/netbiosns_opts.h | 59 + .../lwip2-src/src/include/lwip/apps/snmp.h | 128 + .../src/include/lwip/apps/snmp_core.h | 364 + .../src/include/lwip/apps/snmp_mib2.h | 78 + .../src/include/lwip/apps/snmp_opts.h | 293 + .../src/include/lwip/apps/snmp_scalar.h | 113 + .../src/include/lwip/apps/snmp_table.h | 134 + .../src/include/lwip/apps/snmp_threadsync.h | 114 + .../lwip2-src/src/include/lwip/apps/snmpv3.h | 90 + .../lwip2-src/src/include/lwip/apps/sntp.h | 76 + .../src/include/lwip/apps/sntp_opts.h | 173 + .../src/include/lwip/apps/tftp_opts.h | 105 + .../src/include/lwip/apps/tftp_server.h | 94 + .../lwip2/lwip2-src/src/include/lwip/arch.h | 319 + .../lwip2/lwip2-src/src/include/lwip/autoip.h | 99 + .../lwip2/lwip2-src/src/include/lwip/debug.h | 167 + .../lwip2/lwip2-src/src/include/lwip/def.h | 142 + .../lwip2/lwip2-src/src/include/lwip/dhcp.h | 143 + .../lwip2/lwip2-src/src/include/lwip/dhcp6.h | 58 + .../lwip2/lwip2-src/src/include/lwip/dns.h | 130 + .../lwip2/lwip2-src/src/include/lwip/err.h | 119 + .../lwip2/lwip2-src/src/include/lwip/errno.h | 193 + .../lwip2/lwip2-src/src/include/lwip/etharp.h | 106 + .../lwip2/lwip2-src/src/include/lwip/ethip6.h | 68 + .../lwip2/lwip2-src/src/include/lwip/icmp.h | 110 + .../lwip2/lwip2-src/src/include/lwip/icmp6.h | 70 + .../lwip2/lwip2-src/src/include/lwip/igmp.h | 115 + .../lwip2/lwip2-src/src/include/lwip/inet.h | 172 + .../lwip2-src/src/include/lwip/inet_chksum.h | 105 + .../lwip2/lwip2-src/src/include/lwip/init.h | 100 + .../lwip2/lwip2-src/src/include/lwip/ip.h | 319 + .../lwip2/lwip2-src/src/include/lwip/ip4.h | 111 + .../lwip2-src/src/include/lwip/ip4_addr.h | 227 + .../lwip2-src/src/include/lwip/ip4_frag.h | 100 + .../lwip2/lwip2-src/src/include/lwip/ip6.h | 93 + .../lwip2-src/src/include/lwip/ip6_addr.h | 285 + .../lwip2-src/src/include/lwip/ip6_frag.h | 120 + .../lwip2-src/src/include/lwip/ip_addr.h | 407 + .../lwip2/lwip2-src/src/include/lwip/mem.h | 82 + .../lwip2/lwip2-src/src/include/lwip/memp.h | 153 + .../lwip2/lwip2-src/src/include/lwip/mld6.h | 99 + .../lwip2/lwip2-src/src/include/lwip/nd6.h | 84 + .../lwip2/lwip2-src/src/include/lwip/netbuf.h | 118 + .../lwip2/lwip2-src/src/include/lwip/netdb.h | 150 + .../lwip2/lwip2-src/src/include/lwip/netif.h | 474 + .../lwip2-src/src/include/lwip/netifapi.h | 140 + .../lwip2/lwip2-src/src/include/lwip/opt.h | 2876 +++++++ .../lwip2/lwip2-src/src/include/lwip/pbuf.h | 263 + .../lwip2-src/src/include/lwip/priv/api_msg.h | 216 + .../src/include/lwip/priv/memp_priv.h | 183 + .../src/include/lwip/priv/memp_std.h | 146 + .../src/include/lwip/priv/nd6_priv.h | 144 + .../src/include/lwip/priv/tcp_priv.h | 507 ++ .../src/include/lwip/priv/tcpip_priv.h | 160 + .../lwip2-src/src/include/lwip/prot/autoip.h | 78 + .../lwip2-src/src/include/lwip/prot/dhcp.h | 183 + .../lwip2-src/src/include/lwip/prot/dns.h | 140 + .../lwip2-src/src/include/lwip/prot/etharp.h | 91 + .../src/include/lwip/prot/ethernet.h | 170 + .../lwip2-src/src/include/lwip/prot/icmp.h | 91 + .../lwip2-src/src/include/lwip/prot/icmp6.h | 170 + .../lwip2-src/src/include/lwip/prot/igmp.h | 90 + .../lwip2-src/src/include/lwip/prot/ip.h | 51 + .../lwip2-src/src/include/lwip/prot/ip4.h | 127 + .../lwip2-src/src/include/lwip/prot/ip6.h | 169 + .../lwip2-src/src/include/lwip/prot/mld6.h | 70 + .../lwip2-src/src/include/lwip/prot/nd6.h | 277 + .../lwip2-src/src/include/lwip/prot/tcp.h | 97 + .../lwip2-src/src/include/lwip/prot/udp.h | 68 + .../lwip2/lwip2-src/src/include/lwip/raw.h | 118 + .../lwip2/lwip2-src/src/include/lwip/sio.h | 142 + .../lwip2/lwip2-src/src/include/lwip/snmp.h | 213 + .../lwip2-src/src/include/lwip/sockets.h | 593 ++ .../lwip2/lwip2-src/src/include/lwip/stats.h | 491 ++ .../lwip2/lwip2-src/src/include/lwip/sys.h | 455 + .../lwip2/lwip2-src/src/include/lwip/tcp.h | 433 + .../lwip2/lwip2-src/src/include/lwip/tcpip.h | 106 + .../lwip2-src/src/include/lwip/timeouts.h | 121 + .../lwip2/lwip2-src/src/include/lwip/udp.h | 182 + .../lwip2-src/src/include/netif/etharp.h | 3 + .../lwip2-src/src/include/netif/ethernet.h | 77 + .../lwip2-src/src/include/netif/lowpan6.h | 86 + .../src/include/netif/lowpan6_opts.h | 70 + .../lwip2-src/src/include/netif/ppp/ccp.h | 156 + .../src/include/netif/ppp/chap-md5.h | 36 + .../src/include/netif/ppp/chap-new.h | 192 + .../lwip2-src/src/include/netif/ppp/chap_ms.h | 44 + .../lwip2-src/src/include/netif/ppp/eap.h | 169 + .../lwip2-src/src/include/netif/ppp/ecp.h | 50 + .../lwip2-src/src/include/netif/ppp/eui64.h | 94 + .../lwip2-src/src/include/netif/ppp/fsm.h | 175 + .../lwip2-src/src/include/netif/ppp/ipcp.h | 126 + .../lwip2-src/src/include/netif/ppp/ipv6cp.h | 183 + .../lwip2-src/src/include/netif/ppp/lcp.h | 171 + .../lwip2-src/src/include/netif/ppp/magic.h | 122 + .../lwip2-src/src/include/netif/ppp/mppe.h | 173 + .../src/include/netif/ppp/polarssl/arc4.h | 81 + .../src/include/netif/ppp/polarssl/des.h | 92 + .../src/include/netif/ppp/polarssl/md4.h | 97 + .../src/include/netif/ppp/polarssl/md5.h | 96 + .../src/include/netif/ppp/polarssl/sha1.h | 96 + .../lwip2-src/src/include/netif/ppp/ppp.h | 690 ++ .../src/include/netif/ppp/ppp_impl.h | 629 ++ .../src/include/netif/ppp/ppp_opts.h | 593 ++ .../lwip2-src/src/include/netif/ppp/pppapi.h | 137 + .../src/include/netif/ppp/pppcrypt.h | 136 + .../src/include/netif/ppp/pppdebug.h | 80 + .../lwip2-src/src/include/netif/ppp/pppoe.h | 179 + .../src/include/netif/ppp/pppol2tp.h | 201 + .../lwip2-src/src/include/netif/ppp/pppos.h | 118 + .../lwip2-src/src/include/netif/ppp/upap.h | 123 + .../lwip2-src/src/include/netif/ppp/vj.h | 161 + .../lwip2-src/src/include/netif/slipif.h | 87 + .../lwip2/lwip2-src/src/include/posix/errno.h | 33 + .../lwip2/lwip2-src/src/include/posix/netdb.h | 33 + .../lwip2-src/src/include/posix/sys/socket.h | 33 + .../lwip2/lwip2-src/src/netif/FILES | 24 + .../lwip2/lwip2-src/src/netif/ethernet.c | 314 + .../lwip2/lwip2-src/src/netif/ethernetif.c | 335 + .../lwip2/lwip2-src/src/netif/lowpan6.c | 1193 +++ .../lwip2-src/src/netif/ppp/PPPD_FOLLOWUP | 473 + .../lwip2/lwip2-src/src/netif/ppp/auth.c | 2510 ++++++ .../lwip2/lwip2-src/src/netif/ppp/ccp.c | 1740 ++++ .../lwip2/lwip2-src/src/netif/ppp/chap-md5.c | 126 + .../lwip2/lwip2-src/src/netif/ppp/chap-new.c | 677 ++ .../lwip2/lwip2-src/src/netif/ppp/chap_ms.c | 962 +++ .../lwip2/lwip2-src/src/netif/ppp/demand.c | 465 + .../lwip2/lwip2-src/src/netif/ppp/eap.c | 2423 ++++++ .../lwip2/lwip2-src/src/netif/ppp/ecp.c | 191 + .../lwip2/lwip2-src/src/netif/ppp/eui64.c | 56 + .../lwip2/lwip2-src/src/netif/ppp/fsm.c | 799 ++ .../lwip2/lwip2-src/src/netif/ppp/ipcp.c | 2418 ++++++ .../lwip2/lwip2-src/src/netif/ppp/ipv6cp.c | 1533 ++++ .../lwip2/lwip2-src/src/netif/ppp/lcp.c | 2790 ++++++ .../lwip2/lwip2-src/src/netif/ppp/magic.c | 294 + .../lwip2/lwip2-src/src/netif/ppp/mppe.c | 412 + .../lwip2/lwip2-src/src/netif/ppp/multilink.c | 609 ++ .../lwip2-src/src/netif/ppp/polarssl/README | 22 + .../lwip2-src/src/netif/ppp/polarssl/arc4.c | 101 + .../lwip2-src/src/netif/ppp/polarssl/des.c | 422 + .../lwip2-src/src/netif/ppp/polarssl/md4.c | 281 + .../lwip2-src/src/netif/ppp/polarssl/md5.c | 300 + .../lwip2-src/src/netif/ppp/polarssl/sha1.c | 335 + .../lwip2/lwip2-src/src/netif/ppp/ppp.c | 1647 ++++ .../lwip2/lwip2-src/src/netif/ppp/pppapi.c | 427 + .../lwip2/lwip2-src/src/netif/ppp/pppcrypt.c | 66 + .../lwip2/lwip2-src/src/netif/ppp/pppoe.c | 1191 +++ .../lwip2/lwip2-src/src/netif/ppp/pppol2tp.c | 1131 +++ .../lwip2/lwip2-src/src/netif/ppp/pppos.c | 875 ++ .../lwip2/lwip2-src/src/netif/ppp/upap.c | 677 ++ .../lwip2/lwip2-src/src/netif/ppp/utils.c | 959 +++ .../lwip2/lwip2-src/src/netif/ppp/vj.c | 695 ++ .../lwip2/lwip2-src/src/netif/slipif.c | 555 ++ .../lwip2/lwip2-src/test/fuzz/Makefile | 53 + .../lwip2/lwip2-src/test/fuzz/README | 34 + .../lwip2/lwip2-src/test/fuzz/config.h | 0 .../lwip2/lwip2-src/test/fuzz/fuzz.c | 136 + .../test/fuzz/inputs/arp/arp_req.bin | Bin 0 -> 42 bytes .../test/fuzz/inputs/icmp/icmp_ping.bin | Bin 0 -> 98 bytes .../inputs/ipv6/neighbor_solicitation.bin | Bin 0 -> 86 bytes .../test/fuzz/inputs/ipv6/router_adv.bin | Bin 0 -> 118 bytes .../test/fuzz/inputs/tcp/tcp_syn.bin | Bin 0 -> 74 bytes .../test/fuzz/inputs/udp/udp_port_5000.bin | Bin 0 -> 50 bytes .../lwip2/lwip2-src/test/fuzz/lwipopts.h | 68 + .../lwip2-src/test/fuzz/output_to_pcap.sh | 31 + .../lwip2/lwip2-src/test/unit/core/test_mem.c | 121 + .../lwip2/lwip2-src/test/unit/core/test_mem.h | 8 + .../lwip2-src/test/unit/core/test_pbuf.c | 239 + .../lwip2-src/test/unit/core/test_pbuf.h | 8 + .../lwip2-src/test/unit/dhcp/test_dhcp.c | 1024 +++ .../lwip2-src/test/unit/dhcp/test_dhcp.h | 8 + .../lwip2-src/test/unit/etharp/test_etharp.c | 269 + .../lwip2-src/test/unit/etharp/test_etharp.h | 8 + .../lwip2/lwip2-src/test/unit/lwip_check.h | 37 + .../lwip2-src/test/unit/lwip_unittests.c | 70 + .../lwip2/lwip2-src/test/unit/lwipopts.h | 62 + .../lwip2-src/test/unit/mdns/test_mdns.c | 915 ++ .../lwip2-src/test/unit/mdns/test_mdns.h | 8 + .../lwip2-src/test/unit/tcp/tcp_helper.c | 314 + .../lwip2-src/test/unit/tcp/tcp_helper.h | 52 + .../lwip2/lwip2-src/test/unit/tcp/test_tcp.c | 744 ++ .../lwip2/lwip2-src/test/unit/tcp/test_tcp.h | 8 + .../lwip2-src/test/unit/tcp/test_tcp_oos.c | 1049 +++ .../lwip2-src/test/unit/tcp/test_tcp_oos.h | 8 + .../lwip2/lwip2-src/test/unit/udp/test_udp.c | 68 + .../lwip2/lwip2-src/test/unit/udp/test_udp.h | 8 + .../lwip2/makefiles/Makefile.build-lwip2 | 56 + .../third-party/lwip2/makefiles/Makefile.defs | 10 + .../third-party/lwip2/makefiles/Makefile.glue | 14 + .../lwip2/makefiles/Makefile.glue-esp | 12 + .../lwip2/makefiles/Makefile.lwip2 | 30 + .../lwip2/makefiles/Makefile.rules | 11 + .../lwip2/makefiles/make-lwip-hash | 15 + .../lwip2/makefiles/patch-non-local-includes | 9 + Sming/third-party/pwm/pwm.c | 11 +- 1179 files changed, 342329 insertions(+), 14 deletions(-) delete mode 160000 Sming/third-party/ESP8266_NONOS_SDK create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/License create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/VERSION create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user1.2048.new.5.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user2.2048.new.5.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user1.1024.new.2.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user2.1024.new.2.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/1024+1024/user1.2048.new.5.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/1024+1024/user2.2048.new.5.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/512+512/user1.1024.new.2.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/512+512/user2.1024.new.2.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/blank.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.2.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.6.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.7.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/bin/esp_init_data_default.bin create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/documents/readme.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/gpio16.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/hw_timer.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/i2c_master.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/key.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/sdio_slv.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_interface.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_overlap.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/uart.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/gpio16.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/i2c_master.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/key.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/sdio_slv.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/slc_register.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_interface.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_overlap.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_register.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart_register.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/driver_lib/make_lib.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/i2c_master.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/key.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/driver/i2c_master.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/driver/key.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/cert.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/private_key.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_devicefind.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform_timer.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_iot_version.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_json.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light_adj.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_plug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_sensor.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_webserver.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_devicefind.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform_timer.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_json.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light_adj.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_plug.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_sensor.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_webserver.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/!!!readme!!!.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.bat create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/at_upgrade.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/!!!readme!!!.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.bat create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/at_upgrade.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/sdio_slv.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.bat create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/sdio_slv.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/slc_register.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/version.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/at_upgrade.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart_register.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/wifi.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/debug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt_msg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/proto.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/queue.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/ringbuf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/typedef.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/utils.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/config.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/wifi.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/debug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt_msg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/proto.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/queue.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/ringbuf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/typedef.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/utils.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt_msg.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/proto.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/queue.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/ringbuf.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/utils.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/spi_test.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/spi_test.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/readme.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/!!!readme!!!.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/model two-dimension code.rar create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/ca.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.der create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.key create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.pem create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.crt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.key create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.p12 create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.pem create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/dh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.crt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.key create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.p12 create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.pem create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_crt.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_key.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/import_ca_crt_key.sh create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/str2hex create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/key.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.bat create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/driver/key.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/user_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/user_main.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/airkiss.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/at_custom.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/espconn.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/espnow.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/gpio.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/ip_addr.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/json/json.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/json/jsonparse.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/json/jsontree.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/mem.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/mesh.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/ping.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/pwm.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/queue.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/simple_pair.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/smartconfig.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/sntp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/upgrade.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/include/wpa2_enterprise.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app1.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app2.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.2048.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app1.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app2.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app1.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app2.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app1.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app2.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libairkiss.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libat.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libc.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libcrypto.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libdriver.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libespnow.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libgcc.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libjson.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/liblwip.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/liblwip_536.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libmain.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libmbedtls.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libmesh.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libnet80211.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libphy.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libpp.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/libpwm.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libsmartconfig.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libssl.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libupgrade.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libwpa.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libwpa2.a create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/lib/libwps.a create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/readme.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libc_funcs.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libgcc_funcs.txt create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/cc.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/perf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/sys_arch.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api_msg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/dhcpserver.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_buf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_tcp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_udp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/ping.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/time.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/arch.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/autoip.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/debug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/def.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dhcp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dns.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/err.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/icmp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/igmp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet_chksum.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/init.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_addr.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_frag.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mdns.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mem.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp_std.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netbuf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netdb.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netif.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netifapi.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/opt.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/pbuf.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/puck_def.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/raw.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sio.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_asn1.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_msg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_structs.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sntp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sockets.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/stats.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sys.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp_impl.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcpip.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/timers.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/udp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwipopts.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aes.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aesni.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/arc4.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1write.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/base64.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bignum.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/blowfish.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bn_mul.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/camellia.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ccm.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/certs.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/check_config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher_internal.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/compat-1.3.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config_esp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ctr_drbg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/debug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/des.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/dhm.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdh.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdsa.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecjpake.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy_poll.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/error.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/gcm.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/havege.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/hmac_drbg.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/mbedtls_debug.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md2.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md4.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md5.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md_internal.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/memory_buffer_alloc.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/net.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/oid.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/padlock.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pem.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk_internal.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs11.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs12.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs5.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/platform.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ripemd160.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/rsa.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha1.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha256.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha512.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cache.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ciphersuites.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cookie.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_internal.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ticket.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/espconn_mbedtls.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/socket.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/threading.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/timing.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/version.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crl.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crt.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_csr.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/xtea.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/etharp.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/if_llc.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/ppp_oe.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/wlan_lwip_if.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_secure.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_ssl.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint_impl.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_cert.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_config.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto_misc.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_int.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_port.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_private_key.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_ssl.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_tls1.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_version.h create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/include/user_config.h create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_lib.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_msg.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/err.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netbuf.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netdb.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netifapi.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/sockets.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/tcpip.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/dhcpserver.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_buf.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_mdns.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_tcp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_udp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/netio.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/ping.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/def.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dhcp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dns.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/init.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/autoip.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/icmp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/igmp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet_chksum.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_addr.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_frag.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mdns.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mem.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/memp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/netif.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/pbuf.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/raw.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sntp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/stats.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys_arch.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_in.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_out.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/timers.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/udp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/Makefile create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/etharp.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/third_party/make_lib.sh create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_mbedtls.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_secure.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPFile.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPSocket.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aes.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aesni.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/arc4.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1parse.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1write.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/base64.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/bignum.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/blowfish.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/camellia.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ccm.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/certs.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher_wrap.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ctr_drbg.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/debug.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/des.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/dhm.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdh.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdsa.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecjpake.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp_curves.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy_poll.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/error.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/gcm.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/havege.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/hmac_drbg.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md2.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md4.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md5.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md_wrap.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/memory_buffer_alloc.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/net.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/oid.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/padlock.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pem.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk_wrap.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs11.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs12.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs5.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkparse.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkwrite.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/platform.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ripemd160.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/rsa.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha1.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha256.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha512.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cache.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ciphersuites.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cli.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cookie.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_srv.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ticket.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_tls.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/threading.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/timing.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version_features.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_create.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crl.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crt.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_csr.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_crt.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_csr.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/xtea.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/Makefile create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/esp_hardware.c create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/net.c create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/tools/README.md create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/tools/gen_appbin.py create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/tools/make_cacert.py create mode 100644 Sming/third-party/ESP8266_NONOS_SDK/tools/make_cert.py create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/tools/makefile.sh create mode 100755 Sming/third-party/ESP8266_NONOS_SDK/tools/rmfile.sh delete mode 160000 Sming/third-party/lwip2 create mode 100644 Sming/third-party/lwip2/Makefile.arduino create mode 100644 Sming/third-party/lwip2/Makefile.open create mode 100644 Sming/third-party/lwip2/Makefile.sming create mode 100644 Sming/third-party/lwip2/README.md create mode 100644 Sming/third-party/lwip2/build/api/api_lib.d create mode 100644 Sming/third-party/lwip2/build/api/api_lib.o create mode 100644 Sming/third-party/lwip2/build/api/api_msg.d create mode 100644 Sming/third-party/lwip2/build/api/api_msg.o create mode 100644 Sming/third-party/lwip2/build/api/err.d create mode 100644 Sming/third-party/lwip2/build/api/err.o create mode 100644 Sming/third-party/lwip2/build/api/netbuf.d create mode 100644 Sming/third-party/lwip2/build/api/netbuf.o create mode 100644 Sming/third-party/lwip2/build/api/netdb.d create mode 100644 Sming/third-party/lwip2/build/api/netdb.o create mode 100644 Sming/third-party/lwip2/build/api/netifapi.d create mode 100644 Sming/third-party/lwip2/build/api/netifapi.o create mode 100644 Sming/third-party/lwip2/build/api/sockets.d create mode 100644 Sming/third-party/lwip2/build/api/sockets.o create mode 100644 Sming/third-party/lwip2/build/api/tcpip.d create mode 100644 Sming/third-party/lwip2/build/api/tcpip.o create mode 100644 Sming/third-party/lwip2/build/apps/sntp/sntp.d create mode 100644 Sming/third-party/lwip2/build/apps/sntp/sntp.o create mode 100644 Sming/third-party/lwip2/build/core/def.d create mode 100644 Sming/third-party/lwip2/build/core/def.o create mode 100644 Sming/third-party/lwip2/build/core/dns.d create mode 100644 Sming/third-party/lwip2/build/core/dns.o create mode 100644 Sming/third-party/lwip2/build/core/inet_chksum.d create mode 100644 Sming/third-party/lwip2/build/core/inet_chksum.o create mode 100644 Sming/third-party/lwip2/build/core/init.d create mode 100644 Sming/third-party/lwip2/build/core/init.o create mode 100644 Sming/third-party/lwip2/build/core/ip.d create mode 100644 Sming/third-party/lwip2/build/core/ip.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/autoip.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/autoip.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/dhcp.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/dhcp.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/etharp.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/etharp.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/icmp.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/icmp.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/igmp.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/igmp.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4_addr.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4_addr.o create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4_frag.d create mode 100644 Sming/third-party/lwip2/build/core/ipv4/ip4_frag.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/dhcp6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/dhcp6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ethip6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ethip6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/icmp6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/icmp6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/inet6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/inet6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6_addr.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6_addr.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6_frag.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/ip6_frag.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/mld6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/mld6.o create mode 100644 Sming/third-party/lwip2/build/core/ipv6/nd6.d create mode 100644 Sming/third-party/lwip2/build/core/ipv6/nd6.o create mode 100644 Sming/third-party/lwip2/build/core/mem.d create mode 100644 Sming/third-party/lwip2/build/core/mem.o create mode 100644 Sming/third-party/lwip2/build/core/memp.d create mode 100644 Sming/third-party/lwip2/build/core/memp.o create mode 100644 Sming/third-party/lwip2/build/core/netif.d create mode 100644 Sming/third-party/lwip2/build/core/netif.o create mode 100644 Sming/third-party/lwip2/build/core/pbuf.d create mode 100644 Sming/third-party/lwip2/build/core/pbuf.o create mode 100644 Sming/third-party/lwip2/build/core/raw.d create mode 100644 Sming/third-party/lwip2/build/core/raw.o create mode 100644 Sming/third-party/lwip2/build/core/stats.d create mode 100644 Sming/third-party/lwip2/build/core/stats.o create mode 100644 Sming/third-party/lwip2/build/core/sys.d create mode 100644 Sming/third-party/lwip2/build/core/sys.o create mode 100644 Sming/third-party/lwip2/build/core/tcp.d create mode 100644 Sming/third-party/lwip2/build/core/tcp.o create mode 100644 Sming/third-party/lwip2/build/core/tcp_in.d create mode 100644 Sming/third-party/lwip2/build/core/tcp_in.o create mode 100644 Sming/third-party/lwip2/build/core/tcp_out.d create mode 100644 Sming/third-party/lwip2/build/core/tcp_out.o create mode 100644 Sming/third-party/lwip2/build/core/timeouts.d create mode 100644 Sming/third-party/lwip2/build/core/timeouts.o create mode 100644 Sming/third-party/lwip2/build/core/udp.d create mode 100644 Sming/third-party/lwip2/build/core/udp.o create mode 100644 Sming/third-party/lwip2/build/glue-esp/lwip-esp.d create mode 100644 Sming/third-party/lwip2/build/glue-esp/lwip-esp.o create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.d create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.o create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-sntp.d create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-sntp.o create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-time.d create mode 100644 Sming/third-party/lwip2/build/glue-lwip/esp-time.o create mode 100644 Sming/third-party/lwip2/build/glue-lwip/lwip-git.d create mode 100644 Sming/third-party/lwip2/build/glue-lwip/lwip-git.o create mode 100644 Sming/third-party/lwip2/build/glue/doprint.d create mode 100644 Sming/third-party/lwip2/build/glue/doprint.o create mode 100644 Sming/third-party/lwip2/build/glue/uprint.d create mode 100644 Sming/third-party/lwip2/build/glue/uprint.o create mode 100644 Sming/third-party/lwip2/build/netif/ethernet.d create mode 100644 Sming/third-party/lwip2/build/netif/ethernet.o create mode 100644 Sming/third-party/lwip2/build/user_config.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/README.md create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/arch/cc.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/arch/perf.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/arch/sys_arch.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/api.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/api_msg.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/dhcpserver.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_buf.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_tcp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_udp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/ping.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/time.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/arch.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/autoip.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/debug.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/def.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/dhcp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/dns.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/err.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/icmp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/igmp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet_chksum.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/init.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_addr.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_frag.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/mdns.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/mem.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp_std.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/netbuf.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/netdb.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/netif.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/netifapi.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/opt.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/pbuf.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/puck_def.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/raw.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/sio.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_asn1.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_msg.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_structs.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/sntp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/sockets.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/stats.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/sys.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp_impl.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcpip.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/timers.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwip/udp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/lwipopts.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/netif/etharp.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/netif/if_llc.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/netif/ppp_oe.h create mode 100644 Sming/third-party/lwip2/glue-esp/include-esp/netif/wlan_lwip_if.h create mode 100644 Sming/third-party/lwip2/glue-esp/lwip-esp.c create mode 100644 Sming/third-party/lwip2/glue-lwip/arch/cc.h create mode 100644 Sming/third-party/lwip2/glue-lwip/arch/sys_arch.h create mode 100644 Sming/third-party/lwip2/glue-lwip/esp-dhcpserver.c create mode 100644 Sming/third-party/lwip2/glue-lwip/esp-sntp.c create mode 100644 Sming/third-party/lwip2/glue-lwip/esp-time.c create mode 100644 Sming/third-party/lwip2/glue-lwip/lwip-git-hash.h create mode 100644 Sming/third-party/lwip2/glue-lwip/lwip-git.c create mode 100644 Sming/third-party/lwip2/glue-lwip/lwip-helper.h create mode 100644 Sming/third-party/lwip2/glue-lwip/lwip/apps-esp/dhcpserver.h create mode 100644 Sming/third-party/lwip2/glue-lwip/lwipopts.h create mode 100644 Sming/third-party/lwip2/glue/doprint.c create mode 100644 Sming/third-party/lwip2/glue/doprint.h create mode 100644 Sming/third-party/lwip2/glue/esp-missing.h create mode 100644 Sming/third-party/lwip2/glue/glue.h create mode 100644 Sming/third-party/lwip2/glue/uprint.c create mode 100644 Sming/third-party/lwip2/glue/uprint.h create mode 100644 Sming/third-party/lwip2/include/README.md create mode 100644 Sming/third-party/lwip2/include/arch/cc.h create mode 100644 Sming/third-party/lwip2/include/arch/sys_arch.h create mode 100644 Sming/third-party/lwip2/include/espconn.h create mode 100644 Sming/third-party/lwip2/include/lwip-git-hash.h create mode 100644 Sming/third-party/lwip2/include/lwip/api.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/FILES create mode 100644 Sming/third-party/lwip2/include/lwip/apps/fs.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/httpd.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/httpd_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/lwiperf.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/mdns.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/mdns_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/mdns_priv.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/mqtt.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/mqtt_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/netbiosns.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/netbiosns_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_core.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_mib2.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_scalar.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_table.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmp_threadsync.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/snmpv3.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/sntp.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/sntp_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/tftp_opts.h create mode 100644 Sming/third-party/lwip2/include/lwip/apps/tftp_server.h create mode 100644 Sming/third-party/lwip2/include/lwip/arch.h create mode 100644 Sming/third-party/lwip2/include/lwip/autoip.h create mode 100644 Sming/third-party/lwip2/include/lwip/debug.h create mode 100644 Sming/third-party/lwip2/include/lwip/def.h create mode 100644 Sming/third-party/lwip2/include/lwip/dhcp.h create mode 100644 Sming/third-party/lwip2/include/lwip/dhcp6.h create mode 100644 Sming/third-party/lwip2/include/lwip/dns.h create mode 100644 Sming/third-party/lwip2/include/lwip/err.h create mode 100644 Sming/third-party/lwip2/include/lwip/errno.h create mode 100644 Sming/third-party/lwip2/include/lwip/etharp.h create mode 100644 Sming/third-party/lwip2/include/lwip/ethip6.h create mode 100644 Sming/third-party/lwip2/include/lwip/icmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/icmp6.h create mode 100644 Sming/third-party/lwip2/include/lwip/igmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/inet.h create mode 100644 Sming/third-party/lwip2/include/lwip/inet_chksum.h create mode 100644 Sming/third-party/lwip2/include/lwip/init.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip4.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip4_addr.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip4_frag.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip6.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip6_addr.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip6_frag.h create mode 100644 Sming/third-party/lwip2/include/lwip/ip_addr.h create mode 100644 Sming/third-party/lwip2/include/lwip/mem.h create mode 100644 Sming/third-party/lwip2/include/lwip/memp.h create mode 100644 Sming/third-party/lwip2/include/lwip/mld6.h create mode 100644 Sming/third-party/lwip2/include/lwip/nd6.h create mode 100644 Sming/third-party/lwip2/include/lwip/netbuf.h create mode 100644 Sming/third-party/lwip2/include/lwip/netdb.h create mode 100644 Sming/third-party/lwip2/include/lwip/netif.h create mode 100644 Sming/third-party/lwip2/include/lwip/netifapi.h create mode 100644 Sming/third-party/lwip2/include/lwip/opt.h create mode 100644 Sming/third-party/lwip2/include/lwip/pbuf.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/api_msg.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/memp_priv.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/memp_std.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/nd6_priv.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/tcp_priv.h create mode 100644 Sming/third-party/lwip2/include/lwip/priv/tcpip_priv.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/autoip.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/dhcp.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/dns.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/etharp.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/ethernet.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/icmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/icmp6.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/igmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/ip.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/ip4.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/ip6.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/mld6.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/nd6.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/tcp.h create mode 100644 Sming/third-party/lwip2/include/lwip/prot/udp.h create mode 100644 Sming/third-party/lwip2/include/lwip/raw.h create mode 100644 Sming/third-party/lwip2/include/lwip/sio.h create mode 100644 Sming/third-party/lwip2/include/lwip/snmp.h create mode 100644 Sming/third-party/lwip2/include/lwip/sockets.h create mode 100644 Sming/third-party/lwip2/include/lwip/stats.h create mode 100644 Sming/third-party/lwip2/include/lwip/sys.h create mode 100644 Sming/third-party/lwip2/include/lwip/tcp.h create mode 100644 Sming/third-party/lwip2/include/lwip/tcpip.h create mode 100644 Sming/third-party/lwip2/include/lwip/timeouts.h create mode 100644 Sming/third-party/lwip2/include/lwip/udp.h create mode 100644 Sming/third-party/lwip2/include/lwipopts.h create mode 100644 Sming/third-party/lwip2/include/netif/etharp.h create mode 100644 Sming/third-party/lwip2/include/netif/ethernet.h create mode 100644 Sming/third-party/lwip2/include/netif/lowpan6.h create mode 100644 Sming/third-party/lwip2/include/netif/lowpan6_opts.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ccp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/chap-md5.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/chap-new.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/chap_ms.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/eap.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ecp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/eui64.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/fsm.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ipcp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ipv6cp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/lcp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/magic.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/mppe.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/polarssl/arc4.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/polarssl/des.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/polarssl/md4.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/polarssl/md5.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/polarssl/sha1.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ppp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ppp_impl.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/ppp_opts.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppapi.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppcrypt.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppdebug.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppoe.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppol2tp.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/pppos.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/upap.h create mode 100644 Sming/third-party/lwip2/include/netif/ppp/vj.h create mode 100644 Sming/third-party/lwip2/include/netif/slipif.h create mode 100644 Sming/third-party/lwip2/include/posix/errno.h create mode 100644 Sming/third-party/lwip2/include/posix/netdb.h create mode 100644 Sming/third-party/lwip2/include/posix/sys/socket.h create mode 100644 Sming/third-party/lwip2/liblwip2.a create mode 100644 Sming/third-party/lwip2/lwip2-src/.gitattributes create mode 100644 Sming/third-party/lwip2/lwip2-src/.gitignore create mode 100644 Sming/third-party/lwip2/lwip2-src/CHANGELOG create mode 100644 Sming/third-party/lwip2/lwip2-src/COPYING create mode 100644 Sming/third-party/lwip2/lwip2-src/FILES create mode 100644 Sming/third-party/lwip2/lwip2-src/README create mode 100644 Sming/third-party/lwip2/lwip2-src/UPGRADING create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/FILES create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/NO_SYS_SampleCode.c create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/contrib.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.bat create mode 100755 Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.sh create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/doxygen/lwip.Doxyfile create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/doxygen/main_page.h create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/doxygen/output/index.html create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/mdns.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/mqtt_client.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/ppp.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/rawapi.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/savannah.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/doc/sys_arch.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/src/FILES create mode 100644 Sming/third-party/lwip2/lwip2-src/src/Filelists.mk create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/api_lib.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/api_msg.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/err.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/netbuf.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/netdb.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/netifapi.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/sockets.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/api/tcpip.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/404.html create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/img/sics.gif create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/index.html create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fsdata.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fsdata.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/httpd.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/httpd_structs.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/readme.txt create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/lwiperf/lwiperf.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/mdns/mdns.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/mqtt/mqtt.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/netbiosns/netbiosns.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_icmp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_interfaces.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_ip.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_snmp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_system.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_tcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_udp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_netconn.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_raw.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_scalar.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_table.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_threadsync.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_traps.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_dummy.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_mbedtls.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/sntp/sntp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/apps/tftp/tftp_server.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/def.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/dns.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/inet_chksum.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/init.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ip.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/autoip.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/dhcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/etharp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/icmp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/igmp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_addr.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_frag.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/dhcp6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ethip6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/icmp6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/inet6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_addr.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_frag.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/mld6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/ipv6/nd6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/mem.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/memp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/netif.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/pbuf.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/raw.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/stats.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/sys.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/tcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/tcp_in.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/tcp_out.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/timeouts.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/core/udp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/api.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/FILES create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/fs.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/lwiperf.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_core.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_mib2.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_scalar.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_table.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_threadsync.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmpv3.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_server.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/arch.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/autoip.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/debug.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/def.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/dns.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/err.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/errno.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/etharp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ethip6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/igmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet_chksum.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/init.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_addr.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_frag.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_addr.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_frag.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip_addr.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/mem.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/memp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/mld6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/nd6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/netbuf.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/netdb.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/netif.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/netifapi.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/opt.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/pbuf.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/api_msg.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_std.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/nd6_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcp_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcpip_priv.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/autoip.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dhcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dns.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/etharp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ethernet.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/igmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip4.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/mld6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/nd6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/tcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/udp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/raw.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/sio.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/snmp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/sockets.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/stats.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/sys.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcpip.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/timeouts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/lwip/udp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/etharp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ethernet.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ccp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-md5.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-new.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap_ms.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eap.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ecp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eui64.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/fsm.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipv6cp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/lcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/magic.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/mppe.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/arc4.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/des.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md4.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md5.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/sha1.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_impl.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_opts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppapi.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppcrypt.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppdebug.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppoe.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppol2tp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppos.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/upap.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/vj.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/netif/slipif.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/posix/errno.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/posix/netdb.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/include/posix/sys/socket.h create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/FILES create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ethernet.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ethernetif.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/lowpan6.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/PPPD_FOLLOWUP create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/auth.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ccp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-md5.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-new.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap_ms.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/demand.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eap.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ecp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eui64.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/fsm.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipv6cp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/lcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/magic.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/mppe.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/multilink.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/README create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/arc4.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/des.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md4.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md5.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/sha1.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ppp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppapi.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppcrypt.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppoe.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppol2tp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppos.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/upap.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/utils.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/ppp/vj.c create mode 100644 Sming/third-party/lwip2/lwip2-src/src/netif/slipif.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/Makefile create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/README create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/config.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/fuzz.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/arp/arp_req.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/icmp/icmp_ping.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/ipv6/neighbor_solicitation.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/ipv6/router_adv.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/tcp/tcp_syn.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/udp/udp_port_5000.bin create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/lwipopts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/fuzz/output_to_pcap.sh create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/lwip_check.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/lwip_unittests.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/lwipopts.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.h create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.c create mode 100644 Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.h create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.build-lwip2 create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.defs create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.glue create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.glue-esp create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.lwip2 create mode 100644 Sming/third-party/lwip2/makefiles/Makefile.rules create mode 100755 Sming/third-party/lwip2/makefiles/make-lwip-hash create mode 100755 Sming/third-party/lwip2/makefiles/patch-non-local-includes diff --git a/Sming/third-party/ESP8266_NONOS_SDK b/Sming/third-party/ESP8266_NONOS_SDK deleted file mode 160000 index 61248df5f6..0000000000 --- a/Sming/third-party/ESP8266_NONOS_SDK +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61248df5f6d45d130313b412f7492f581fd4cadf diff --git a/Sming/third-party/ESP8266_NONOS_SDK/License b/Sming/third-party/ESP8266_NONOS_SDK/License new file mode 100644 index 0000000000..8a9fade8bd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/License @@ -0,0 +1,24 @@ +ESPRESSIF MIT License + +Copyright (c) 2015 + +Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, it is free of charge, to any person obtaining a copy of this software and associated documentation files (the ¡°Software¡±), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ¡°AS IS¡±, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +ÀÖöÎ MIT Ðí¿ÉÖ¤ + +°æȨ (c) 2015 <ÀÖöÎÐÅÏ¢¿Æ¼¼£¨ÉϺ££©ÓÐÏÞ¹«Ë¾> + +¸ÃÐí¿ÉÖ¤ÊÚȨ½öÏÞÓÚÀÖöÎÐÅÏ¢¿Æ¼¼ ESP8266 ²úÆ·µÄÓ¦Óÿª·¢¡£ÔÚ´ËÇé¿öÏ£¬¸ÃÐí¿ÉÖ¤Ãâ·ÑÊÚȨÈκλñµÃ¸ÃÈí¼þ¼°ÆäÏà¹ØÎĵµ£¨Í³³ÆΪ¡°Èí¼þ¡±£©µÄÈËÎÞÏÞÖƵؾ­Óª¸ÃÈí¼þ£¬°üÀ¨ÎÞÏÞÖƵÄʹÓᢸ´ÖÆ¡¢Ð޸ġ¢ºÏ²¢¡¢³ö°æ·¢ÐС¢É¢²¼¡¢ÔÙÊÚȨ¡¢¼°··ÊÛÈí¼þ¼°Èí¼þ¸±±¾µÄȨÀû¡£±»ÊÚȨÈËÔÚÏíÊÜÕâЩȨÀûµÄͬʱ£¬Ðè·þ´ÓÏÂÃæµÄÌõ¼þ£º + +ÔÚÈí¼þºÍÈí¼þµÄËùÓи±±¾Öж¼±ØÐë°üº¬ÒÔÉϵİæȨÉùÃ÷ºÍÊÚȨÉùÃ÷¡£ + +¸ÃÈí¼þ°´±¾À´µÄÑù×ÓÌṩ£¬Ã»ÓÐÈκÎÃ÷È·»ò°µº¬µÄµ£±££¬°üÀ¨µ«²»½öÏÞÓÚ¹ØÓÚÊÔÏúÐÔ¡¢ÊʺÏijһÌض¨ÓÃ;ºÍ·ÇÇÖȨµÄ±£Ö¤¡£×÷ÕߺͰæȨ³ÖÓÐÈËÔÚÈκÎÇé¿öϾù²»¾ÍÓÉÈí¼þ»òÈí¼þʹÓÃÒýÆðµÄÒÔºÏͬÐÎʽ¡¢ÃñÊÂÇÖȨ»òÆäËü·½Ê½Ìá³öµÄÈκÎË÷Åâ¡¢Ë𺦻òÆäËüÔðÈθºÔð¡£ + + + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/Makefile new file mode 100644 index 0000000000..11df45c3bd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/Makefile @@ -0,0 +1,396 @@ +# copyright (c) 2010 Espressif System +# +ifndef PDIR + +endif + +ifeq ($(COMPILE), gcc) + AR = xtensa-lx106-elf-ar + CC = xtensa-lx106-elf-gcc + NM = xtensa-lx106-elf-nm + CPP = xtensa-lx106-elf-cpp + OBJCOPY = xtensa-lx106-elf-objcopy + OBJDUMP = xtensa-lx106-elf-objdump +else + AR = xt-ar + CC = xt-xcc + NM = xt-nm + CPP = xt-cpp + OBJCOPY = xt-objcopy + OBJDUMP = xt-objdump +endif + +BOOT?=none +APP?=0 +SPI_SPEED?=40 +SPI_MODE?=QIO +SPI_SIZE_MAP?=0 + +ifeq ($(BOOT), new) + boot = new +else + ifeq ($(BOOT), old) + boot = old + else + boot = none + endif +endif + +ifeq ($(APP), 1) + app = 1 +else + ifeq ($(APP), 2) + app = 2 + else + app = 0 + endif +endif + +ifeq ($(SPI_SPEED), 26.7) + freqdiv = 1 +else + ifeq ($(SPI_SPEED), 20) + freqdiv = 2 + else + ifeq ($(SPI_SPEED), 80) + freqdiv = 15 + else + freqdiv = 0 + endif + endif +endif + + +ifeq ($(SPI_MODE), QOUT) + mode = 1 +else + ifeq ($(SPI_MODE), DIO) + mode = 2 + else + ifeq ($(SPI_MODE), DOUT) + mode = 3 + else + mode = 0 + endif + endif +endif + +addr = 0x01000 + +ifeq ($(SPI_SIZE_MAP), 1) + size_map = 1 + flash = 256 +else + ifeq ($(SPI_SIZE_MAP), 2) + size_map = 2 + flash = 1024 + ifeq ($(app), 2) + addr = 0x81000 + endif + else + ifeq ($(SPI_SIZE_MAP), 3) + size_map = 3 + flash = 2048 + ifeq ($(app), 2) + addr = 0x81000 + endif + else + ifeq ($(SPI_SIZE_MAP), 4) + size_map = 4 + flash = 4096 + ifeq ($(app), 2) + addr = 0x81000 + endif + else + ifeq ($(SPI_SIZE_MAP), 5) + size_map = 5 + flash = 2048 + ifeq ($(app), 2) + addr = 0x101000 + endif + else + ifeq ($(SPI_SIZE_MAP), 6) + size_map = 6 + flash = 4096 + ifeq ($(app), 2) + addr = 0x101000 + endif + else + ifeq ($(SPI_SIZE_MAP), 8) + size_map = 8 + flash = 8192 + ifeq ($(app), 2) + addr = 0x101000 + endif + else + ifeq ($(SPI_SIZE_MAP), 9) + size_map = 9 + flash = 16384 + ifeq ($(app), 2) + addr = 0x101000 + endif + else + size_map = 0 + flash = 512 + ifeq ($(app), 2) + addr = 0x41000 + endif + endif + endif + endif + endif + endif + endif + endif +endif + +LD_FILE = $(LDDIR)/eagle.app.v6.ld + +ifneq ($(boot), none) +ifneq ($(app),0) + ifneq ($(findstring $(size_map), 6 8 9),) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).2048.ld + else + ifeq ($(size_map), 5) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).2048.ld + else + ifeq ($(size_map), 4) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld + else + ifeq ($(size_map), 3) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld + else + ifeq ($(size_map), 2) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).1024.app$(app).ld + else + ifeq ($(size_map), 0) + LD_FILE = $(LDDIR)/eagle.app.v6.$(boot).512.app$(app).ld + endif + endif + endif + endif + endif + endif + BIN_NAME = user$(app).$(flash).$(boot).$(size_map) +endif +else + app = 0 +endif + +CSRCS ?= $(wildcard *.c) +ASRCs ?= $(wildcard *.s) +ASRCS ?= $(wildcard *.S) +SUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile))) + +ODIR := .output +OBJODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/obj + +OBJS := $(CSRCS:%.c=$(OBJODIR)/%.o) \ + $(ASRCs:%.s=$(OBJODIR)/%.o) \ + $(ASRCS:%.S=$(OBJODIR)/%.o) + +DEPS := $(CSRCS:%.c=$(OBJODIR)/%.d) \ + $(ASRCs:%.s=$(OBJODIR)/%.d) \ + $(ASRCS:%.S=$(OBJODIR)/%.d) + +LIBODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/lib +OLIBS := $(GEN_LIBS:%=$(LIBODIR)/%) + +IMAGEODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/image +OIMAGES := $(GEN_IMAGES:%=$(IMAGEODIR)/%) + +BINODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/bin +OBINS := $(GEN_BINS:%=$(BINODIR)/%) + +CCFLAGS += \ + -g \ + -Wpointer-arith \ + -Wundef \ + -Werror \ + -Wl,-EL \ + -fno-inline-functions \ + -nostdlib \ + -mlongcalls \ + -mtext-section-literals \ + -ffunction-sections \ + -fdata-sections \ + -fno-builtin-printf +# -Wall + +CFLAGS = $(CCFLAGS) $(DEFINES) $(EXTRA_CCFLAGS) $(INCLUDES) +DFLAGS = $(CCFLAGS) $(DDEFINES) $(EXTRA_CCFLAGS) $(INCLUDES) + + +############################################################# +# Functions +# + +define ShortcutRule +$(1): .subdirs $(2)/$(1) +endef + +define MakeLibrary +DEP_LIBS_$(1) = $$(foreach lib,$$(filter %.a,$$(COMPONENTS_$(1))),$$(dir $$(lib))$$(LIBODIR)/$$(notdir $$(lib))) +DEP_OBJS_$(1) = $$(foreach obj,$$(filter %.o,$$(COMPONENTS_$(1))),$$(dir $$(obj))$$(OBJODIR)/$$(notdir $$(obj))) +$$(LIBODIR)/$(1).a: $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(DEPENDS_$(1)) + @mkdir -p $$(LIBODIR) + $$(if $$(filter %.a,$$?),mkdir -p $$(EXTRACT_DIR)_$(1)) + $$(if $$(filter %.a,$$?),cd $$(EXTRACT_DIR)_$(1); $$(foreach lib,$$(filter %.a,$$?),$$(AR) xo $$(UP_EXTRACT_DIR)/$$(lib);)) + $$(AR) ru $$@ $$(filter %.o,$$?) $$(if $$(filter %.a,$$?),$$(EXTRACT_DIR)_$(1)/*.o) + $$(if $$(filter %.a,$$?),$$(RM) -r $$(EXTRACT_DIR)_$(1)) +endef + +define MakeImage +DEP_LIBS_$(1) = $$(foreach lib,$$(filter %.a,$$(COMPONENTS_$(1))),$$(dir $$(lib))$$(LIBODIR)/$$(notdir $$(lib))) +DEP_OBJS_$(1) = $$(foreach obj,$$(filter %.o,$$(COMPONENTS_$(1))),$$(dir $$(obj))$$(OBJODIR)/$$(notdir $$(obj))) +$$(IMAGEODIR)/$(1).out: $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(DEPENDS_$(1)) + @mkdir -p $$(IMAGEODIR) + $$(CC) $$(LDFLAGS) $$(if $$(LINKFLAGS_$(1)),$$(LINKFLAGS_$(1)),$$(LINKFLAGS_DEFAULT) $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1))) -o $$@ +endef + +$(BINODIR)/%.bin: $(IMAGEODIR)/%.out + @mkdir -p $(BINODIR) + +ifeq ($(APP), 0) + @$(RM) -r ../bin/eagle.S ../bin/eagle.dump + @$(OBJDUMP) -x -s $< > ../bin/eagle.dump + @$(OBJDUMP) -S $< > ../bin/eagle.S +else + mkdir -p ../bin/upgrade + @$(RM) -r ../bin/upgrade/$(BIN_NAME).S ../bin/upgrade/$(BIN_NAME).dump + @$(OBJDUMP) -x -s $< > ../bin/upgrade/$(BIN_NAME).dump + @$(OBJDUMP) -S $< > ../bin/upgrade/$(BIN_NAME).S +endif + + @$(OBJCOPY) --only-section .text -O binary $< eagle.app.v6.text.bin + @$(OBJCOPY) --only-section .data -O binary $< eagle.app.v6.data.bin + @$(OBJCOPY) --only-section .rodata -O binary $< eagle.app.v6.rodata.bin + @$(OBJCOPY) --only-section .irom0.text -O binary $< eagle.app.v6.irom0text.bin + + @echo "" + @echo "!!!" + +ifeq ($(app), 0) + @python ../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) $(app) + @mv eagle.app.flash.bin ../bin/eagle.flash.bin + @mv eagle.app.v6.irom0text.bin ../bin/eagle.irom0text.bin + @rm eagle.app.v6.* + @echo "No boot needed." + @echo "Generate eagle.flash.bin and eagle.irom0text.bin successully in folder bin." + @echo "eagle.flash.bin-------->0x00000" + @echo "eagle.irom0text.bin---->0x10000" +else + ifneq ($(boot), new) + @python ../tools/gen_appbin.py $< 1 $(mode) $(freqdiv) $(size_map) $(app) + @echo "Support boot_v1.1 and +" + else + @python ../tools/gen_appbin.py $< 2 $(mode) $(freqdiv) $(size_map) $(app) + + ifeq ($(size_map), 6) + @echo "Support boot_v1.4 and +" + else + ifeq ($(size_map), 5) + @echo "Support boot_v1.4 and +" + else + @echo "Support boot_v1.2 and +" + endif + endif + endif + + @mv eagle.app.flash.bin ../bin/upgrade/$(BIN_NAME).bin + @rm eagle.app.v6.* + @echo "Generate $(BIN_NAME).bin successully in folder bin/upgrade." + @echo "boot.bin------------>0x00000" + @echo "$(BIN_NAME).bin--->$(addr)" +endif + + @echo "!!!" + +############################################################# +# Rules base +# Should be done in top-level makefile only +# + +all: .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS) + +clean: + $(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clean;) + $(RM) -r $(ODIR)/$(TARGET)/$(FLAVOR) + +clobber: $(SPECIAL_CLOBBER) + $(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clobber;) + $(RM) -r $(ODIR) + +.subdirs: + @set -e; $(foreach d, $(SUBDIRS), $(MAKE) -C $(d);) + +#.subdirs: +# $(foreach d, $(SUBDIRS), $(MAKE) -C $(d)) + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),clobber) +ifdef DEPS +sinclude $(DEPS) +endif +endif +endif + +$(OBJODIR)/%.o: %.c + @mkdir -p $(OBJODIR); + $(CC) $(if $(findstring $<,$(DSRCS)),$(DFLAGS),$(CFLAGS)) $(COPTS_$(*F)) -o $@ -c $< + +$(OBJODIR)/%.d: %.c + @mkdir -p $(OBJODIR); + @echo DEPEND: $(CC) -M $(CFLAGS) $< + @set -e; rm -f $@; \ + $(CC) -M $(CFLAGS) $< > $@.$$$$; \ + sed 's,\($*\.o\)[ :]*,$(OBJODIR)/\1 $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +$(OBJODIR)/%.o: %.s + @mkdir -p $(OBJODIR); + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJODIR)/%.d: %.s + @mkdir -p $(OBJODIR); \ + set -e; rm -f $@; \ + $(CC) -M $(CFLAGS) $< > $@.$$$$; \ + sed 's,\($*\.o\)[ :]*,$(OBJODIR)/\1 $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +$(OBJODIR)/%.o: %.S + @mkdir -p $(OBJODIR); + $(CC) $(CFLAGS) -D__ASSEMBLER__ -o $@ -c $< + +$(OBJODIR)/%.d: %.S + @mkdir -p $(OBJODIR); \ + set -e; rm -f $@; \ + $(CC) -M $(CFLAGS) $< > $@.$$$$; \ + sed 's,\($*\.o\)[ :]*,$(OBJODIR)/\1 $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +$(foreach lib,$(GEN_LIBS),$(eval $(call ShortcutRule,$(lib),$(LIBODIR)))) + +$(foreach image,$(GEN_IMAGES),$(eval $(call ShortcutRule,$(image),$(IMAGEODIR)))) + +$(foreach bin,$(GEN_BINS),$(eval $(call ShortcutRule,$(bin),$(BINODIR)))) + +$(foreach lib,$(GEN_LIBS),$(eval $(call MakeLibrary,$(basename $(lib))))) + +$(foreach image,$(GEN_IMAGES),$(eval $(call MakeImage,$(basename $(image))))) + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include -I $(PDIR)include/$(TARGET) -I $(PDIR)driver_lib/include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile diff --git a/Sming/third-party/ESP8266_NONOS_SDK/README.md b/Sming/third-party/ESP8266_NONOS_SDK/README.md new file mode 100644 index 0000000000..eef92c6302 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/README.md @@ -0,0 +1,3 @@ +# ESP8266_NONOS_SDK + +All documentations @ http://espressif.com/en/support/download/documents?keys=&field_type_tid%5B%5D=14 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/VERSION b/Sming/third-party/ESP8266_NONOS_SDK/VERSION new file mode 100644 index 0000000000..f08c7393ed --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/VERSION @@ -0,0 +1,23 @@ +gwen: + at : 9422289 + crypto : ce90efd + espnow : ce90efd + json : ce90efd + main : 9422289 + mesh : b19a6f7 + net80211 : deb1901 + pp : deb1901 + smartconfig : b19a6f7 + ssl : b19a6f7 + upgrade : b19a6f7 + wpa : deb1901 + wpa2 : b19a6f7 + wps : b19a6f7 + +phy: + phy : 1136 + +gitlab: + driver : 68fc7b06 + lwip : 110cb9d7 + mbedtls : 8e8090b6 \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user1.2048.new.5.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user1.2048.new.5.bin new file mode 100644 index 0000000000000000000000000000000000000000..1cb68279fe2847e51e6267335647996ef841e519 GIT binary patch literal 427060 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 z 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

?Sj*^r9atke$9#wXqR3!b$=AL$h*L3rZ_iQ||d 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 X6<((x70CYO2ive*!<1`xM~?hIe7+Yq literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user2.2048.new.5.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/1024+1024/user2.2048.new.5.bin new file mode 100644 index 0000000000000000000000000000000000000000..73ea5e49cfb377de899b0268e0f1e14614a32a51 GIT binary patch literal 427060 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%0AC3cG7sO(9VceyO3G}p_r0CmZQ zUp1V1mI($h&}atfyc3V+U~ZAm=}XW=m8^*D>XrOEAjTnBU+msnQ%*yJ%Vr;VVE)_> zXH9iv9U_zHrUS0)2-YN-5Iwo7&Yeh4Z;)gt>C2`oH!5wAU(qk7Ww1rp)u9X$TDiu$ zF>YW}tq%bEpBj+_AufEEg7_j{OPu5KvHm>c^h|F0JFHk1cU_6M8e<3pQhF?A&#{s& zkJhnYIYg?N15W{c@1TyrUekNR_~QxYgrVm^d$R7>?Rhy0E7J2R!r2PQt=Y=yYsWw{ zITfmCE>9`3u}X#+$KI>7xqY@-_f;2DDZdyD1owHwH$-+lA~~E9>$qhH4oSj-IQ#7! zqTL`u!^tH>QLkjmlSl9@`9E@35^4^Gx^?Q_dyoFS;FrmNcesYu}V^wz<0_1!{|>Y+Jf%i`JG_ z7Lw~G0_Xq!oI$ev-+IM3bFQE3bAR5CJ7^i4k5UqsRoBK@ebGOqJcu`|Ba#3zAB?N$ z-an#B*j_KZ2VY7hG#py&xI6euo=;HKgY_5wW88XeP4)rIPfNN2CTZ*UYqFomFJji8 zq4+`mw7`yh5Mx*%NpAR>%l20orJxw0IMDWyLhV=M`k6q9{+ z%=))A7{QiD6$PJ+@hcJn-6%nWVSEJfX;6i)OF@yPK>wZG$2HT|2QhOhtHO$kUFfP` zQSkm4TxBZ~taIQ^n~Rm@d3Ov+GAd{$%j6A(wS{Ns=qtjMf?f$da`C~g94(N8>`I-V z{@cyCXX0hBcN2FWbwyya|41%H=WTw#Q9XWUqW+ZpoS1@FCZ0pb-toiTpWGa3)@a@I@(C=U1zUKUKJ&(=w&2c7~2{3Mh54QOfC@01t}mksDs$@%6R2~;^;14 zveJCZhSzfry?)ub%f=RdK3dtW0ElmJsJ+e55gdGSildC!AMVW_9ffsEm7j^EFMZ+b z<9($3Al6FnYvV^`P>cyk3>aKr9dDJr0wT;(4vV1Fi%Jp@hgi6*IdcZd>nC!`3jb%k z;`7mhCoc!^Ox6BzWPE8;AcPfkP|(y_Ka?J%&))ydJwKBmTrE_ z(Bo1!w;JRNG`02XNg!^HrS>fgP-NaTcDuB1-j=QSa^Hc1BZ_X94*zz$qU6tLu3y=y zWVL%#JVmWNKqAd7Z&`S=(Q7um(J=)@dw7Z%Ei4->8+Pby=6d$|4(3Tt_c#kjMZ*}> zpg>z^-cDze;vuL8m7`II&R^K0I>L4;50?5Vx*JaGHsiiFOSk;QEx%9VDFx~RVN%xe zmX#fBy}5~feut`kLzv6p@yP12{Xe_PYHiV-Fqa!bl){UPUo_UfXz`j1&+lNHnD&)n z?(>*Hh*q=ZO}|s-S}QG0@LRZaGL< z;j=VS8MOWeE2!VbN1yCq)TvY`MOS&BhSeW^50;T^YU9>7Oc`Q~eeR0YqCGuux2<90 z1F#xcpSgfI#J6F<%ua<~_A|PPu&h(>@w3$f_eTYU!biqW-QWAdh1YqeZ!WT`TdK$V zZbl*KoqQI6|W~;zGa7COQ#eJZ3 z<8k-uU1^qz8wc{cEOJCDn7jiLcHzWamK?iIs+naife^EnZi_^Ew_GZ67N?tJ~jO!mVvQD z4V)kaF}lecv*l;73ru3YC)Qq~=Uv$K@0)EH@GizF+Jw40lu2#P&Fd-|*=?XjlS4D5 z=cmLV7>?J(_x_r;^jIoI#1yq&ly)7uwr$V2)40F!yOQMxqT4dvafbQ_R{7j+L+8{t znFZec(~(XQ*b^lvv@e)^sGhYatZ`}F%heq z-);B1vvhf^kXd>(y7y_MeD{6_Uqi~Gyx!+%zB$YF>)n=nKaqeij=lQAeJ*3K9CC~dmW#JRGF4U!5;eE*S7}I_~*#Ka*AtL#~+C zJLPOZq6@Evxu%rQ?{PyBTJD6EQxV@yUprxoigb6Atxo>-F4QouHHF`H54g|#Hs zSK7pMz9L;%>}As^ME{qjMe?vGn3*l4by(Jhcl?L)o4J{osPN}gl&pa)9g52u+vw}o z+dJ5_P!RQ44WNYGW%iEJw7zd7kxi@k%lYEZ6ezEE8smj1>6dyxp*C(VV7_ZAt+?}A zdPceb@EGSbbsR>K8!mMC8aFbn`|t?&%T(s@RjxgOKm0w%@WSE$RK9WrTYe!W>J6^> zO74Syd+mu;`L#>Jl{5bB)7#BjGMQy|^$7|6?FgElEMZ#HDX%@1cPPB+%EnbUcdM0* zS`|`jhz(XIb@-%SwBVBz(b2AN{v*BiK3T?o%YvlLwJ#cQ7N?S4e7>W6QC_z>x6{#< z%s0fdF02S$sZSf5^g_~G-PO4-?0umhFjvt#I~vGBBTcE!>h;6sjwK_QXIaGH(0rp< zZAYQN&E_HA*t(W#UZLb3ynxn)91O%SAz6nFgpG535B+EZ&0_j~M>h8p9zdfnIc3Nb(^O)L79(i?ZHy%^TsfU9xaGW4$W^xfL=G9WQ*OPze2J2~_oD&u1G@$5lFe8vugt<) znx1vuMp**k%6hg_*h!%n94>*WJES)RpH*_xK49#L-42D^-@oAj=yDBBCzG4-vbUp4 zgawpZfb);@8Rwc10iqh9Hv0QSLio(8rOiz1?UK))Sf9VPE?jxb`)vKArRrNHb|%(1 zyYmf_iRO8{Jym>1607GSVnb+1%{sn)pgOrFi+0=70?$oO zi%e}dwk$RM=7t`r(++697v9aZ#=u&eD-@ydW8MOx=!#Tvbv#oQ7|;rb z4L|i6}_*! z+R2zx>P!sqy0LJW>RDv%2!HzTwKFu1LR|vNq(G%Z2nImcK@KDCG@E!#aU<--7DSaO zTFf*^gPj`QMV%GK94uF@E}5+@6_V9nO6{gJ3v&>&DVo*DcS68sB!1INO@IpAGanv> z9XSd&rT0>7jjYoltej$&$b`lEBTQi;4V*m8HIVw4*^Iy|eaUK3 zq2?8us0|U96+V%1Ehv;wvGJXVv>UMF^pt?aBe<)C8g=hw=qcy3kLtfKAj>H!!jw|U?bB)<0zb`b%JT73=e1JB;T<0|+VV9|sw{Vfcg&b( zc_3Ul*W8)xi?Ah`1#Gy5>H9fqf>Mm#fQ1ckp^zO!EBxV?3NMttx-ZUk%@DiN26?ON zE~_w|@-`UYjxWy%Q?fRZb*Xk?4(ygA-w4%d!(D0Ts%H#+XC3+GTy?tEVcW~5d6RVu zD!BAz6d@~l_m!8s!ygtZY^&i~(rY$MXVkx;y(T4ggBLLo8lPKbW3s3)&T6KAO--r` z=f~7-v?VM2;oqpL3Xp!J?24snJ08gLnYp}ge&MaH4S%@%rb}-~ls{Zqa<@0xpnZy+ z2JHdL#Ka(X##`D7+JCqGcXhSxmnm2~YO}pHx+mYL+v1%u6fz7Rkjs+4XbHJkk~Z(s zcRuCU={s~2=uybG_thBkHHr0_Xi}A3s4?&kb>Tn8@GieY$4>QW^?ofIA<=8w3f4Bo zuYG9yFX|@Wgg_xKWnOc;lFPI?V)n#@8Z3pEDIBdFANM|`vpMeLi_TI%o*brODyTi* zFm1I4o|7#hc5h%F$?o0D*yGRsHHR7wf1X+dqMNL9S34_LES>it3Vu{(tn_y!?`T?W zX%AN({W-(lP5iX$n9{qixES?bIQLU{^Q$b;(VRe))?kK&xd9!t2cNn|) zu?>HGF;t!Ft4@EtXew{E51VJa}!KEP3T$7`$)To?4a9{cM4ls;<8iW2aVz z)G9`;_N(>XYBJ)`H=5hxy=qPKquU>wkF5sT0iQwn6V$r4ZGH2D^xzIdq<9AQ7 za(*fLi0^BcSU?WN@D3%&ncj`w%g`!YR^(%&CEU2to;)|xw~JcqgEr2R#2c5s{wX2Z zAgc9V%xuIgQ4;Se+`ceJsL?rM&&T$@O@T`E{X^0^(3qJP?oN$(lTuJ>+)6dZ5#xnV zw^Ai4m67jcWXYJ7xg9zXqsVR)ReFTIN1FBI3a#+A6gh5N-TU;I&4F#&`4l_F7unJ> z=_6aT30o9opf>CBJbt*r(g)8!HX`2;C73w}TZ_P>YEJcY%C@@cDbb{~#|GwSzJ#E# z)jysWtzT~+g1}s6C%gQ;FSLtodqqm=rc?r@0jELxYvo@2(Ed=ka^b&n9io|I6K`ZN z-V`;KRQb~F$XJ~po_X)8y<#<5((9$1Dc(4x?WI6pKvcaj26mtO5~^CKbj(&lM*i`_ zHUMxoWLH91u0v(dphj0}i{TqAj+nxis8#?3#N}2LJtSFN;T_LXZpht0T@CN(J=0VH z(E$q$LVD{1MD}XA6J)_+T|Qp9nd;pO*S4i~wRBOz#eK}iY8~F$N0h7K9Ns;JQKwTE5nJ{j^+IXwbsnK=g|)BbDPOXo&7s|^ zb2wl@D5$L}fJ)K4Aq?8>ov(7wS2OdKB>8u~rf~}2T@=UswQ>y^(N-tfaV&5O{zOX4-CZ<1E~xbgq>2nc zmQz`I*AdlDioYKc0q}R3rp4HDZjI8bQ3)E24_&`bE+!Yqy!jNNU$M57tSotL|5V-k zz!*5YnFFD>?Twm0k1rM&b+qJ+X}aS^Sp>b^Qa5$em9e}F?Y||I5%#2ZEX!h0)B=C8 zzGF5;g~Fk`)WTFXpGg^D;VFk{7s-{1c3TirFf)=T4= zfNoW-lGNXh=f_f(L-faU!W1>aAoNFbJJS~!C+uVEI7_MjEVVpF;-ESHP4u+>P9aq- zs+DfFijOEpk!*0@SS|}b5PxRoVE68h(}S_wQps-pnOb!(q_q5)qp`gnsdWHPZQUc) zWf3`g3k|jKIU-vD6YClB@1{SGv`rDUdN>HFtf~@!YGd z>apjqDv=Ss;pTrK0<&mj(Q9vH{JT4f^F}4Ya<&hwrS|g5 zT)Mvq6&|q+%G8UNi0+g=6q{ax>TqFM{vuArH54hF&H$l<5urdcEq6@XidV|MBOR?p zglW1#D==xGSORLX#nCd*>xAwLO`7;UwBj)aFh(2Q$WP(^M)SN?^e|ip(t*ZGtXNeI zR_IS=6-WoPr@#~1(ktc6l`MVwTDTJ?V^fL6fIdfj3q`U8b}(We&b6M}6^ReiiYKl~ zb?u4Pq0eBzdQyf(5O>{6AIZi&tx41XpYDfxVKRy)gPV`?@`+xLa#_U!Pj2I*a3M6A z9zrG1%xvqYpA~M0Q7ScH>aD}SDFIU<`PYKq_fnnKz$sgSv!aY%R8j9~YV0kf12wkn zjhn-I;u888b}K*qKje+X{X7wV2K)utrl7hpJ|a*rk0BB50aT*UihyU!+GtY8Q~fI< zgILB`|MQu@$Dn1j)FQsCSuhxix5pd|I;n%p50*Bu2Q?ewW+QyPe0)pCKe&yMZ-HM+ z>GT!9k;EE9ec`J7Q-v*9R2aj_$hwUJiH&KByjzZA#N3=-n{HSlhD_Gqe3kv8WE1G! zWCI|WJETN9K@6o!4;*jGI{YM4WT75P*J~;@Qf?lIXZF*GuI1@9q`MV9NwiXp7bM>b zP5qKpa~3S={T2PAFvv{WZ#EoYi6*EO+4%YffsJAlmWhHGwaP1s@g9!^(L_hSqYZhEck>xbF!O4eiPSWO8G?D9W0JKBF6-tiFScPF}Lg!MzN=fk_F0rEq1qqMPpXzl#49Gi|=napkAP24HC zkYP^etGN^AY&?>2jAra3_B6pU3N8r~3c{W&l;{{eX?2MO#X_uubwjO9uSF@5(lpiO z8=ZR4VF)4_ph1CKs4aDRnsK|b=RM>LNl*Ezg-EZpn<}H{eR5ro;C7D+&3b-mwPo@ct;wr&$NCi4WIx}!%Wp7 z#Ei|vsf;WmAtW=etWze<5lZ)Bu5PEbr3ffzwRN?I`qNcws+BN!EqzrfhltPhMhoFl z?isxpzRJzlL*UtjEndH-%hz_=*OlH}7hb!eeQ1Mm!!4S^beLNG4Hi7D1F`4_PVZS$ zt%Lsf{F{+SWwaZsPM53^b`3(DDSjn#kh^F^6BbY>^Ex+G{;&R2YTwP2*p=+Ir|x)_ zKn+mDznLvoCv(sJ+uN1C@>v4bgphUw+VsA1j54{PfItm_*3rD7ncA=m>IP$;)e%HO zW>!aavgTC){8PIMpm~I{!-hbPv+xy_Qxb0*f$ntum zbbd`2k~iaK96yOjzREM#{u@9F^nlRgL$@Ql^N9IEHWyH_@KRV$=IvcUZ2vzvThtIG z7~**8)l>cAIrv#;T0Z@gQ#vl0TB%SIKY^H!o_4O$FbvrTzbLm*pugPl#QBK38 zvYj|t`P5|m+>|eO(#Xua33d%YvLc|9MKB(6a>Zag{XJOnG$HLRT}ZYVxv7{qfqB;ib1I zYSbjUyK+#zivep!CVnKsdT8l%SNH>(5}$o5`zrC`M~r6He_YVfHlDsD$o(EQsYayi zOF%rhAU@lJ<6lLNpYDL?_p+4z<(Tz7oH>Fs|B9U9yg+4P6=HB7tsxs>pfrBh;zh6k zu=;`Od2C5z$4%F%Eg`%9>U4kgjDhMj;pJwOBKfy>g7zj3leCoTLHlD4$;s?sAy zImo&x@1ZR9C5d_haZCkOV+fZjSz%Kx@j85*XyeNNNE` zKirKx7*t2Z;-)7aN$zobXvV|97ncbEj5RIHK{ChN@etE{pBUvrtY_9u2aHv86A+)7 zViQwrWQq-;1ViU@-Ni~VArY==mvdcrv8uhTptj9GJk`bOpmv@7MH6w4bSD@?#T2Y< z`?Tvq#qfa}L&0xh!f#d@yNj8H3vew0qnP5D?qWr4uE87)WvRV>JwfX!j;)1-XeXVu z(*oB|ah$B?Xu}-^KiMhkIyx5+H(oHv-=p^JB)%5Bv%M2Y3($n3iJiTeC9qY+`USm{ z{zIA0h5qapI5-NjlLiRY zO&`pzGS^$H5^75dNJ8F&hGnH4g(esmSsk%_&9`(E#v%5qvjEyU;yjw@`fUGHqgbd! z)zG!R0#`|aSg2~=v+gGwU`unsKS>U#ad8mpU?BrclG>(q@<9!(YD81SuoS|ZLJVl$ zLbjujf=P{xPa*9s)N27cbF%S>$3$Y3gkU^kM?yik=?)lK^;7D{)!kyuDf23p42<$g*Zf{NW{#3YdQ>XOxR z7Z%TvO9NKJIjeElYSNySlRj+fi|T;;BI;RI`XzRu59JY)Q~2at*}m?Wn3~x3t%l}G zGR}O3cHhYMktO#mg?NRSu&$mSE4MmE&qg*ibs4q<${luBXmJv(9e|Z;zm+>iX$~;0 z)zp@KZtk*@JB$n)syMEM{%aH+VF?Wa7u2ph#&H0dn9@esg`;cL^ zo}Kmrt@=zFW4NAVo5{JWWYfDj^lZWb)D6JIEP?=lWI`5sZEUP)<=Cj=Jf>BoSkr<1 zh{^IKAVOuIWnJbWbfMdmNcx6mE5m#k^r*O-Ud`w#Uhu#wmwRIG$3ANUDjTR+W^Lu> z)%s<0(;+mW@U+Bx;yFeqzx@Q>9z)&^G+Y*y3wjrhW^UsIjdK^Pd>2)ta7@v%V3gb; z#yPjC){pYm_(I<(rj31M=DoG$m))MYrE~HHD~cMhO1C44RlmEW_iX^#>>cQ~CceaY ztqIN({YAVd0i)RF$wZZ2?%lVMOZMbJru98(HB-b=qZPtr65gjn9+74JnSK9JK2yRyF#~$|g3d&0noN{gKm*9Km zpLC#G^?-&)QXnpvFIKCLX)50sb*HGKmbiba_Iflvqt;h*D|aW&&!&NuvU0Q|MeR>j z);IpH&Hqz%#5iJpX_cO~1l-pbLUBSdnB?nd&Jk7hH$=3@YzpLa%a#jna9 zd?w=+j|k(l?3>v*)CvG-MW8%CLPIkZ$0?<^`qusg&FWa6IoEGbirxU2>V_m=buPD$ z^0R3jL3vx0rtv)8QZ*Vf&ts{X@FvV7Dj@`$h$9TXaxQuVVy_PvJs?6;Sp{orUX4lv ztLWNQ+gBND3%A4W)jSslW+3b$Y;fji;9QyBZBNQ)>WSX5Tk0POv1#4GW^jcNJkr2- zQVaH!D!TIR%X~u$%;|_rWtE#Aa7=a;_7DWuK4>5Y#U-S~2qD8TQ`XUh0xz-j29RC? zt@K<*6NHH%6+O*`oY@TnQ_u9hR|B}O+J4vg_W2%FQWY?BxySmPushrT8O{Q#1xg$i>){%nbZF=z3nS(%=U zeYB3u!hk&`aYZ@zCwrC0o2))i=C{XpL@PtlDqpmwJ6eq%>_ZIA22w=}pNIunyJvm# zll0&lvKtJ1ps8SRg8^r83bgwdbt_+Eik_z6xCuP1jSZBKMW&TiyZbi+t@2NCO&)kv zwPhXl_zLL&{Qy|2%X}(}^ zgP-YhAnC5Hw4)&<-Ig91{u^Br*^OD41$bO}m&~_addvtJd3q1A9I$FQWB6pXvkWGA z*%=a2s2PR61KtkG*bdIGCB7a?vwbG<^#o;$e)Dy^ewJ;0^8@tYU51FaWYX7z*Uikz znjii!4K|F#&kYQsCq#SdDt+Y~?U;U`A+@y#C=_Y^W!N0tQz|#RxAJC{&z$8aqZzWt zcT>t?O4UJW7>wplBefG^k8w!;gk019{rcuN=|Pgt-6q7L|9@NI2U`ry>uJm(f=|lZ*28>0h%K&9{^1*RK82*^ zQ?X-uFb_Gvw2;TX#5(R>K8R3xJfTC!S6Lr2MpC{`HD(r^QL(0D zii=9~9W08@w0wE(7~l{LjsKR+B_&4Buk6}vrAajje`%#J-5xhh`6|hn9YF2yj36um=6PqKO^pw^a@4Q2=?7FM}<^^i- zyN40bx0))U9;GVhj2Ee>{#zI5aQG!O^C_z6s`Qi=H);Zp1y(_LUZ4wkQ+(c3H?!F9 zH6$%@i;D|iy{?9N`BZmL6Zg4pQd;A7X6Qp7of6<{Se#`#g=an9Q{Y$g%_8 z^u7%iJacVM_`^G>8f6iXwsZ^Bt5kkwaR*x5<`)+er4ZvobT)=hg%;S(Gie#;=3p4V zli)rFxdoBU*k|X>DHMGf)EFBz^AkV83NKAJBZpmq&Tx=v;gdSXbvR>k@C)+VQpnBB`|uCnecCIS*~#>tJ(N+ zihk8-a&WR zQyHGFoO%_ny3sF-_Y5vE;yt~eUPFz>)8NUMS6$Ct=>6$9-Svs}cb|YC^E}l**xyq? zVB2$*6Xq8__%Je)kZ=)8MIz*}wvhYzjgx%}hK%OWQg!;n+dbvSeL&NM~JOJeo~lE`a=I&HIy7_Oc9C9T+OHRAps6!OTt2 zuO=eQ;P}K8IT0Jze@ku#=vuBC7)V}V)0=)#x5|`#9B!*M0KprZiKe!GM`F)(#;X-a ztwb6-``6494->zK)^Yw1T(joVZNJ?(JRD1DlTY8IxveR?`*vz}n0_D=w;p5A9nEb9 zq|1|I_fH&yopG1bV#%608|5@tMGo2=T9YO({X+8hJn~ABv|7a=vXEZp5O;;>k4ZZM zx7+A2LTn915L~Fr@aTWB_3Z7pUw`J^k!Pw2u1vODvOb-O=91X~kvord3_c2+HRRU; zXYE4cDbGa!Yw#xJ_sQ&LCYBasDeyxVWdR6&R#tE>ALq~yX8n-L(emqSC|iqo?kBDx z2Oj^4R%&!zh4p-u${QR4PxA%`S0-eX0Db7jB17yWC^O{B2~u(x8OqT?@5`HIS+J=;p>Gf|W;iW!cgy-^BKESNJOk&~Lc zT4Lk)(UGCcrCIRq7Vk*+z5l1m=S|vQb3^e?1NTh)qRrfaIBgtP8`r6#c80kNCg`qd z0Ie{0zkjguCkE#qxMzT$#qBeeu+XTvIYyi}QsA zGWyNBm7TVJUsve?w*S^v1$BTePSPDP3cwh}gH_UZTbCZ?(PPHMf`YDp6!CsRmIUL^He{j>gUv#FlX`h_Jw5C$Lhw6yZbc1p3 zG(zIzb|Nc1+b~pc=nHcKa&~&@bUDA~m)H7UBv5O@%ip&=aIFi*T-7hGsdr1x|AtXeUshxY1ABHg_P*tcOVRfM!HwrG$5p8pfLN~#C1_3a>v zAUMqWYw9P+S0w(Ql#VG-(2ZqDtvt5%1MHKbMJRF`^`kl(u*(kST7j%4r{igr2w!$l z1~E8T+^*q!rmUi|{~YWpTJ`s<7Ow@a4gTfPR)zu!1nsm|8Czh>FCgF&Fhl_)c)$}i z?18;(S>r0th5bjj!Gyy&0H34FtmuCPfdp)?k*Z`2z%bsdT5)YJ&_~(LDDz%&O;*;1 zi*hL@MHvXA0^ftz;G@8QgP&LgvyQi_M5{)d3|p>C?RIG(9Y(}38v|jF$Y3r-Rtdov zaltL`q9XF15FE z*V@aS5CF?`dvl8s?l`4nPUYQFk(zSH>o)xM(!po%;(niS9!h~-zj9G7`c9Eqo5xu)5+Ddx%lz9iKjz&=(Mj( z<`4iIndiuU2+Uf(QZ(suv-{WOGc8vnXZF|USg{|;1X%f6z0NFDM=`7+`-5={48o-b zn?lb7yc)9>-j20WCi0e`*Zkne2N4Qh6Bq*=mnOG6iujep2#?J5E$|cB&Nac4X!6FUBAZ&&;E%$-zuEfVg@v*&AF>@NIn~+2_#9 z$OYJHa3ugp&}(eC4#It8o&cg0&HvE<$!8aSFKKb}Ow0enIW2E9X$0Vt^6NJfFl`9AgTv0w_wp8jc7nuKFQQ6xZlzQh_U;r7X%HiY`yy zi{Jxt?-47)NSp{2vgCwW2F1T79$|yK$A+<~$Jm4;V>1z3!f1hysL4r3I&Q|FEEwvq zq$6xT6Ly5bj`t9_m6`S%mX`HfGCX2%J)J?uhm8GNJo7l7d43&}o6MW!XP#zIKiv8cbY~a+cd}P-DW(sGuj?W?K|wenSqE^*Z|Qz= z35v80p)c*|M;rb~+(h<;3Y4-zB*|3|=|{_lazA=My544=leGDj)!N3aAKL6tkXFNF zyorqCyT_cVC5`{c$xWU62Zb{>H}&un$IuvOYJFpsaph}hx9W`C>XwfrwECZt6*+go zgY@$gtp?7u;=kMdp=A9C7wx0}KrT}MM>1>$elXhHiNB#3vQE%;qJv$iI8|^F5Q}39 zhobO(DWCbGJ3%&V*>3u;hdN?&jV(t=vAz3Q)_Kz@TJuV&t}*L)IJ`Lg(W{CxN?oIk zbc?4;C%Sc$mUQc;x$UG|Hy!@NF?8jqRAT(ny)^!5L}OVIkQF>duP1Fp$$6ygTTkN1 z`}9X-J`qKPyk-2Mt&B%|bla(27xte~oF~;HV`vezlOi$BS#t(+;H4qC#kq}>8NRt5 z)x{B%?m-Bg&HVcOc?^SmE_HfVQC)LQzTUd?UntsRV;~!ryA6muVL60QFRM_cTt#_h z%96FcG7dq1E#HoST)?#P?MQ@!T@M)pX=T(5qd^mhM~=E2SSuz^(Zn-M%@kbz^$5|k zDa5uaUvK#fe5x&h8Jt{y^2-sV8smTvg44YX1 z;bCN?(i@F{HqUvJYH*}71X5o3`3OY5g2p#4+RU3){>#fK+O+<~vL|P;p7_$BWG+U^ zA3kIK4AZ3XEjGaD;9E>odije<{)}sUL1IK|@k76I~-6<+?N z;mu$|B@)+pVpA;`C?XZ~XJVzVf%s$4v01&XF z1ud_Szr==Y{#8#J(*CSFi~iudFItRkO_DE}J6OsD&Cn^O)`o zVi08POj+%PDE=?(rpM?tU$;`c^{;?W% zorCmTneTrm+4kC%n6Y8>m%CU3Kfh|n!$WjQOOmuuJ^{^+e($5b19@*bw4T|qgPO}l z)teUaA66nw8-8I32b63Zi|F+_<3%{QS^bf7uH&2ccIDDtkK4@s!+gID(!~mTn>>1k zeqpN}%H7sHK%5_8vyN{@LVcuT=L<;JmhMkYM9I;LeFJ=&6!^CbuU(XyPsL*4|uK8>X=q2vz zp=b5;Wk4lQI`hTTUy*h3qjV9J)@*kErtc-s z(r+sMBXwd~wZBl%{#pU@V#?{-o&M&v2C9DjzMY81C)p(MPVCG^Bu6u4sHH6BltpKy z7n4DiAM?4i$ljTKq@rCm*ES=N<3(fhqcrgmb*_&%4IZ-6BDwwtAp9`)br3ncq@VCk zM(W+39gzU<#87rVqdf@#n-3D+DE3_Co(1SM?IXY3J(sv%gfT@V-gNgp?1w8&OVT@( z=I1wb%+8OoSPQUmGmVf3pC^0hBGcs~LFy$&RC!0CzZgi?V(>TgS$R#wKwCxhsPfCZ zV6e~C%ec!iM5>WjLw-yqig&i+QBROZ<+B%=5Mu8Vi>abv#2NCa!2$KY z<(~Jr&gTI7xJlg-Lo^B;Kf;J0R0mG=LDRS>cc8{Lbz58OvLaI;J>*T#GOQ482 z>SB_ni@^{eU+4|w=1iJ|SiqE)uPqGym%1I)kuRp=>3+Do3PXCfG{B}V!*c_2t3HEEP1ghr05Vmwsu>3>FSmdzCY zBkiOMe*oyh+!2a=wICB1uR8jo;#LL46zDvAhgdyZ%Eq=_gHNc+lO#DS^!j=Ei_Uzp z&xrIkwaen#wzUo$D=Fu2`#brpKGo?~Zk-S`vpD=6n*> zN|SzQPy8OXgLT92(Uk$>^6xc%idZ}Z1n{1?I{QsP7IhvnKSKYO3=MzC;ylDYBD_6? z-WK_7i~KgwkCWd;Fs_p8MQa@WC^>Mv#=-|_xRqBUmLkq~$gqGeIiXU2TJcw@{F@*@ z``#1p0(~|g3u_1MBFiCP&j*8Iu#>(O%NO>ebS74Fd79_C8B9b^(xv0FVrf^9~i)L%PN)3WhMLg{Kt%MRObq zvhtu@A5*kAh;m>oeC|33j^Xb!TqS>`Ts63+nfFX#JX86%OWdAhyQ24FX@^&h5frRb z*cHOtRkSlQ%3RB<5`QR#oi7|(N9RP2W#RghxLyIsLg7%kS=loDE`JC|#Y5$8z`v&Z ztjTumqqOgE8vPj=+8y2KuMliztW)P12{Bg7W08HILxNFORN1;PR(JGn` zen2OZS3wImu?C&rR@VDJip**P?W?*heaJ&+&Hf2^_aEpJh?_ zZ;*djc=#rqG_`^o!@qHvr9KR_MMWKR$9_W0}^oIXas zKu+W0oAB#BdUvF;FiKdDz#50vfU1Vvs}+FkCgg(O)s;QtdSgC{GzR2@?Ng!+TY0o+ zfE?5sbu6kin1A$~$yw+8Dy@mjQgI3uGreYRZBm|+M}kZbDxlDdN9E=qm949HGY!MK zL&3JN@e7ud7|G=|Eq=Prq-0HMQlXwm$PWcpH56{5C&irzOQZqJSPZlgo z_AYt%u#eE|$dGmMPWrF?bGtr|$Qd^ZP}BrHCFs~kjU=<;Tu&BD;R$@;qP&V8p_h|q zuv9;zv;VdKi>`B#JvZ4NdCx&X0N&OQ$R9Rf7d$%MMNC$~0gq|e6VG@I4pe4|>+wKL z0?_)0DlNw~tGK&VLeRVPl{<%(YC-8?lqx7_@E*V%&nUfO?^6+FO*3aU06jWll)7D+ zhXnibRr~9vPknwWQi%o9+XnT6TCQz21%+xt%ckxKclW0|Ozc>_3tDCu-`itSsOPW~3=ht?{{eCv6@@ZOldp$js4AX8?Yssa`ca*=s zjXzD6UG7;xx{dZ!mf4(V-RG}Q7v>wkY6eT8h8`d#9&5$^JrC-)lP)a_(BX{seJbHDzkgW9Ii!g+rKrh z@M%fCL#i+J_Fbt||I25;wemm1ecPm=&B{vc=d42wsOd+ajMZQ+j!SA_>Zf|B5;U}E{vz>qWpLV6tV6ePp zzyx8M5Z=+7qKRzB;d!*pDyTycS+gE)Gs1klEjKGT_c`7gjUjqm zDk_t%ucgdwg}oAUnr6cG{;@peNz~p#Hy0slX_jQ}IU=NNwt2grC7_DJftr2eO_ zue`!P0pyzL&vO5b7F8OrN)7)6B7yPgRjJ%6W#l_n9T(sK*Bs6E4pq zA+dj)Z63D5ML3Q6sbSe!?%5o^e~c4RnI`vy_*`!G<}v>L<(Zf0n@M*V7SrYtty z9UMP!sPm7am1o}n8SC_y(kNyqdN|Olj#5hYGsuNuOBIY``Mz%~zVJ8#P~D}n>IGuc%+>^-P6S<#Vj?K{T;WEwn2vFbb7w z@V#XgkV_KyQte0gN8=0fmO4r`9i=ct)55Vd!DFU|EQo~VJ;}rG$1~wk#*@TbligM` z@${&!c~v8k$@Z$QUjOnvzPSGm08$Hrz~vYrmHereKQ&@dOJ5;NY54uiUTc!un(VWh z-MyE6hcEj)W{6EIf7?}?Zh@C9LAo?|Ot2>X-VTOyf!xAQ>o|krul@z9&;r2B`4_-h zeoPK%H&t!g3n7^M+Qj!S7p>FsDf;i^ zgkYT}lzNHNtklyt2OeXN`+()1WAkHqYl8UPz4W`}sxhXYNGEY);&UtM$K;*i#;saB zh<=+~;I-W?j&bjDW~DQk@6XQMCA>X{ zevRB^gN(@cq_wCe=Pn103V!>@QEULSQosbfeURQu4&+1DPC&CW_tSgGZ&FA>+(lLG z_gWL^N+Jq6$Q9XNjf$mSGRmbM@wqK@EotYa&quf1pXqko+W)V7WI>A0{f53rZa*?? ztt=A3+}2oce+7RATxD;|w+tUtcutNAyO5@-VwLrX=}m0;KUcTrL$Ez>VppKL$ z_*JAazoTyK6i+XFTEPu}jkyet ziqCDJ6UplxvDr`IR}&pae)WAUQEjJX-^A5Tx`Lw>r#u%L&nO9yJNKyuRl3iX9AYV5 z_5wQ7nu{17;-CfztU74xhc44h=?!HdoZDS9w%5VsG~4J7uIRsG_?h$Ag2THmyZ*f$ zA;xtk?UsuwZ;kZ0c|615t0R`~Ta6#9*_xPq2FUsjy(`CG&@tN5>Q z1Y)~y%&gFP2=XR^C4jKtEzYvSM1oXYlDUgN zM)@iT+_+=sRlL4Nk6M)#&Vto!R#sZ?F{ZL-!~xSJsWUl()0G2PS$*s05>*a;OANXY zN*1xi=n9U((0MCAKvoppN*+a|_^s8DeKj@~Lr1HO5~Kyj$?^?(aPl3g=%p2t#uHgq zC7L&}3lWp0_36c|;mRG%mFW#vR_DE5mJ11B?x!iRi}@|nExHE2p#}m~Kb3B( zz}w;%1acc-RdCx)f!-!_{oLrfRdXRcGY$9Xx>!Z2k_aRkU&F1Wi9aPxOs^qE{_kM8 zZaIt`y~#Xm-A35&SrbB~j>tZ>$qER>A{Ur$69Yc9go5k6p{AtaRB7M|x4mZL=Lj}& zH`Ms-rh$h1z{*Z@TW)mQqq!aS4X6$1NtvH~W> zUm}0kptd7x2;=~`&ZHG)$gjD##-`eOv#txK!@rT{rg8 z>#Zf7q-34rhJM!m=v~%lt_eZ4(4e%rStZZsY|XQoT3#3roXcnIWIgab0lJ*5Y!;z% zVnglqzVCA3(0W9896g~sG|`K-H;$mYK`Gj!Ato~oRl3uF$UgY_-9E2!7W3 zukpOLo#5_#0X9`E-ONBo8#eMzNQEj~pCmxOI{- zUDxzjgZhGm^{|80kaf5+?#6YvN_?mr=6l$nNP1VSmZIprv6LJCo@5O!_BlwC1D>hF zo+QST*yEXU&NJ;81Ew0;;2qjYIucn>Xm_r>nsx)`u9Qdx5N2||N5ix%Z(lxai65{e z)R~g%4T*J}7)#HZ|IxEC?pP{Mz4Es}qZz=FGv_>}I{r4$@%sgfY2P{Hm!F+`ucYK| z(PQq4gY6G#W&6i>c)__%=MGtHUf#p8ahPB>0XaybCmu3+D=N>$_&_dDG!ntR(cPZ- zkcaE=nEjpvz##fOad2CrghmTuHU2tM@V3NQ&Bys>CajHO1})p^Lu9a#n*~;AH9|ew zKt^^Xe{am{7;RbP}c?;mUS-c$V_X?WEM<0-e!3; zlQ8WGQ0s*|P|<8kJ&Wqg zpjxd|Q3_R*K&fL$b{l+oXmj5uQir{!eTR~J6FzA?^)Hh8A7G<^u0Jldek1|Ik9!fZ z|9E@9)cQB+z}MWZ8X){t9#`8&Ilr2mQ5}@j$0X~#5$t)PUyD621}U4V_f8ZKX5~jc zFZI16KeXl7Qc(}|@q1}A8A5L0TXMcIDD@qb&#QJyMSqNZYmxfikiQk;p4TMj!QFQu zXdV|oCczn9@^#k=x7~0$p?);*q0ep%Y>`{?iPZX{)OK)p6`c2I@)oIYx72x>TXjMH ziSc_z+H;!w#d-3xw?`^^8Xf9NLVxy9a)6eAcufBfMy#IIuJ)#zV2y~< zGvSgzAMpXys2az22s-AF1uK&A80#`b*koUkoHYfXNHeEz<+DGyO21DA9Fg+fYOmFp zeRRBJHKc@s0+%aZEO4Si&xFNing=_=-ZQkf zZ;y>#Tex{A4b}bOn6}lq)<=;$&|8AFvb=64$a40ZR|^hF^i70T^jPBttnufpC_-kE zjcrH^QL{EsUw8U+ErxMI&N=7fO^><*EBBZ>=SA<_InV1gt?F@mm&tMg?wKp!0rBVh z9bVq_kULPe#w*iZ)%>ReaeddJ$&%g}eSb;iopmCu0 zj5gwCyF&U`f6KOj4r$S@U@x{yy91S3>y}bm?q)5ZgU}9z^roeSRECv`sHiEN|K~n~ zX6^s?{GR8zp6hzLIx^=z=iKl2_x|4Bm(O==5fp(~4G7r%ooG6wYlEu{^8Z}S9g583 zLn0tO9oXB2pdJhf>z&loVXp0!Nuua&=0@9|)XWw#o$e8)mNY~l7&n{|aRyi)dZ4GY zF`MvV_nL+7+KT1iD0cX@zg+I?a(8#Qz8?_qdGWJ0ne77i+MI+a_~iTIp{(-s zBOJrZq6Na}(ZQb+?jh=NIk(}eQzk0}l=QOb$Rj)lcGVX?LshTsq% zKNwwLUu<5USuJs!C&kh%*wHJNWx*+cMhKvMyX)S|X7mhQI|DYaywj_M-+M0t6NaX- z#q86C>>4L@I9~gdilti??5Nj1O%M`vpF1#Ty!s+KViN6$;t7>GGf@}RgVVE%wINvk zDXWL|%2%(dv{YMFN<$48`iYjXDcW$2dtE~gbmF<+i++7{>FfrVYea@~cqL!J>9;uB>w>;+ zO;dq-%~Z}DwR8#>@9R#qx#L;*qQYP3x>k3>8VMqXow778iTC6(Y%a0ovQ4?Ne1CHr z?~c_UaQ3_7+KugPo#SlJtIm2?fVc{R2Xi#IuDmzL2#Q zG8}Ku3NWmWSM!BYdiN@Q(OGI4RH*b6DuhD$U(@Xk3OObmcb#q|rVgC@1@6W^PmnKE zQP-xz=rzgzzCLQ{WG;aZX;_L;pssVpwz}fhBvVPCj8;9PNg#Cs3ll2XR^{`$2bEk8 zTxqVcxneBH!!@a*xviBcU%$@1d&e%lr zk;nGg&DpW6Kw1SRS$-o=jFgh6bA5b!Q|EY7Ayy%c@ky5<%sik^LN_qwpcA&>CX2Sc z(`#V8dd&a$elNh(Cg-PR69Lv*3fO}_*`&Cx-$bi@m_+#!@krh0Y!^Nt!rmIi=i-yC zvQH$<+jr2l%_aY)<-#XOXt`5!xIJA>?x4bOfTBp}bQ$<)uy`V+5&g?yJJ@M3^c#3o zf;H%=ijuC!NKD)d&STaw<#8;^!%^un2+gX%;T9;e<)6e#W3kFtzuYga`j+e+F`73Xk#ho~UYcs7%A=_A_#W zBEwb15)Z2g&!FZ=uP>bi3&JK==40gyAUddVA%TUQ_lyW1+M4Vh)|)>|&RG5G4an{PoXHngGEv@NwKk_do_T%soZ6k2VA1Gd z=Z{Ou(!BAXUwgl3i*H>$6_lpm2o^*ffiz}O0($sV5 z>GhIH0Os8V?-ffNIrYupWa;vQTA0Uwb_QLsb>@n!IF9}1&|vWJBsDxOIRHVCuQ$Qg zYhOYxeufheMc|!`8#88Q-+XRUQmMA*dV#~4EAM7Jr0Kn~q}drIdqXRBe8 z^DUMaRCk9YE86OjtBt`hML~0^Ayb2o=NIWy5s+G{Dib+RNwKG$yzxDj2ahV*_gd$P8$vp9FDt^b9@FIN%fLqbLFLS_A_E*=JYeU0+Z)q^4pj@ zc*b4yrXFaQmcujzS0CJpcdQJ5$}Q<^&qa+nqM@^*V*i1ThAxxWUhH-*QoDXnN_b^D zqygNQWHaq5NO-8(nL=8M21tNW&K?IL^!{5lEJSBM1b>w7c<5WHM@q30XerH?s4NmW zoIi`V3f0&foa8M1&CdKCKERJ3S=DkntlopCGI!>+RPnQWjzsUrfa#4N%Z>YBlX<9~ zi#MK=8@~o*Vz`q}b8=Jp&hz@db#(D&gWZMxNK&5Wl0&o%oKQJH1}!}6>$s+>BRODa z%^f;6W=#vXzG*9Cs%%R$x3(}`3L6}+ZMof(Hm~L}y(ctYBwH8UrsouZj{ynawiD!e zS7mVHW=Dm7Mg8U)Aam!FEtM#!E{|PPY1?zjGe=fYnc3*cm76Lz*51vN-L!O5Be%}A zVN6vC1XstRU6osETl4REcv+OHl5MAPyEycREu1PriFo6;nY=VY8?=+3i`_>KoKo$d z5b3}a!(GR*j+Av09i_~ljZTs12?7@(rE+s^^T*&C(Oh4Lrm7>+W6+dUdP4WYT~uLa z0R~tVh5g}L=2o-4mP@@ggKVaCJ@P_bci~2D=zTC15kfjaMz6AupUw^$g`5ymz|=bt+huYQZ1(>)jD6JTn8ys;O%aRZA_=!kZR55 zCQnGU6ga$p`nbITVvcBoZ(puiTV};cWS=7)C;IK(`$P9(R$Ufs(Nesz9&a4ZM4eu2 zp9$Eo%KrqcD@0xc{qZin;d4Sg8d+!z0i)`w9paH|w2R;=FQ9K8`8sO7Zf3+Zf zWl5FNmv(C%rcC$tIp)Ps4xD^OOMV}Mri3U5S;`s0e%=Y9psuq z=P+RF&`l=ocGiyJ;cnt4E5-jHv*vNCzd3I858ZdYrZ2irkrOVH58DN$)UUw{ct2RER_8EX}F{M|~Jv zRxZD9yXS%5R_*IPaKx{J-(;DU(`9O-4cRfSF!Pa*fU5-}QZjuINe;ckJXtr6zWYJm zyNFGfH7vGW?=*rlfc%m2S(5F}F$^Zv3qgmU!}qf=q&5>`pi}ns^gH@{$J1mVX9#eh zpojS74}-Z#=PWiktZ;9ERE; z0bAPqODVpzlJ7p!JtxNvJxV9YOQ$Y)DlT1Ks37xbm9~%I^{LsQK^5t1vf+3IBP)9M zfMQK{=~MvMq4Pv3r8{yho{Us1Fc#lwIz+fdMHjkaOm$;CO4=JYOp$;}6+u z+gNpZhNktM@!;BZmTbKP)**r#Br-z}wQ@zVg_33B2C1~=K$JMoUF_#M=(2KT8;Yyk zatI}EO}+ItE|pBB9d!3?rebbA$ojSPuA+EYBI@p9`;n2Hdm3If6&J=)!X6(PUy$<3 zt4aBkcYYHx_Zs5Mn?=6*P2Jt>S` zMKC*PZA#)Vv1&Q5mVuTDdz)IziSv3l080-Umuxvm308E7J`%90Y zs;a7R>RRna=pkVyS`vRIcYoykFWEOkd&VXdUtD#Zm4szQH-=AN;o z0A4j$mjWrd?GOt(^ux=(yPptL&;(%s$x@PgJ$2L95Xh7(X9~qbm7s3Ztnve zw&=WYw%qj`YCjG>K}M-aUX~4Zj%pB*!0Vzp+3ihJ;JrCFx7&;Pu;#`LvYK``#5W}L zHl0;F4|J$nq#31ooa)@$qjz37b?nH&{XHE3qU!~PD2y88s$yj}8R9C^corD-%-(&k z=T#4Pamu8R+)`YZCy|Tm zC32yq6}>_(V(DF>8a~_{cvJ84=ZA{HzRq2=tJrghfPanfdY({jgh1R(hf;Fv{=qGd zgFSTLv6eFLGG}z$s*s6_X1^S^SlC6yvd5d(cnouh9!dN66vDznOBzwl`{Y#*fNc9?88(~hDP zrF18zWq66%8G4POui{xFeOZSfP;?vSfYB(krI~f7SvcxT-x}$+d^q*;=dPWQ4M@gD z>*$va*okr{q3Sx1h>hYiX$Xd?{U3db-5wnP*5Ed3>b#z8poti2DMC0Eky_yE?L_X_ z#=su>mYY4xZy*mzZ^h>xf*;jY{1Pu)#LDiOAgt+T5Y`ew0jqT_V@zfJH=W@gj9Pb+ z@4d;^e%=#aDunONYbo2A*=XrIW69V{&Qt9}$>1eZ3rtPbrZ?MD|HWDsdv*iZM`>PvEpt4z4L_comh?)wL~c`NYA5oLPza zi_IfymS*7~5bju++!h?4rI}&W1M>{C)~#)L`~l3#^jNzg&@sVaA^%c# zTxe9}>2Y5f={2S=)i^cEm=0PD&zvJ4inf_f|GG)Wbd@kuFs>h(HSm>Z=55i9&5A#z zS>MBWk{H@tRpZw9us19&WxC!N*c098wpJl5&I%2nB-R4md;(7*k33vH8RkrJh3X10 z>iK>E2&)?1q=datwYSB`c|DvDO{Kz@qB9HLV3nVVRWs-LXBeUz_mw9{J`4?DFBnxd z{^V`uLAmbX;Vjj|3|rp^hpdJd3)PU`#ky+5u78P(Cb~jl7ISxt%r^9Wt%zQc4k^65 z##T`*RCqiU^L!O|RaMM~LZRZ$z^zv_23)FV&!x&Hgp%Qx&MUfUvu){Y%Jzd8XJhn+ z4Gr+9B%jb#VAv?8G0}AsjG!e&y#4369I4{%Od__P0iTzx^2%VK2tL~hKKZw(1Q2m- z$iJk;sx<&PX$jda zmHV~m;uz;I#dNtXwLnNM3=P7G(r$IvDyUg!d_-RPc(i!?b1~xWS-28$b;I}4v5W4B zV5FgSivrRjZ3LzS`z|>v>PF;@9*5|E@m_*kJR-wrs=t4d33ia#Okm?BDDPdH_wfc& zL9E}1#qP7t!I88mA$4QKP2TnRKJQl)BszDl;!ro7#tcpo;uhl+j($%blj@!&!s(=L zf?be$)H@5s+{p6Ad91&{AFoSZpIpQG3t3~0UcVC6nCRc+^5i8E%!YQlkkWzfLR!)HiX6n6|~w}aXUH9Ft8%)shvE1dWk2YApX2fX&xAiMnHGJf&>(wvZ{ z6p0dfeQtvfPs(#cV|XK^yIg68VVW@~I9!?;40FxjQyk^rph@@}p2;}2MQa>k6&6km zVv&zhSQ)C0?>Hlpk#W!7T{ivwtiDWt*ScF6UAdfVb7>jFcjGXXl85@o;hF*c$>LnZ zL?FlMaKX(F4&d}JuoO6XWK3{_uFF7^K$(D5bW286y_iTH9&!G8f2t;(&2JwYpdVf8P8 zJ)mfSM4^pA6rGhjb}VUgsO!H4^jPjUBKHN%W;hu{-;ufycR&1%E*B6*3{ zm$ZzVw0!wp6Z40G44TEIz-1j1A&&O3tcR6FXpoO(7{nmG40<~238;6}!Wf419eN@8hUiL8rk_Nwb3Eiq>oTWh&Wygz91F9T zxzWFhz9;&j-P>O;unTG?OR?bb={_~73XiXTQrF{cQp@VpYy>=$0Xkrf)p*V1>Ivta z^G-T=da8qhY}@Y5@9p1n>F7FEISaEKD)9VpfA1yp%%kaS{VWFJ2QKcyv{sI3gCspn zLmnYQZSc&C#kyP612NjDzp?c;X6tp=a$x%)4wXJm65Z46#rhn5-n4U@zeYw~Go*~7 z*52mf7@w5UfR^)l~)o&BuVgz75TC*G6WE*_o7D&G;S`|IBlZ(P3Y zSK!6o6es<*ciYsA5Ij6*v(p1jPk4Ok6ZR^#qDjrR(s7Y9a8AacJPnX@eQm=9z)!+O z`QfJ$Th&obY8nt2DNx{S+GI6e``?V(qldG(&hYu8&$4hEO;@}6#r(saVLEDQY}buU zCwv@O^Ry8)1BU&^!(eqN!Wl3b?~EC^T{~+#+ht_7PM-?%)M9-6Zsg%s`J~-_C6mB=S2DRRlF4lonP}=TFV#?&Qao6M*;+dn zJ^v2;du9Qy_kE0qa-Zl=Zme!ohVb{@>L%qL3_@222BBVxyb^9@947c~g3F6;G$uqZ zt2L%1VD1toSr&mUpyCcNxyiBzCN|lU!7)>9TAE z*-oEbk&RuZXn3z?#5)~M6oU7mWtm}KD(iPdzh#ppgZD^*Sk96oh zY9l~Zg`{~2d66bj^EUk6N`FJs1om8d)+#-Vm7e{D{>DkipvNX2OE%Km{*EjhjXIJ) z`U4EOvGAXqcwdd*o9XXdIABv_$W77%SW@8kWAry{`fY}5;pR|fFnBsN1znwnN-8_#<+Hm?>kdW}^t z1i3)YzId;ky9pV4Pm5I$of_hKLxS0xSAnE39$SYVyn6+$5o?$%nE^3I zKG9e=+1MX%983`UMeh9x6lJ zYm1ai7sn;dZxUpYhj^6FbLJ`knHaTLjgRphFZu*o()@G;)2KErjN;5cWM4(IhsD7U z*{!lXJu)ha}{2{Bzt z#(#YjcfCiL1XET2*=bjvaDZr@WD~eLL2X>0>Q7DP%rG7Ef2Fzd#v&Q$t?~8iC4Erh z`Dav3g0@bGZ586$1VHP>*9i$mU9{i$DVKsJmW>J|whEKm1YNS&HrlwJ^QS_P zuOy5=@mg9Ztk;+}VN$EW*@W0SAG_5J96zB+eg=b_QUhwg=v*lDjH&5W5emz&kLo}Qo?K&-@Sp5B3ymFLec7Xm; zJc9ORl@uzA#$CM70SzGZ5b(q{#HY)h_nzE3m+j)213CTasa5J@wxBp`3hSSuF7v{n z$O(-?;jwy_nYf#RyT03Ms%C%7tB>)WY)JOyZ{ys>rCu6b%cnlJ!MTy#=ns7LnKkbu z-mvgNp7(#}1GXRF9~Pz(2URef5>B$}W5Z04FZcK3$Khaqx<8zqn*_h7r17pe8m<7# zTQBH;3tNn&@dx5u1D_dgKB`Pio^3Xw7ZE7#SC4hFt%Vj9z;}Gy{v&d2~bcWaCpcNbCOG`DS*#cdpDI|y6*Y* z@+Xu>u=TSxSza_Trc58BH{9dm`-o8s7V3&T7PxxhC@9{r$C z|3$-Oqt3*K<-AuxERr>nK_Q)SNjkkV6$7(II<($MZ)^W?!tj~60ob;zdw&({G){@< zI|W->D%hS1I(UIE_i;?i$H1k5zBaY-+9%t1mKCmPGBXzN@;rM7qsvsLby{zSk(!R& zO+PVPb*zG(c!1{Y%m<`4P2`qX|9rw^wWVxCI8?s#dRy2{is*x6j|Zj6Jl9WiTRjS; zC+Eh96GKC%$!fg;xlSk1bP85*m9L9FWoA_rGwY~+`_kIY7aN-{)|m#I%wIHIW4u;v zcts>8+7%|wMNVEp4{Q0W*m{F(`!8Tcvxk^yiPjf@fSEu0(Rr?pvnDR|;n{SOZ++CM zsO{=HB^p{pqNBNVK|YB&gxwM=ePXA}*^}Zpk4xSOIR*Y62&FhQuctVy-;2c;Mejwi z@}h|4gwHU8IhOr^W!pFKOML8-#m*5i&_nHmfpz@ck%M95=FE(&tN8*TFwUVQ-FDYe74zR*SZa*)(V^| z*A(;R52Z7qv!W#CoXlVza-u<5p#Xy+Xnnfv{| z2Gfzi9aI2ce84+YdA^pee2BT2;V@*F6c7vl&^2nP5$7foZu!gxamZ2Q#iQk zaB$O`!CjLMsJpqL*z<92cqMO(vDjAyU#i`d5wy#K2=?i4IC5$cWlZCCl;>EG$+noH z@>RoPZJrl})i_om(+xs}5*fSY<^I~?4fLCV6Se2P_@q5ti?{j?Pb4E_B<^^VCL&u$ zhGm6&mGmXPLG~*uRys~t)_B}LlH3hN{W?0HIEV^<{q$g1EE1lseU*$NzGP-g_(W)BNs!j8yjzEuG=?ioa z?T&3Rkq)U)o{uY4Y+`~crf7a`5kuQmQ$(A-fkjmq(SkfI%*s*)x=eaa>NHSV27`+3 zx~elGU7@OsbOtiIx+iGv=!sHVr&0y&iTSiAiqI4BrF^6(=Ks(W4yh-kZa{ZT^uv6M zW1=7IwkzGB{EfJaoGKO%u;kJ2R+J+q&njppECVYsJLveM<>&=zUeJ**RSd;4^ECrQ zDw2K*Y#15~N#u%$m=)>pBrujs5NpZM|_RCz`DN;<3N2m4?=p3iQJ zFI9ANj=oixTL;wb-7BGO9Gk1wHm~A^6~rahlFxrMd)ekDH?eC$14BwCf(bPO zNVzqnfYK%)JmWmRJnL$Zq(#(Mq)--3YQYPsXek-Ru)IK&5Xq(;~0O$z}VvbR76U&&Hv>Cf9+B$-8LVC`0AjB4$Df% zu2qhrRl)he;G4l9r9itTl`3}ZqO)j+-{RP{66w1TAyTvAP0fxB%PtndQ;OcSSl+ah z#@l(kvP_^8HN#To$@GD`WLCj0Yu~0na;>>*8CIt4l*PBn5-^F-=1!T0fi^r$0O^9; ze+Zqy_V&H)ZL-N8nU0lFq*AHoi3}+De6nM{ihD}7tJKOzOUg*8r_4~)y|So$ zWzZiC(wSYMTv4s5@oUf%-E7ecgi%@*Tpe5!g%*`6&|yWTDX-9dxu0A1&sSrvH?ReT+gn!yf!E#@-K*QF5 zCbF_?J7w4TWJ$DDezfYEA6kXm55#3YpKPi}HjR}{zuctcD}zBBR8>+9$VBmeOQyCH z8%Pzp#8I@;VP6G;NgI|Cl&Wu+RVXd?l~58`!WM-6l*XrKz6LfDmiZPtyUDKs4nDQiV~sW!81fo5qE(=AxaS0X?Y9cN1BOBGnt$O$i6$`R6smRg~d z@?YWCz}k5eiohWGEp|`0k7n12Zb6Pn%r`G8 z7eWu2sFh;PL#j3=X+!{4&X}25Z3?#rDj?0}<-#n%ySv{@aTvz2-Ge10zqo+aWI)7R zcqc*0E!~|Ht;H9p(GR(c-e3MWd64q)R39Xv$eD@t=IV%Q(c3P--Oo-+6WstDos$6* z$X~2bY0FpF{TCmR#6$}Fh}P|Lc9bUta~b;6=ufc}8)icvsCa7h@|#MgTw3E4He(q% z=IwDFEC%Lx)Nw_4Wq5x0=dg#L!nhtC#VL>vQYca2OmXopz$^l13~pB@Lk&;#CadDk zQIpm+ZxlcSPmFHQ?tpp;XaxnH<%R8fc;DX1CBpcY{#<^i>zfdM@XP1AHjgUmMq%>T zX^H^_=(#Jbx$|H5Uk6%$r%6grw42djZeI6sm9GA@7||6HH`~i?J7c z@>w6uItyYPhui!5&U}(VuAvWwWSNPxC9|KfcVsxA#@Jyh?mW(L&W~?aA=+1zj%63h z?FBHgI7F)$Zd$`}(>__fR*DT03k9R8VBuY)hvtM>7OIT}KQjD;JsI^qT7&snNZXvv z8pfb4HnDJgo0tcN3!(|Yc95=0xzmkhs>!#

z|S z^Pw!%$E-B!=NT)%u@p>ob6Kz2?vlCYg>YElxXFDrXSnDC z2K^K3HkEF6+^6*{V3$RC7GjK~KJRZKySUci#n!uJFr`p&{lVY#7s>jAwe*<982aeC zGQkI~Io|p-YSKy?Xp5atF8mNmNveNj?rgW2cB;oX@52ae^-l8ROZ|)iO{NK9O%7l)Odj@&P0wMyDUBbhIiQl9&1 z=0%uKn=l5*=ZcWxqDa;cp>D3+5N55deaOh0({a$s%gCE8%uXbE)NPbwU9&?Ja!=_F z`wEoXQ`5P2IRhaWqt_D$eIs;6tO^n#jjJk9Ho%`6j}7Z#Vr$}Eq2bF*y&UDEY>aB) zZy_p3xg?VNXyFkWL7UFh;2qV$6vuOsdfHe9uY-hYOm`}|PD=Pr$$)OxX4K>l&8RzM&=L?vSZ2(U?3Pp0QSh8LYGjWFREVn0+3|hV7 z??jt|ag!t(*wf}>-10dY^Wg=auE0Yp2OD>-5d4mabox^H2Fowk^0OJ(Jb2Qy+n1ke8Ci41Oa+a&1GAsk|XR^aUa_{Gf~1f0*LvQv+lB%(&1Jg&wB9 zBK!+A#6Z6!JczfgT*H@Z8wQgz3RwW#)2@mjbw}ns!wjGghH+^=reg$*TdEzFbi=^g zVS~f7c1(hXhFtg>IikMX-{-hfXT)S%w)&m9*qMaLD&#Zzz3XjpUt3Z(XE-a8PiO); zF|N{Y*O+x)kk7oheb7fhfJs>87UVxg(BMV4p zle-cIP8}Mb^xeRB&ZHAC8{R&1|Dth@Ysbbg9r&pa+8ziYQo(=Gai?uq`E}M8RK~#d zPiNZ?*Yw}ZD&hw^4W!?|4q1O_7E^>at%uH}0ar6F{j=k@mm^JucCN?Oj^9CCHMkDI zmdE{TO5fWLc0{)v+uyU3+Q6VeUIxU{5U2+^HphZNy{*;e`ib(I=_&Z=|`|Yu%0Mq&=ry*gH)AM5h>xvj=GA*{rz` z;UGvIeXX>x!ytZlA52N^h`5uw(-Gyuy@bq(+)gYc7rpC>Wf0O10$4@mFw{TfHkvpv zSC5)ir;}TM^g$-QGZiW@?Ws**VPaV!HS-K4khP@) zzZ!O)F8eTiq8Tji9U>{E?*XO4@UlqeOTWLPkC+3PPq^A~4ddGOeu~3^zvZ}UaBae+ z#|3l|*Yd60tmRvPqQH6q5}MfWojmB()j63eC-FI1k5k5bTp^J9|G+WeHAs zNllD(qez-)m+6`if+^lwFOok1y&7?G@_-qB|{J zjWHRdw=f5d5Vrw(SD(tTX)?pxB6C|!W)@M?uTi(`Sl0%?UzTRM)0R%Ap}7pNi$p0s z?65$?%H`a08=Te1WLgLGvAu(gAH`35fe8XIx}Yk6PevuugL_SB*zU423v306CZFO@ z0C^(+id4khYi^9m`DyD#c$fxGelycy;PdTLOtx&=$Upyy%=+1@ZC#T%)hv&EQ`Dw zc~_Iqn@{P+qak2RCI6-^)(y%`r*5?3b|1anK0;0R_RzP{lEkwMB~&9FWPigK-L%f;lyiysR?;?+=Ms^;Jdx)bDNk{HV$@dsD9&o@NV zsq9$AuP92XVF3sL{S@dX8$ctVf2Fw9d6i|}h@Z4%t)n1g)TztdXsRUNOTUV_IG~?r zb4g;m(4JR|#mxqt#$D!1PBH40I<{m3FbT@7M~Eo{aNP#k4|XK#L+)fB1vlMu|2{6Y7SoSsK6S2 z4i`!S4UbT7$_^|zikuCjW5ghJCTATLLnioiASk3OW!QS(7@rcaYm*1gidNs4O_m6- z?`QXykAb+5S7>KNC<_P55*j&KuVTncG!;_uzHB{68KpR5ENyFgWMnpyO zu&WrRq=CO-J%v6#Y1lJHPS85I(+nMB)^A1fExj|mJ!bvlEahFg4P=O>{IKt%Pohca zrM-S$g>WGldi)o9aj!pqD!G2lrkCqx6J8H_%Mu4)M>bGB3XWb8K{=V|Vx|b~D944o zI=uwE7TjzC&+j$H$ArV+$;sGP_zafKGZ=$r%*2yVFCFqFcM7eq!4x!F8t#}e^3f%8 z3PPna7Ja8r2@pZ7YCexGix*noPGgC96j^x5ScTDS)Cr2vyy42ROWE9-8C=eq8Fk65 zdCJD9f6pMJ^ffR*WPlb4+pcfK4dLx>!@M!FP3no_G3!hqCz0o+ySZcb?Gj7ZN^h@% zvj7i?_H=`<+l0URb-Rx9&oPMTnU*8<7x|Qy1BTAbggfaV?WM)R;2eSDqTspC$<=7x{<8R}c*lcog-^!lOPzY71^w&b zgC;g9qlmYx-h5O&yaRO@#??pba*f7Ou>KjGfM7iyL6JOG`Ly9U+ws0=So#fEp4VvI z4zq{a3?m}>Gp!gnpI))xH4{rJX>UuohsU%7m(FaRzN#AhilGaO3*_0k;F}xL9K1GS zAPQ5<%*K*=F;FY0okiaO-Qzf$6h7D7*QKGV2DRG?Z1>}=5cGEd0?A-_O*|$uL1!D; zSt%V5f=eS?>yOn6AO;*)J?_??+9o<2ujN^Fk6#48l&y{wzK@dRj-W`(C%TLaCg?gA zeo1E2s?%JdsCCfahBv{J5jv(^ zf<&0;!|`t-It@K%^+ne|em!ahT3y`JhR-CKR69_`OX!voo4d*Pv z2H^w({0)$az)3Vfs3&Mi=pjLwDhf z#_Dwfqvc<@sC#_eW&kz|4loX_iMZ;JU+&q6(5bw2&JSs=JUMtD|Ke>0e&ffLH>Gw+dA}p&{k+eWM)P+0T!}RA z=jpFB++6vBwj+}F+mXESKJv!f$U6-`uDq$o{O*gKeSg^N0kAI zmuCaRIM7bSnaq0b0qTy?W0;6Dxsq0(7oM<)GZDiSB!bc8Gi@e{|WIB6ysT7Wn0X{uri-|mlBaIwd-j-?Ga+UNW&&JMu8LiG(Z$sAfO ztgo?L8Dq+_CqpFnDgDfxMXQyr9&#SAMied+<6(b^Rn{Nep&=mVe`bxcN=#r41f8T3GqH{ z@!AEO(^miGJlY&1JQvuH~ zuUvnZMPxuV4E{q}TCTMSHXm-%Kuc7mhhKJ=H{XTw+@h2d(pn~2g3A!K9o2MlGqvWH>^Sm=FH!6R zh!11JozPOZtdTrIllCL>ruq;IB-TcuWj)EGeSwW&A=5*)PI~}2SscRa$n$ol)zQx$ ziQZ4D>1UaLD7yf-h)REvk+M&40$m-2()eWjoi9p`9gB%AuV{r?K_3 znQe_+^wZwnnBdF77b{I1V!xATB~g_Pco0~roE3-QKhqQ-k#ZS4pxe`6LCOSJ($Gl{ z!5qn^#dM)vN&oPwD)Ylp&95VhxPQuRD4{EjDQ!dpy}gQ}dxB+^_#THrWWgx{;|y|W zp*f^o&Ox`#y9PO|ZvKeor`qT>HPU{0ja;O?vUS=FlX_?;#|@m&(&RU8NCQ7~hCVW> zIp&6}Xjwkup->@|32t&i%Rk9+>7f@jP)Ee==ZopC4$}|%ypeoGpI6|F{f@s(nY&Ab zjfz(ZTtXC`JAk=@dDx@vj*lk0(^RY>cDGTJWppGNSL9~3&Df;3C%b3+bFTHIO+FOD z!7Ywa(jIH5vh(%_8xq=OKTuCNar}m~Y!lk?rqqe~ssL>~qW<3xTf!bEdh?gi1AgfJsGE$ z{5Khy4L?#Xpbhl=N&Q%QfoZY3b@#g6OW62KK6zTyYc#vQGsCR*;~Z1t*H;Mi z9>opk{H&^PzthjMqv>B!lnKSkb3dXE5Da`LojXCFAUgyt0{FPBpVu8{w-=hGHpDAt zvL-eDq_U>;&=#C)t@#MKvxq!QyB(HlztZjR95X%8FlcoleKDz((q)+sP~#`p5dZ)L z=8W=ljRy>R$I6Dsu{(V!Dh5We@1d3y;Sp~D5=9;ukbby6A1#bcZsH!Sh~@4p(?t%x z-P$V<77P=_TF*I2>pU>A=fizCT^`;|bx;weK(8KV({#4wM7Ig9RzxRbqpiZ`D6`X_ zssrXasU1Y!(GnP-<|q!1s;nlbhtc>a@2;CV&8`tN(Nzi8-HdyoBllk9iNX$K{>8t~n=NW=oX2%12en zoGd($9_xDQbiIN(bhGO#5tNsI#%z0Fl1?BHONO2}jdnY)*6XF&rwP*(u3GF;%Jf+L z%rgvWe~}|BR4O)~u3Rt%x#S#+DLGUiYpyb(0GEz68%jDS)g>z%Don|)d|8QaoKGX6 zJ7gucs3uNRaxK8bi7m(|e#YW?qlk~2M8mrxAPWmLWG3xRQ!>vdgr>{g$k4VV!8N{z z?j!W*x<$>|eX**l;5n#@H(q;es&B5!Q=koWjGEL~WwWJK=AJ9;y;O43Y2g_&IBNXs zd1cRnM1^l}a>>zCyn$6Lk<}U4s#lnYUr;n5P{$&3p*p!K>s9hJJr~!%EgJqRl1a28 z%kOAiWUhZtJT?`M7Hm)fLRSW06;pC_VknALV~v>&+Y?OcQd{%i8JOlOm^E{&_FXDj z{VlEN#%o)Xl_j@aQXUq!LV5qG_)*`u;R%tPJ%X%-SN62w|3&7mkLf~>m2|q;TOn|# zT7(|$am++W2+qg5S#B}bP-bFe4TUZcx`sk0i77p>gs!3g8WWx^BCk`Ti8ZubxBt{7 zX$`GJdI{Mfr7OxFsIFi7=VaBL)$AnL7SLRovW%r@%JvxGY!3AgPuAzA0|*3r~}3gzd?NKc=4P=f7`@ zoBMIni`lUhctP^T-q)K`qFXfatNwqHIE3PkgqTd%+xwcC7I1LGmP>A?9E2ZUT|ygNeekN4TW6J1t}r zO;?fQEMKl`?lk=F`aq6op4rSR-rK{;U|Bs^!zH+Si8;2!rsUM{+GpcZO|ekc3qiV* zuCZ~t70S)*ovDiTgv)Gwc4(*dlzG~th=@}M@NijQ-%9=a>zEDt3sr5)XS6OiH7z&S z6{v=s=ZnLOvN@bpUx1qIGA~J~S6pf{!VH9}AWjUo8eSF2U33EC0FK#mCyK`Y$W0aE z(sYlX!vbD`*GgJP4KIo04(Yw2$i9bz?jXxgw#SDZp%xLd1^e5?$YG(JNO5e7(9s^? zu8aa@8V6m8~%71q}-3D4a@(&%XDJN3FwnJ=A1bYhQ^qqa=*^;OC^pE4FEIWUib zpPXM@44G>Hq8ftzBB1ir29=Lo}v}bu;p) zA@9)~BKup+C9K{->tjf-Cp}WSEK`E@c0Gtf0|(FkbbqV*VSlTfSU3TSg@duG{PF&_ zjGFNOXn(7Ttc^U98Q)`w*3z>Y08s$Sh@Bz24fOXE3sgeRZsRnjw)Ugp(SycsE`)to#Rl}>; z#OmQtp|(F3fM35fBZr)n+rs#`37Z^ki@&aF+O)efhA|u~&fLL(k6{-^M{Q0PrqaF9 zbDd{lbjb%7LD_|k@w!(pB0~_E)sMH8wlTBYB^_7H&58#_<&YReJKG~|jqHI3i+h~M zyx?!-Af3%iq&-kEd={s&snNT`gXyt~8K;%l1t%-MpjcP7W^?nr^jNq*1+M?;9>}M& zwwVN5AEJbKrbc!_X%Aea4DqKcpS;K!=^i*WaEJ{z9ZRm)F-=pIx@c%bp_n6xZ+RS` z1LIU%_`hf`E}xBEWg*>}Q0Ot>y0U|>?D;xD!M^fk)aG?S8&Q1E@~2uOj=Y_IG=DfqYRP-LBhcf&S>ScA~39%_^5^)5sn zr~9uWU!vDnge5F62OKFjeiF~eBxPj2HLL0K3I59sqarE7#Ai;P2$DY^upL<^55ouioYOtmO*{ENcfBV5LS5Y4r>?nb z*K6ayZ;hM##viZR^;rJ<{D+FPl@0AHS+5Cu40D&8FS=!7fW~o*)cX8;rWlqC>=j@ z-1b3GJ1#|d{*diX3oMt0Y4UMsj-VWyIeO?GYt=yPgq?f)&eTsCtrt^lkM8yZ= z=5*cQxxhVp3^-Y~eNMAs0XR~qF%%an780{s$Bx?KxQ2OLLLds~+-%NumNie+wVtuQ zA{HnfeL&z+msO>6@CgzMQbT&$ZGRdMO{agii5yKqh8wD|Q%YOs;*(c4Nw_vw6{xO0 z_JI&FIRB5r&%=CC*m@IYBgML=l(Lsar;=wPU8!TE_n*1Qs^!?tw2W)YsJzI@DBmh4Ixh0N}-7)V3|a#i$1AxF+-IF2Wi+iBh?OZ;Bg`U{dp?|uRl zh<2d%on9I1WwF~)xioxr=u8UTe}d-{8*J5Wxf;f>=OW9qx^kJF*|*u+%kcWiW-TAD z3A}s4qzzS`wSN7**(q%O4Qv^BT8i_HiyR_KWu}HL=}az46(Yz?wC6P6U`|7Z0^7;t z%}&67oRy?BEDZJvR~C^M78 z3a$?NB_X&L>YZd-hiuqd{}-(YDL;x^GiNsxs>u}k=wLELkF+XQ7l~A*I3%Z4aUSqq zmR~}4WlWf4Oi49n==hgU0A(bfR6F$gLq$^40 zK!tkEt&q+B4fT4Jyh)43lz$0#uaP(C-4#CCf`0b3?kLx`v)-*X@ADq-bN$|Jo!%Fy zmyRw+o-QZ1QopO+P0;+JKX7DhjSL#^eRg*fZ)hbM^toVomQ&xs1FX(tc+O^c-mTDQ zwCB$coLA`tRrN@x;e~#~He2fs*05E=B!}Mi2+c3S=4~N5+VO?3u^HnHErRz&GA)wj zi`>*Zcr|GPwlK>Gd;1(KR=)leE9|?_zFu4BU^Eu9|DzjjVAGsp1|-Ukb!O>Q8e>HXycILx``TuP~RXt<2zQ^kd)2nek((2 z$U>jlI#wjhLst6X1?o07@nJxENIz6q7<|Qd{4R+PWHN=Yb$t#rs^fQjr?&6?&5P8? z!1XI-Bq0z`mL?;>l=Kv%xK)YeyNk}NB8-CrmwxN`?P<8E%~IvD+UVl4jvns?V7QIR zk4|R0e$Fg|nMIG5i?2N`Hobi2Y3IhB7TadFd$^aeq;7`4xcay%Jq}Xj{iL00?#)LU z25}#oX(hX*`-lE_R0uleEskFqoYszKaK}=UcE0 zAEj0QegwZZ&|j(!7_&rom^!%kkH)k0{}S0a#@#VXqcCn_mAl0xaZ*lR2i6id8$dca zu@U=VpuqMx%M51XY5Ai`-Yd5!J3kr+8-CkO$?FgnQd#C>3bjhdl2=>xJS1^%z^>Re8#fU!N{7+H+SsOrdkM zMf?u)opah`IH%wH&A_pHKQ=luNum0kpTS>&y!RO@ogQadC* z=_c>=rbEjex(0wVj?S<{a#a=Jv=8N*RqW~kvn!^ zOU<%Z&gDG1^KMam`{RWhdF`hAH&<>M`~B>-TMeq$@_g4%8+E+uXfOW7J;s;zy?$(w z=4T(xOUz+wkG34>zWDyvM|+PLK8l*P=VA4SXO1WS!lgL&#f#^kJ$dOM`|G8T6x{Hb zkomn>J6icL?|tS0&i>U{&NpvA_u_k><(KEbIl5x^zuxY8=uf8aXS941u$=rrF?EAH zv+sk0Up@Wl(eu@<)9)+UzBh+ApLt5WVfG6tkN-6@xcSnavb*nV3Uhz>?U|F}{zdBp zcRsZ3*8@k>#uI0gXIr$YxpfcCJ9qQQ|K{s$;G(#$zww#bU0&7&1~kMMj5DLcf}q2$ zMkJ`SD{q3Bbq&5yZFe>aD$!=8T8uy1>|!v)kOoPc3L))E5@U(ANRq}tk}jLz3td|z zZ%RVDA&F5E36dBUmHB_~fd10{pXc%8u)B9=&OP_sd(S=h-1CzDc3bzyNqgVl{WbCk z_sJ8xa-fb|~?{ZeRM8Fh7QRW!R)YUJTi zQOb|E@-Z;aE5G6UP?TP0yFO+S82@yW(%Rh9*4hLwwWgPRt)i`-ZGMeyuH)*f_P(gF znNoe#p0a(stIR{)EA8Crdt7vtutnzxl%t-p+DGetKy*FEI)EKeD_2S$R%_lnTJua%`jX`m zSZ;vpZ~JUJskwi&)&Ku`A6EA49;>%%|7fef5?!rq@Jlw>#0o1x-X_1Q{= zU#S29X*TFRUv%}ewq0zniaY-qklFK_q}vt0M;h!+X59i;bqN(GRq@%1WM=V1p)nej zv-wideXdH@2KPKOmoC6ryh=_Nl16)5N@BSH*ICt`uCO^$=V+DXS6Qp%?htqGbj@Ua zo#YALtaSc8Dd0{LJ4uT{MQR!PTIyuob47ALS?ToQeuCIph)U6t(Rw>rai04AOr`Tw zQlOL6dSZXmOQ@HSBEWN`Ufd{i&lFEw;*wak$*A8ok34~;FDV(=W};@5(x_QVXE`%x zw4g2H6`+CJh3@&HIG0svjf#ObdDoyM#gmo-MPQ+hZd5i}b!v!`G&@~z&l8hIsVt_m zc#Qx~1z<`63jgPNJ-B^sDy)KTWO}qC5TBWq&~FKh&gOa2Q@@I|KSLmMGz@V zeSZYiu@dTXC5hZjF=-a5CH0>ppenT#UFn)3a!DegNfPNnV>BSo6UF%i%&`&FbPK-a zNATNk!~ffV!&h4Y;Ku!cjSfgBfZiBEUAJmD{i7OMZq<<5JVGW#78rpIh|Um`I6O~i zWlRO`XxKag=->$2f*WKo8s#6=(0Hqc)cyZWA$2Se3bp^J1^Y%@koxbUi|*rQas*9^e`18i{G*KH^`sx%TCwRRO3zU`QLoUu zM%ZjgkA#sEhSh$*jL9{4g&Q0ehX*c|kFXYLcwmU1)KA*u?icfNf?sgKuf+b|&we>V z^pEQM>3`J+o_)K%HKXH^U4LG3rpT3Gu0N=6ygaQFQ_|RC?De zXL%$F&|So?L$?c?YD9>!j%%1B+%+*-Q{D3MtI+J|?t}e7wuTDB{vl2)N!(K8BZiLu z41YfLM;W1z(LG?p_ILHC5Xich>7in*z$r?&VfQ6s&qi|1k=<(S^w8qzOvp6K&>Z@V z`iUGA%x)+@&TSY!AugwE{KD?TH^S&q18P-EfJ59YBaBEmoEcUmQ>!;Ru#x#0awV^F z!sa-Hvq`Bm5xY!!2D^~hqYS7Y}=-9fB#2(huHi#)}g3B>tdS!gey`U>d20tQLZ7{j=} zf{?y~(7uAOzJhRyn#-UO*F!(D5?fWCdT60>U9wh9`+b!j`2<8xGaz}@{YK$bf+=8w z$D*|$9)Ia8V6te$G3~MEJGfE~ zC5SpyOHs91G~=UZ6>g|GpT9cp{+>ny0*>_M(G_`AX@N%f&oMpdnEnRih(t5FV7a#9 zByW#FzTFIAD49JU7@9WG6sct*bv|=+Iw-p>w8a>~JhUiTyOzEt8`m+*#;GltNdKK+ z+Z`F7OnuxuQ#gDDhIm%PxC~8>xl1^FZ8wFj;*I}O&Ix?T&_5Dl1&wbRXG&(*N2R@A zX`?azHpdi1ApXo>3CJH#jYsP3%vG1TKWv_LrBCt-VkDJ>9{8>v0W(8 z&9ZW7ys1EIEzm5arCi=xfMKh93ZpUZ{x$6e?L&nfZ&3f4tH^%%22M!~{Z;e^tYMmpFs9KST8B6^(R(sW9&oO1$eE6G<0*(}N0DYKroXjt@Hz3C)m$a8iS`Y3Il}b`1a4B-x;m$_I!jL(rDXt z?}4m{Z&}_I8WW3yql7qkJt33)HJm=N3nPr(x;aoXf_D5EuLA9s(zmkOTw8Hba}#<& zLj?08wVpc8L4%VL759t&0^QRTiVnm~?CItLzH@P(jfNZ|=gecf@I*QrY6Y^!EZ|4I z(8Hn6H2|H944ic7bD}Rtshv`2U#<;{Hh{DH4ormUOc!-@zW>9naG`e3YU8 zulxb4c#ealJNc~wYaha5EYN>tRc^(LSWk#+{{onmj*X{g=u=iGinGIJf>vpKxV>Y- z24W0^oG&Uru{LhpLX0p^^4Qy`)0)`?{d6;3NQgFSeY`t{GT6GEEN{m#F2gWlF&C1? zEO?82V?)B6;cua%!rn?Tlz(ryV+Z{c$0M898m#NWHU&DqrVd8zGgK8IsBWDhaP?%t z$@Tv+-H)z+^Tx@qk6k131^A2g7(!4{MorrIjuxHu@OK7^(>`j{Ojac>y*WsfAzHxzPztJ5KrWz)U)9EAZ z6g7@Y_+7!2%!J>PaJ{b8rLn)E#BanRNU$k!rU%LDi>w5=(MeDv*Qs~^@ z^ki7Ix>29D^GBG&!)Nw$hFvH2g2WybMS~&aThbTk1=Yw8k|j)GPic+zthYvtKP@25 zg8AI}RKdTd@+`z8RY*cJD!e{7IhUAWl@sl9(vWQIlM}k-c)vVTkdqO*SKAwMQL}|! zs2k#w*GCpab^K2#(b)5eRz8VtJqs$O&;>|BV&apwL_p;IL z;1F>d@_-ZC`(oXWP?Dj;gzskhmC?6N{48>RON8#1ck{rt>sKE97n7~+kB*T?WP z)bP8&wM)g-Xq8j!^6Viwxlf+eEhqWqL_rq+6IYSon)N7fonYcqto&^H=^x`do8UUZ zB+t?PDl{%r#dU%|@C|TVavRsm{~@?$j^gURh3lMATuB=;bf3UiuHp(iiIK*EX56l#iK%M`84;Nd;L zw%^b1>gFF48byY$P!U;!bB+pcjY>D(FAFA_JH;TD3jC()FQM~3;nN`7n%;-D_9~r2 z8Y#4=+%B3(Th$_-%g_|i%RbBq-MG%r3(k*d=dlwVmk_D4hT(Zq(MGi%FY2+%f?b~O zlxHwx2yrHvPoWWNnEo}X&cySd@NgbZCSXlGhsy9PakLU)v=S#jy_BDU6r+fP$?!8r z>A4Z}&AH#^AY*m8U%t0bUa>{nE!);T=9KMZte^NPPJE^aI3QFrMwkL?tX_wD2(*^I zM2-(2T9Fhq>j@e-ruf-c_?+wq2RudACG@iCUAp6$5#(}Gzpu?Y6w2`ShCdUe49B-n z#-Fn5eD;nRs`PxK<1>;aorr2F6n*UsVEOrbyLnq5ze3n=WBBExXp^;gDNas_4Hj~& zz*6|44s*bdx2>lOAhFmIzd^0;cK#$t`hdNwY_kc})F1Xeda={77Huq;_`X*bd*EY){o zuk}7)Arm`AQKeq8ihymv>La%WmH{!7O_@|_Chd$EcOli`nCr}B>{BOS)Q|{XnHtkn z+}4I|IT`I|7clHyKM@A0=!9hKE{}WZQ&ig9KIwad&bTGZ@qGkS%;=|N_%dD<+xd7V z(a+PXY!HD$I{x&17#+85O@twqn0Q6x+y$RDVf|#no>aDUF8QwrKuzR>F2Y;YB(XXi z_G*}hu=3C6*Xa8GLSQGRzR?q%7Ll2Moa~-Y_*zzj3Q! zL9K;$S}3oVg}q=YHhUIrg+=3X%`LSsYXS++Mz!du>gN{Xpr;_R@)c!G0Kv!&1@xB4 zqF-nIUJ0x2rjX4<8@{6FUxy?}auj_>KI%fO{v|$RAbqa1WY^Nvq?B=UY35^;=ce|2 zfbOcri%x8(?$|Jo$rdPqVq#5U))&_&T2d$9OiD@Q=_BO)1jl%?(UKO(6R?5bK-z#` zvTi~sj_k@uAo#D@n((`*H3273{N)&m`>{#xUN<>yE0S-Xi=i(v@QmJ@5_x9-`6KFL zU<~B)X>zZYUa7*9Q%7Lic0V0MW?5LZv0;5gZXirtsKw7?WDo@4*M|7*ee#qcIgTMG z4wL=zB$8TOV8ScQ;5>5G5Qq4SEWCq;c4tv(>rB&A5#;@bSzt7&=K%aE`q!i}3mIpm z#<*_1#^g-3c4MtPVd@5BnK-(2*1e;sZ}w`ce`e*U2JZWGnjIe-hk`W6AG|NZK07 z^qgtfCbUZ^j2?Z65!!7%bLj~3EA`DAjr`Po4aP&(7hAoF&(MD-rMc_qw-qbN5PmfF zXP6>sRL4=o0iPPX9b;o5ZEcru(&twa8=#Z9Rd7c~yOMb5LbUt^_gsE;yCI(TnNB<#$* ziMz66sq!z*#e_kg!yW|MnU*+)iPM|D)rS%Wt;Xlf*DMH4we=OCLc~4?z6RUZ$i>!5+0I_hZaVJ zRTo5rNo#0yfeBM4W_}Bb7>cR3VOQ5hDZcelM&7_Jj4VI`7C1CzZA3z}XDi^vlvSiK zhOjtm0-GJTaz48{?tvV3huwE!RpsT4(Xk<6r43=LUJgx(IvdjSbYCtNavGk-QX~5( zBt})o)IoX=nX@esRLin3_#&QEx*I|ho)3pGspD}N)V(GABv!u2)cM$?585R zl@$kRUNuz?Hy}4gn?iApkX9vZU4vKP9xww1ovmqML~FKrnAaOvUi%EmuXarpbk$N#+c z@Rj+Ay2isly!?W_vj~R-qJ6X_p_D(?miX{%Gh=o?<5 z8Vw_c6I}@Iu`cwM5jq<&m~S?&GrXsA=A-mqKLU-at-|3;aKl?wa3hUg_5O7zJw8)b zb>ma_l>$3o%J5e*N}=H)nx1fahaZNXIa(%%cIHraR4xlT?ISA=#AL!{uDloSVH;QU zWDUJHv1D^aHnn5hJ@GE=YqIGz+mH%7?Sb5F^ed#=Cwr$1tdXmx*=Mr%RF&$qdje&% z--TFaD380}pd~`VRm*yVQLYHwK)&q2HD^vpMUKX?k#|?|6*-JEN9VUsJ`t_^l^TYP z*ukj+4b2ETM866O`!iA(!EUdb{tc-OhPf-VF5E;wEIZi>g@h8-3CMwWh?YFeeu_Ed zOHIWKbvRR`v&i59q2RilLF>slO-;IPTxUJ-9KDF#f?40X+k190T+t`QLWAgKq1o3E z$K>4{btvmVj9`d3rCAGaTYBW(>h3Bg)W{r|I3IQw5tZYp`~Wga{GrbP7rMI*nqKNu zlp)G!h%MDsG5LYVr-v;J%aw03-S-LPu`iElseB=ghUA<}+O%rudUgzTlggiiX_Xls zMF&4Xsqjz4`Zi?JpOPObQU9gMHAJqnre1~h;+atxYve@31*W@D2)V3eXpM53q1!GP z?WT9f7C>-6@N|fwJTZFr1dK`Kw&Raak8GH* zCgRS^5wM%Ss$dh3DF@>p19Ol!T-dR`$^xyh_lajJ)`ymCh8p_ggQzP`CBh2sTY)r_r7t@--UeU^bs;*#<~P{o6sr3tMAxV@;4iyH$PX7AtKG^ z#32&C=-|R~YYz>cnOa3DBgE}s-sendggG&cn^NzoT{BIv)o~VXCxoC?GmjhQ2 zm#-I}xI|oT{C45fhffxtE_{0N*@aIIpEg`xd>_O`;XB&vmuXaqeNZeDLTt1iCCy+C zQ=x~(BT;k5d5EWQv!Wj%#o195*!}UwNT2B7g9^Qk6o%;W_?6J)S;x7BJk0eTCWX7P z%QNt275X9ai$9~#o5+{jW0pC5DKvTdan8nfBlwpJ<_EIyg(k-z=T^dvj$Tg+A^0$d zzYR_P$#E|eGLwQIFuhtW???G?X!07AXV0Mc_Y``CTK)yfzYk3=MEUON6#qAc&R5I- zrCaRqgW3QNXvYyKKP!0U7;6~!jShB`{8T0b-q=V-|h2-_&k8+{6z)EulpY>*mHSqGHOL=CWGWTryGq63>+Wjbs(s(` zFDi7B3iBOUMgCCJ;9IqHfcGl&Ocmx)rSVgGRnkSiL7{o|-PbS-sPm-H{)K+R)l5F| zo5QDs%Z7`^<-%2i%ZrP`g}zjIG5j6oyH=A>as~o0)({fkunDqWoGW?P{J65@7jxo% zoqTz91L3e4@f+~TQyKHi@F`HsHa?Ee=~S)vf#1i)p$Gr1(AVDw6cU~18u@a&2l*a_ z{+^U%UsXu|UQ)kbR``z)|4;osr0^dgmXZ1$5!=ww=hg4uCI!=O6HD>Zss07aVGXztFmWjB17RfAwXWzKc zmKnmbasP3udXRK5(nv?dFOAN5As45S$0CrRFLd4+97TqVqYg}n-}@DeA{$TMh|td} zb23R4OyVrTjia{W3KGBi@!0&|*L(NHDXVuLbvzgXVzU5vaI2~CKq1`Se736`^F`sf0AcP{4*W>SUa5#+#C14V-VLmy?^Y040aB_^EOfJg`iE%s|2S zMDTJ#L41}WWFa!HLAqE%9*1C^90JkWxlCXEAr5iXcX6hxf-)?FjAkv!u^Yne1-YgI zjkRDY5!;r%r2Aszzt7@~7$YWcEH({xFP37Wb?W%+N4a54jjR}rFb})@as?xMPBBJ* z*t+gymSG#tq$E*+0^#uB?mH+UZn7cE@IcyAr4-|&G_bkYS?oME;<(@E$a=;qyYtNR z8!co-R-MpsK-BS<5y4Bv|CA85mKLzEAFy7e0$kk~Tkl!CN&-dO##-5(Co@U5wg=<#x zi0L%LBHvvm{SU%4aI&%<2YI#`&%|Y8^!WLwOpOx5R}*wu3qjYEtSe16n8r64LUx)T zGVA7rBxmNt9Ksp$ZW8QXR54;s!qWN_@Fq?v9pkjmwqS3xkj~I%!J%fzNFz!O-6@P7 zVZ>XZoXgfyzzCGA)M`yUov1P5{-`dJ@F?ovGbQ`WL0h!1_H=0Xrc~>ud3~Eq{!JpY zY0l6lGvlRhYRQ&1qXM?S>$ZjCtdo9)v?m|zBrz%jnwAb7{ty&8811v&`2J*ShPLH& z=t25VeB(oNJ2Ydrb+q=`K5({9ih+#i^(NHl$$JG6Sy@^#AS#oLd)s??&1)rUz!nc2BhWuE#zQXZKx> zy*$n7`#$!s(+wY&)y&7qOJxZ0o3Nh_wa=WJ%XiMRW%@dxmxXu4X^r3yW-Ze!)0*)0 zbf_TAHoY6{2-hW^5_rmIa+@?TB6vYE`&Mbb1v#czmx2~qUm=0NKf1r4#_{|kyT0GJe2o+m}eniNom;f#1sZ?!&{l*2K{UQ!IZoTo$K zELxmwDo#PN_|u_Nq|w)`4;ni&tsf{>tzvy}R>!|J5eyzJMXehWo$<3uy%lB8{>r$; zvKj2*tm$;9X?hBM?K=#U#4V{C6tzK#R_`Z>+H?O|lp1t9wpdRi=W{Zi%_~a`-MGax z-I!OrHrBYM)0~HJEb84vI+_eMgATXxG%%i#DBzvxDM`ioX43<(PuUnEJdms}wr5lJ z)1l6pM(fNZeF*cQF~`ds`-gJOr3mkdx{#Z>JaE7hAiUrgRmxX}+yqeJbQm&lncfvU zqHf}B3%|yQU!xn+9{Zz;y1%(&TF8GuXdZ>Yg%AihH+#2PH!}psO$6R(-?6#@ZAcAX z4?%GK4uoO`0wK2$;6`76oiX7yULXi?mG3Y(%=upkHM)N7?neOuLxb!1h#?R({|O=M z6F|UlK^=nx!Y7y`V<5@+8SMB{8}cw&2ZJOY2U(s-l#Ly zlh7Fk8gRznA48X^6TJ7z^S#CfQgR1fN=niK)hmr}8EZSrwPBkNxr}fwXt0v|99=^0 zhi%U9)u$MlRkb6e6wv7hRJh6GbU_^^n_8Li%%}8ENihiY_(~8vBRP*at%w@QKl}KZK-cQ%@t>bUOV{qWoPLd6OxC>aOD> zZEo}$ej#Is>{}*bg1B|i=`rict#7m_dSwpt&pn10hu7OX+*2~A2u{j9g{qES&0Ugy zdw=wVzh-h>R_rMw70- zWr#_%ocUu|RQQpr({Ns8h%iJ!DWJu^_6Qs_0&#RCi3-YprKFYT(rc<|6M1b-IRedB zulDlg0rC#Ds!O-gvZ^?u{F^ZOjOYAbm>%vwu~iMy6Z*2Y{4Jyds7Q{0kKn4b@YsPH z2&YDK1Wqs#QECp%V?vUsaNbC*ZI2xa|GNqFh}VYkYuaO-;rY~*!ec)uSZdRbWXamZ z)P+&tybf(zgEel#7G_OqN(9`&Z!!%PX@Q0%x=Ffn#2?^JJ_FBHI+RoaJyH3mu}@QQ zTLO^E)!J2uE+1SGTXY!_BK27pl~YW1H<4gXCk$EBw6QSgYY6#=a&^VkzZs}Ae>6rV zf-b9qSHdi@HCM_HWgkZb255Wv0}4IZ1@Kq-t5JBAz4hqsx5%Cbizs3**sIOP?kt32 zynU9w4f}4#!I8zwaHZj5aos@Kd0bt%e7L;0ev7O87xQCG<&WjWn9F~+I%aP9fekV9 z%HJr9xx4(t<1zEg&;C9pt-Sx`m<91n#*u!-(yws&yHd0fgO&?QHZtFxSB_mLf3Y{W zd`0%=_=~-{$HwD!e{#kC*)H13ssO`&J#pX`cxr!sZMyT39N zZd?CO>By0PxnBb~gOvyN73Q9H@AD+r#(2v}3}K6OV;4 z$E$~xcWS=gYSUs<3{%QPR)9Y;@r=Bn zTfWCHrw_>s`{WFhytt1UZ(=k1Ol{BOuie_An4(q4#kk8%{40;zT1A8H|Bo zH*965l`?k@4sgCEZit!gXOQ%Vt6(N~1vsRp?jARX88@4}UdZ9y3g#}Vmm@zj@k|0U z&V>ARwM>%0%pwVe1g>_R8IMtQ95e3jmT~jR_cpFYUc&I!79OSq=`G{#xmB2Xt8h`v zxW%^$vu+jAE#oi^NbVv)Kw+~P$NUxmF%dYrmT_9#HEF`h17=bS(x2n8Mj4(-cp$7r zAK|9xM!i9#IAr&s0-Rr7gluhofI_15VvaGeCIeEbv>?5(VPd0U0>I!6Bq_qXMt}v;uB~7UDUF7ykIbR@{36tqyg^25%lcAl17>B<`?(zi+yd}zQnrIetz+r?Owg-$aICumd^j-%v0TR zOrJc#o8&oB4(oQm9PLf_Pz91Gh#V!>JmC>|i++HzN;R82z6fGQ?=BX-6kEYB?!x^A z9*0>ZK1q~*plVHpJifoGwaOjlY2gOe+)W-u&F*y49DTrH#-41E*DUJIo#w7n z1aw!5$0rcbT@jw(DGpHZr0*mfOdd^-PTGSBG;&cz5BcS7v z+)r$65(V}s?H0sV!S|M@NdRQuArG7g2;{d|pTXlr+PS4t*CEb(nDw@C`nJ{<`n{2Q zL67<5(YFCI*GM39jE8C>kR2Kk3A^g6IEvjD?V!YZs`)w39_-zu<|jSK;|0jR=h)^~ zJZ{voRPsH^xu0U)bzD=O=Px7mHG8N%b^3weZwNVphY93h6QD$?>FN6`Iv44|9;#CZ>~m==4=cDhQak}`d7kP*AKc)BQ-PytPR z%2R}0nAG)W($RPe!=%KVPPrcU)XZlA*R{ceBB1PA?Lpor0Ik`;IUYiyDXz%8qH-i% zETW3c`am#3^sV#wC^o3V^=sCAaO_( z?^mmV)6Fi<{R9hsR#I4GODeuw5W;w$wb!Gu#Bw&G{Zl9VE5~Ntddl zUDUDtO|~r0XYvSg83MFzCV2>0i&>nM!%7qfi28o2zp1H?%3=@7HC1fQ1&tjzdnw~A~DRzBDz`Cw@01#lM83a;K06?YhJ)OnW2VDEzBV8Y| zs1@*~FUWHQ{`c%)FV~NW(%IWtTw<0|*qRNZ_^t=Wn}AzWEQ+5Kz~XmffUkOj0kN~K z>!N44xV0GIF;!3km|bsskYNolrBj^G$NB`WRX8$vBq_eNxK$`Ablor7Uia8ku(l45 z3wY;CwlB%cc&)YW=w6`RT3lb;)xu)b12Wg=sR5GN(q8=t=T~dNB*}A~SqJ}}Oz8oSG(bopZS&Yb+I&fRkBnnvb3+qK%r%dAHXZ@U zl7aLA@I05wipZ2X=|SQ$P@{PPCz@EXjO#2*?YX)0*XaZOz3F9y!GL5J32nO;dPKF; zsJS8`Zef?1J<(2?#ZGgP8FK>A(YvS|q^McVx{i+_T=Nwd{F)6Ga-D_k@7*j~*=bG} zItxKHK;}#YGN|SQLKX?|O}ykd=FtzZOC<0?(QKh|Bnmm|N-PX-0Y_~rZsa9DujZ@- zg9@mPMD9(qD4h~rFR>+NF2G6w5mO&^3|2l~md$6_U^o#E|Q$(tj2 zff(FntGNEE&vxG2Q{7($)atw&Imd(Sd7Aq>l8&-iO*nKLmX+n?_2B0gm2``MZ~6cw z5+o_fLk787r1TcBNWC(QitogU4CUSEpXK zG{i4-pCPjp?G=}Jyysa`Z86tV+{b5}UU{=*b5C&(yjZ*WdoUk;nIihk&!?kelRVMH zFLuh=5dI+WjY@tH0fD5IkA*mhAxfzEfk(VIiU~LSgGp4#RQwdzmO!dgz|z|FJSR(Hd}xVR!me+ za$zD>t5>Y$GmFf~j_PU>?R;iZlfY-z)LS@#3|~0*0WTZmmO63G5%AmkLZDX!@=TI` z>j}ZHFX3ZQsGj`TjT*qw7^?JS^&9>QTI}9q z0Vu4@#ZGy0DW6j!6bY_3JS%)RfU4{F9^@AWiY6YdycCbnW>Cy!|Kgq=3VJor#T#*?l+WFjcL6D~;Rq3n1TYx9l zS9B8abj@RJI#Y;f zn*KVhh)H!o4ANduohf9AR9T-*!%?BE&CF6}uHXFG#vADi`s@19!;9c0`dg1wMHUjk z!14>+BrSOjNCoTQPkL}`eHFxSU~ujwJE0Dmb77BLzHY zkP?UZJAn`3M8FBi_sLU1FRa<%pn#7TYWb;RBpip?`YLgN-Mi$5I)(es*H_hpds+5* z_LMSAb2RDt7|?%9HRxaabqe&&fjG*VIR;ItP-(~G=aHV zz*HLf%pqRtZ|dWhHdR%~cLiS*T}U$AB<^W~IQ%N*8Gwd@l)4WXKp_^) zY>B>heejRqg%(tSQ6T<}YXruN+2&RxsO9R-ExeSzNI#%A_qRceBz^pxI{d#@*D`Pu zO3b5t4IbYT3y}AHqauvrOcBGiClifu_gLKf2(mRQN3P{3x!`48*F3^(>3kdc0H(^WxA#XiFh>R?- zkR0j!5xljN+IM8f5iD_J2BYUyUW0t&sIiuxR?1K796*_$p9cI~J1t`(0njcJZGRWV z=h>ab-T;C?h+V((lwcI`1V1dk5dI+=fo!F`1v@7P<{$X%7S8c7>!{=ObsO91m#^11 z=NW)2ZjOhMrvtIUpAp0cA66?Wkbn)CUs4-nJ8!W#2*DNHIDvcz(Qro( z$(jgyZ+Nh(p{kk$j>DF-kn<&bS_@Izk+s*0R<#zkLSS#UU#nceM$H0h-MQ%EDCwJgM?1Pesq|({eBG15H6-B@rA_m?C)xd5$n}84&W?+Ld z2z;m#tGN&OStLl85~qM9&V@uAc;a0#8@Z82lpQ292;0i6^B)!nvS~eiqbqBI7uRbRucb zZCPU+8DBn%h#MI37$f>X3l9a=oz1UWK)n)5AAo4*mlJ?2*$zX-dsE$fVc+?-h+6eZ zO&hY6dyu9Y$aS_2w_yb$*g)BF)dMM$&`uE@53=4cmMZ3ki!b#LmpnAw)><}P%(W02 zgXIFV!8SzAunh58&4QRGSotjQB{T`LF;)OFj8t(6@*D62GOd{yCwZW*5jW5VSB?kL z6gm>pTb>!HIR5G(ccA#lCU<~_?*`t@LWMp9;qDkYAY^}_PnA=GBcwK>4^W8sODe<` z6*7F+Nzr$l^__w!h#)7&xYV{`1acvfH{5r#J~Ibq3-J^f<>9{VGT7zf(WL{zFE$4R zN-t#Inybj=7S~(A* zV!c@Yyzzd$C0S6vf)FNuBp^q!B!CRX}|#q|jIcPXE5YZAemT|2~` z1I>@JdISLKY3h>`2meiog+*(0r8vEEc<^Z=;-RAEKXNs-M81P`x3hwe>uG8_;Npu$`OAkfg;LuiO~1ZaU4UB#mNb4xd$SMp%ZfS5PnTPb$+ zSiFTS)r$!{!&fL`3F?LSTu)(1;ow)SYXdiWP^RQk}jI zBeEXS$1LD&`yCPO&=PPn@)%}qy;!mtdkH^(7f`DC9b5B^h*8f$nO2Ox+#5bzvJpZB zga$YqSt^Q!&YIyDAz&1Cd`T^Q0ws_k<`vXE**Q;78xU*7!k?TcI6fjf#dHCf zrG9=5Q@RUN8gu(BBA#GXWxMLQ*1B$fT77N0kdEQGG)aM40oXx@Nu*~8=xORGJ5P`W zM-d@;-rfxT(S!XCFtyc)B2idEIvT8FZIE=ZOo0y?-ANV>^S2H199cF}S}_N(CEM@6 z1{6U=$2%OU1=_@asQYJ&B=9+o0k*kiOjYwHwxmsUK%)t-=R*DsVgbp)B1gY3cRPBRS=;FT8sky*Yx&l&;^rD%$BtR|7dHdW9oHY~eDrKSQ(#5%3c#$3ci!^jY+47P<| zN`1<8wXv>l5dv(J+0o0oFuVq^ov!a4?j@ufVWAlYHb4-Mqq89|qv5{89C2||xOAnF zpPrg|ZTMz-Z@SXc2F?KQT;K?H*3~3-^V89quJ5_(>t1mWp;%HcWH_5T3kD&) zz3kzDlSLYY@HU$WZ%u{#^{dcP7p+I#P&@bb1jHl@7(M}-gHaHVnV%;#^6^%D#hRe5 z`9K)=u~0Pv=cQ6pCWcC$0K^2@jBy3De9Jr%@GX#VXgfT8`9O1@_g=Cy>1uc4xh$^Y938K(qE_LTt;!Dlix5P|L(% zCQD_CC7C^$SXSIBW<+*t^*B_Xc3XCnk6cAGyvM+Pp!rs;_^85?fZ9-tghwGTSqX}q zlW-0RB5sleKG+MG!SM}+(fQC*eY ze5&l0*QRfS-T>toUJ&Al?1s81Rd$1RshHCj3;Y~<&()HL^u_u%EDo(@zyq67G@fcB zOCVgd(f)2ezf}M=TKN1?v`5Q;Etwc?qU&Q%E6fXUM#ji@WAp$s2y@NqkwfrrB1bg% zt~M4YRzVdreOqT6Rsxh0%;H&SO^JFB!ox?1ip6#bT&DnT*8bqtq*>697j_ELYh+Ca z^F`C33?x`UZ~8X&lcb-Xu|V#|9V|{j5oom{oE2Frvn8uM9|}4kgna-ybM&FXJ3jOS5qz*+=!3RgVwe_w3K!00jldD67=zvWl zDuAZe1pr{8^`sN=KHeN2fD%>m4DpG;nke<5H-j*%hv*Ep3H?2^cR+mbUV;;3zrpV; zq5{zyvL>X=VT`e~=If(+R;((6D(?qRf!G=B6^VlX98vK1)DaEqU03THdICLlomCK9 zA$``$D;wo|A%IrM_ED9pAQzbA6~M&G&$r9VA&j=jHaOz9@XMjr^I{6Lu|Qp#>j9f5 z^juF6#)=C{Vq*_pfObOoMobpD{Byt=KLBpXccAWf5 zOd}D~$Re3|n*)k==yS-iEP9dmT>&mV|044dyD@a-uqCON1h7PhVn^$nZb8dT{M=FT zDqVrph8YPsPTsy#z@RDR?*+nyGDIGAJfx1LV%9rMa0h{dbt1L_^<_Y*mbc@mg^&!} zZKB=|=P&EaAo!U}6-n6SXgZL-uv05cM|db^VHk{tR$IIF6v}B%qaqu<@RLEc!WUB1V);9g)z7paDd-QPm_+a=VCZ=lBJNV2-y= z#8XL1DGw3u?qD5Db{A$Mf0goC*z768b-=Eb=*hsU$dm^g1MX&UkVQbKIe}{~W1+5a z3EYvqD|jOjOr@%ppVKN}#|)HEJzC?-@HCf^kpVFX8&FY|YQSY$Gix9$mx)+x$nhJQ zKqo-mMPv@8k)9RR^Fl~htwc+KJunWrfCh@2e=WjW*@TUAnFw(_kMLwbY$_A|oY=_v zjB?(^Gegptz|oVTbm$C02Q(rl#%fV69Gc|t{^h=gd0&CpR1qGC}1LKVhlP-WM{VAs&vqnyyGp7nNmZ0czYSH#&? zLcZoY>)JI}>YwXu>#S=n1~&&>BF#aj`zsk-DF^)|2rW*5&jJByOf+z5q>GPC^^=v=bBYwA=_0b*1X5I7NRYC$a#tM7&##TLf8_x)hcQp;}GcA z9pL%{o_Bue1o5>^Ha{r zuSi#*Q-y(3+NBGt);@b}_nOl~d^9!{aGuKs@<|FLFk!z9=wo@g_DifPSZTnpx`=HC zmXv*;?Rj!f;Z8&Z-dWgLS9kZ?_*$ODYSUC#S4={8z~1$md|^d6e=_x~<&*~TeGo&7 z8oW=h4QFzib;cMN$=`M8>1Eo%Okd7I#IPQoE%=S}566A5f&GVZVPwbiHwObgtb3-q0pFKutMXlpIH3QMS~*yFTl9Jv;U z?XtVdQeg?PTWG6=AyF(XRGJ2XxyAeDH!~qtD#I%_eEQv0O!H!qIXSp*s$is|dyJE3cLAtg2QKnz*A{ zMQGB-Y89c$YpU(il-vdtp}4dL6``rd1{I;Zjy9aIv`Ev&!WSU;xN79N{`t1QpZSBX zJt?u?8Tw)Q-9_};y?6Gy#53Q_xnsfF$SWJ-%^On3`IN`=Ui(e-9cwm5%r<=T^3&HI zn40@~&WraBzhi-mRJMMtcrGY#d8(^;qUDjsP2Fq#ONSQp?eA0m1mjCewLxW& zb2f`&R8KKCiilk*$`HuKFCzrsDMT`>%%`gVyb$s6GPLx)>QI8I^lgLHu#<0nchAe6 zkIlOJ+mTCmPyN~HigSOSwt3O4hu*eae}w<_cncgqw_jfIi_7v4%GRxyJ>M&Pe|{Nl zxcvWa!{*B?zE$Ls%Udrho(-4x_WySqSAo&W6gWr za6!7?v`l~CH8i ze}@Rs;ytX0nCchHzdI8r-i=VttXRmIxIY&C?8@u(lz}1c59z(b-{+7wD&z#<@04dE zz8HFj){VFjOn z9(y7cZPP<&iig(ok#;9PGaUnC{H7y0uhLVnI~hMDPr%}G^)r)vhn2r0?ey?S(NEJC z<`r0F7`4Xs@v$G12cHZ)NsSZIco5ShN1OO*COO8$Pg!uugkUc+M4P)7oHp@O7kp;o z@!G_XU!xHqQN9y|Uu8nNi7B}>qBTy))fNTPKRCG0+O0Fr^6ydCc3P?R|ef zDLyNtSx=gB?I)Z?_vtm^*7?l<1<+xoYwdRau5_ws-Ek0_3NKyj46Dtp7^eE~%TWtz z*H(nJq&31aaOHfppk-}iSa+Jgp4u~7aAL(7`TW+ao^Y^}u%WcRR;p?2$)UA*~DubO_|QXCwY5~*v4fjt}se@;N1n|kEGJvYF_ zo*r3j3!xBbN6jWd;%1$-Tv$OOe3_=dDx|c~S4l9h1$1IGlL9CYhqf>wBIWeD5Umo1 z?%6)w_sDtE{+DAr=#A0vL)wyJ-;#_q(3NJv!2uL7jy2l}16W1-ijg=V+MzN4*T(G* zGiTj0$Gw5}m9e97oKa%hGP~n-B_g8ql(dnpq8vxJyVJJ2576#?v@e(S#S<0+(`~7a zlPrnVMnjTg*X5d4kxI0R_twjq3w7UupSiyL(D;vx|Y5MzSGmmo1i6ZanaUGW_g4Nn^` zChpxGhVT|~TA`Z}{9n-TlNx>;^#P#=4EGxTY~0Hn)^^*eAv=9w+P!)|_q11E)u*Am zHB5^}0}FH{iRji))Bvo}X&6J}XUk@HttPZl6Vjs5xnV8c7VWL$8a3J{&2H7c8NX^b zd!7tDp7Gbd7^*i4>7VllE^Pg34ioZ;lDId~gIKQIKfU_E0=X~wQH0QnqBGNg-71qd zxN&>Xwmq1;ZHF8bw=tpAl(I+U&pH&CT<0yvL|kOjP<9<<)l%+4nu3wMIT|Mqk(7i} ztpN^e zM$xdd2%hJr^d9x>+j?+HSDi1v?M+XxNo?Hw=&DVZjeA25f$&rC&y9a0_=oj%G{!3v zgP6?|f>iW58|2xifc| zfjc;ZIBKBXdo`W08Dj>^p+K1{V-VN^n}oaCGGwTwt+2J)ezXu9!=ldzu_fKL8fde0 z-Cea-E#2K=Y)oxv0n5asMf#_uhGhAF?(co>08zW2-}mF|HFD26_ntq`Ip;ag^PJ~T zMp{}emHb1n25!cbO)sPB!5rph15ty~1Ou1>AEXu8e!7ivQfV0Cz7953+xO2;;Sp~b$)gKJ5>uWfY>P>5F|~Au-TM66w1tmW|C9uO zrEUfsi0b~qmMEmYKk{?pHgp1Mv%aw%zR_~1SN7e|I6oequR2-;sYS>dmZ~M`wBo*h z(mIP<1hyq@Ik!-oKRZ8X>4rzEpCZ9mO;}9Op`qpB?x5X{lwJ2DtrCaYc^~;Syeopmkk7C4$Kn6aGNj(LJzCZS8f z%I^deFif~;!LB08+o%hU=Q~6k3M2c(Q9xnv@ULP_>PN4BDYfez4Hs&~J^^0Tps50n zYAdzyrk1L$@`+t+PY2uc9))=#IYTQe7KIlm%xeJi)!|Eq{EfXpF1L{2PfQf2NJ8%= zPf($HHaHkB)6Q({?D0uZT!8a6Dcmdh#x^!2^oe3mi_p=M2C(B?LQg+XD{m3x798a_ zvMt%FTh1G60h?+}D&V)APAUbs3cBhFYHYHIS)|Qp@^e1??FZ0P0Q|z^8T1U5poZd> z!VUV@m_6znZ=x%ZI@ALhZXrRNN=9wPHLWMOk;ah$HrR-!zSt0frFlysI<$j!h{FA! zCN>Bfb?i~ox2!m>N0eS5Xu^v6KzmiYNU#_ju^B52q6=IVRRs}@HKO9Vjp--iimcMgxS=0js8P;$CgUj$NZi3X6lrIuOF zW06FFd>&Jwcorsw(^B>tiZ-lf5|LOW_@CVPr&T;Rs$F} zwqfd)1(wHQL}|4F%;-X0tzKf8rOO`$?Y33=&2Or!A1zz>$b%0){WK;GC6aG+l`jR; zhPi}}=Gq-oZS0zCrg~zU?WEri&7&J~ci7Hj24tVfq4hqgNR%!dEr~bK30aLK2t*`P zXtD-LOo&>npv-S_H6O zYEOZJ*cuIkmzh0SLuC7G0WJ(NJvi0b;I(56>VUYVqoR6Z<0*ru_i~V5TJk@i4=f1m zRK2esUoO;4Dv>!R<=4wTHKbH5(v)+IPRl%|Y2cXp`uUsZ!2Jfu6`ez8?A<*2J6^}@ zC%u|d3*tb7U4;%j_~26;&me%DYKy7YOezGCaBs2}{wWEQQnpAFzWlvmrh0C}8xn*h zaI>pnrsBO`w3fxEWashTi%KcaGm~b|f%ok}pVhsvvt0rw72StKe!Ky37T}*8?xz=# z@Ff_PHWq6(ONn~pm$bUbjD!#>f_*SJcsa0_>^%f@mrLA6oA%4}Sv;xSk94W=@a#E8 zNO_zN{*;G$&8Mcyhzk%`9suWF&H7S9zA@##^mHUP*I=QI5m7UY# z0Kb`nIMHxJVPX$Vp#DbS2N?b&)8v*Z-ftB=NWL57mP`~}h^0o$EpAxbego#`h8l77 z=8+YfN8OM0wK-{C|A*P|;j4Z)LT<@{eRFRtHBxRtjBl<#WszG7kor1SHdbyaL=)!} zsNq8Ou2~!lul~>t-<+b~Jeu2l1N(WBc16{io1p=dSS${6iN>Acs5eQCXj*GFh~=Vr zk<;KQ7e~utQeM$UpDf_8GE|1dWLwjrb=WZB^F$I&EiVC>=i$%yQwlyHyDY@~ z>?0>*sU({EhIGYJ!)fXQIUY+T)6}=*C{0=0Y2qq5q9#t##5K}J6Nt=yUJhI*5t^Xh zJIAO_J5#As2hic`qSLF>PZDPo?$BUxZD={v-g&Z>ZU3L`a7K9IG`{ieo3!epVx8+Q zs0!^Z4*gvYy=Bq_^h|Y5&C+{cFDw?zX4fFV3{$jvyJyFw&EpKsp?!SDs|IqMac9CE zVtP%k{doHAX~$0LTMBb(?n=)L=cXQPPio0lQ@2aBAKPzHu*QQl%thyU$RSxhJVM&m z9jBCS>LYhT6!Qm zz20>s3akE%qNz7)<^A*Xipr_Qs-~ zPXE`+@^$(hwzyiJXX9(v@&`sTscWC#P>SXQTQuDMSo2ML_%~_u)79o*UE*m|$^-MQ zEmbd{qP@`6u%wt}8(0Q4*Dq_Yu4w;F1zPwSw6&%RqhXnzoL7|R%<#+p|XuQ?X2IoP{atYYJ9*o39a0@cgvt3HfYz0>=cxr#Lw!y=Rpb?NN- z;t!(5;a)_Y?^bL^eba&c1Nem>e=}pyc=sxBmHz|Z_A36NTmd|;gRpMZz=g>!r7?sk zI#_G(rNTvTq>oDAeQx;8c&^fsiaQN=tX|7YI(7}q#5ZijywHl-A#4DZVIw*W_)#7l8-i7ZDf=II?&S zx)0Bu&b?6^N&S4mOT}=Mz@|vq<6jpKJb?KDC+e!+Kr0_cBC=Ek2)6BrZ z0bG5XJn-|az@fL8@4>YER>>8YAl$swS!$L-cJ5WknOcg_VLLEqBkdUQoLO#mkOrE- z`hW~b?@{MgJr_?y#zP~v=rw1xDS}ONoMGV-T~m>E2b>%F6}j2t<`GW*zT^~8)EdOgJ~c)**NPY|Z<@K~%I2h>oZ>slm#m=@d?J74 z4qnyob-8#AjpZXO<2v zb*(sxLVxp(hzaC2!nq>!mZ_kJB+=}Y$i+>ks1uQ4G_|7d00{l(?tJO5VmqzrInD1%{}NGOa`C|fA1LxaFP7w76!#C5U7b6ezOC!#DLvd$*>RY?ch7!f8m`9lU6*h*zDi;>ihC8M*K?A+b7m*_~98t z-cZL2X(Tx$I&i{-kJGlgl?1dkD#QNy@ZqIo;kUV;Eg$h1e`rKP4ha5l^FAANe2n@t zfD`%Q{sWBLg>Y1ZUSs>=sA4D$LU8+OXeD61_nEpg?kxEQ)|%O!VIWO8pJ8{v=lF#2h^Sym6|kQ+8I zwGa;duJ-oj{P3ry5p7*=&Qfy1Wpb6UBxfKJDHmVJ)x6A|e+ zrEgd^V+=xW>D`41;&w6nRzRXBrg9q*{>qV+2+?5pm?DX(I7X#0MAihW#gywY)TGUoQI+FnsRZ(Sypajt+&x-w}wJ%*W^jDF3d^{pHfOiTxr$) zl@&){@-Rx^(o1lll*QwPS&49>eVs+0-A<{2o!StWl8%Ib9dp_&izz&h3iF`_d4n}e z7E_DG6xVZX?v%pxU@$$HogQ%QzXnc;eEbhO1Jm7E(hF?QODtr%kY_OG0#XMAR-<}8 zj!M!KFtzTP{KUi;wJV}CC!)`?IEo)3kAGbDCGlFadq{G=T zN2bsbmWw0LvYRI?s1hwz6CbbgnJl|Gegv;|iDrm^8c>sd?a2n)%G)KkZ)1CRdQF-X zM*psG#jSulMe zvCP!UZBf_wCmh2P;K%I=?+#@an`OkOTu>=)U=wB+7qjw9Y!{o5BmaV($uTwJ2wqpU zfvt51mj$br1*$$&$`?$>>cIp^>sfbtwiE=EgHjMsl|t9tS)_&n9P*Zw$U8T&GdG}n zsQ;kI?NG9Y;mN;Uu|z(^11x3XTNM-PeFhsd7tk8*1-1Bd#X((rUiM@ZQJhXO5!U%x zZ9=QRmf?qWpD^=$7OyWl|3(*Q`YYr>ytM?~x8#qV3RDsGqj$Y^Z@fdh-=2Y>X>jfa^FVngCj6Un|WClx<4!IpwCpLbLv9^@0HdYs(g71=b;+Ap;3(|5E%dvDM8tpNSzfn1 zGyd7O26F-kcV=`pSmFnlmBul(O;69B6IX#itra|5!E{1+Q3X`}1BMIj4tUV-(l|8a z=dGyMMzYxdn&IHTN~e8D7ya|Fe_C0YErt=z zXEl~|j$O|tFovSWdTn=`nO9OH2eha+ElqfYT%fyY1$2t8#ifp6QnTIDn4dHqPj`bF z$yNnhPt{#euvT)5QX>gDc|{f4eFH1zKb%o?Zf%5O;Vzs}3E}X4%&cJ! zxF9F9=!kJ#TFGXU8^;t^6Hva)KG<_X@#k*Y+d;b^2NBs zXPAoMNBKEbFR&@Im)+EwW#k@L52~S@5k1?%8yza@^tD2=W^w8AoR&{Go-Iw6*Ry#b z2Y`h8Q7{J-oItmPO90)mRt%m(u6O{wl?~Df~;t zy(tzI*AKEDXT0k56yFEvyy0}MoO6Cr3nj(r9QHlO_N)hPHeGJIaxN>;n}LOVtkPPf z&peg|KYXss>%zH=wbGxq^bLg5bl-Al@Xc| za!p;i&rvng6|Nzg0~uM(4P-#Tgcvb`i_Ys$I&uB}Xp^469u{7%u7 zA9)@cCd}?zwjA7nstx?9rejpWE~N_rLVV`V_Ama#&g@ih)E9Znpm>=~5B=~j0DkWs z{W~p&SIVdiOWkYq2)2<{b&ZAHpgH_*29YK?UN?&drvnwkfwY9sAqHDMIjLoP%z@+O zO53W8bp|Kszl?S|tK+dNOV?pn+C=P1tE=?ZIXi4kq?v+{=WE+v+p(c(BiVAke$RIJ z&3Y}cEM?+x6u3vy-0SjgK)Gp+0jiWyPHn*_lqJ z$~XM*JC}A?n|dz>ga`%hFe^*8(yx~Dyq=Hm-DzIYYx+sHaQ~|9^+8B%SM-*Z1)twe z5-JwB;}&dSm*JGVA+0PZ`AkB6u)$|m%W&}WhNt}t(v1t&>t)ddx#pca2|s#?fgk>x z-v{nrznjukf6`Yk4c2cD^7`GVaM`k~xMeS}U+hKvkg~EzwyvzcfBov9TXPDP?2J+?aUPZ;vw#KcsY}6e) zpI?#R)p>rAdG~g9=9`Ljm3v)yhGG@{H!?%LP!_5&6~3qIy4Gr6j;c*nFZ;irrvf#>_k|$^Gu9i?B7#- z(t)cAMED5KiFyb8p0f==OH%_k^$KRAX5!1l2&&(+{u+~JF8;%ev^1w{uBJQPOdkFi zb7RY7H?bcEl6Z|ZlbIF7@(_doNmV!3T$VCu$3%6B4fdNxN<5VWPVaI3WNV*0F(WlW zvRy0b)llBne^JpHm{j)UG6cDL5VXwOs^mCP{=-9OSp>u-L7MKkPh*?baUYv|2Fuy9 zX!4xIl$^XXv@rzbf|PGyO{-&~bb#Kao}x@75IUiR?9;<>4Ef~F)V_DBlNsVkkSf>< zF#$?HTyU;#NBAE}3U$NRCWQ@+o7$>zyV%H$LH>1y6Vn(-o(;rH15?>G6As9enP5?o}lPM4A7Wip@;Dh{7){B7Y)aQ5Wb0tjbqV$bGBQm-IXc--HUY z61n#wt7T?ks=)+t{_)795o%BQ9L7tP$BJUy9QuCQGblwuRL#xfO#E0Jg5!G6nNyg! z7*NML&s~*Y$>^SJwiS`v>AJABQo(O{xT0^hF@A&MZpD$J2_FWzi|lh?2R2Wh%ojL@ z`8klTwDfR#4Cdi&>O1~3N^a}n9Gf=GDWygEk$X3FfKeTG(0s`g)+?vGVv*q0PC`P} z>4Z+uDtcE1It?;WhZal{Mn4?PjRB1vB0$e4vDw4jN~;l3zXN079@gjfIrxatYN1UX^9^9#bq;`h`9|u53vVO#Hf|o0-Sf9ndhf z>r!ghuA^v#JE~avq8rw=8lQKh<4%3cmP*VpRrT z?NaOIjw36f>*%xJF8_G*NC8o#jn?-L!v(bWLe%}9Bk?fkqwu%U{7CM{DP4CudJYon zd(Ik6*UK>q2lJE|{w9jSuJV2prBp4L>S2^xNumK@vG^%`D-A`bR~_=51xc92Ikc8D zahAWwS)Pou%#MRcVNdv@Xcz1DgfB!va%jP$S5a9st=C2n9NCDPG0Ox6pP|!K1DxxN z+MEc_W#rC8A(GaFe~mA^C*b**Mu!f62^ZyV&nYMOWt6VZ@M&}~7E4AS>lZ}+R6dEm z<&in&MdD*lda-Wsb!m80E6d8+h?e~?^d=WGAMR3e%{C7|&PAOXV;7xJ+@3CV^KfUQ zwjwm#6?GRO+5mP3N5_!cg7xwwy2_6zrr(73(^ZP=%W#d#X`zp+4pw?kN9jdBh0;>U z(XdxSKDN)tu|6_zY069fCogYKx(Q5fAGqcZJIOKTaMv;8Cb04jBl+bK>=m-=Lr7sE z`TGPX0-!&HQk39P`81?u%R&xAkBB>FiKI}3jz|u!F(z9g_u;pA<-mD`PSn6pC>DU4 z5P1gD@6skT9=xNH1f57h^pDSMk| zGMnv&`sLzX&!p_F%4IfZ>hAg@E>KeTqDI3)ZubN(Zv87dZcy$%$km}dq2xDFo_&+U zl?B7p1bVA!3{|(wcUzC|4#_t)MBUWh-m2^39AE)>xQ{1=ZvnhgOSYOQpb4t9G|Nc- zz8BB4u&7Z;_R_>WQr?mc1);fzGZ%G;xAllqC5~}1Oua ze&@w3QlO1JyDrA+LfqD{6YlZVP`my+E~=&6Ef=AL)c-1%b}@^GY9kHt>b>P+hj@FB zct`&SAu+@2z9GaPnB$MU{0)9LM;djyf+YLP(GUzmNh} zGMU2Djk_jWVy^jA<)MbW8Xyw|sK$o-I6RJ3sPMxr`lHc<9^05xzGFpPW3=BgLmhX_ zxPi*mEj7Ah4b~)-qnoMRhNyKD5U2#370XUd_&J(u_cunZbGhf}kk(^J-t{zhuJ^a} z&*IoSE4(P)#1H3g1f$1~Ll*#+CxLjK2Z3_dk}&Nvr5gLO#|xTgW4A$aV3RYbEUKgy zLiASXI=2xww+Cz10@sq;=|OsyedjM3z$ykNF7@JO{{{+QI}kz^Dk)Q zpJW?tg9i8gJ}e{9sU$MJKM`C3=29hj=uHYa^DN%_Lih~eRrf!b(l|((pzVSgqN$F6QBky&<4L?0AI6CQrc@4VJjRTQH8D z`Js|BTX$J;1*0WL5WbfezFd6sw3KxD2#wW{!dTw_25%i`#aoE@PUoRpXb`F-ZMmc= zEjM^_i}jCL8$f&_Sgt2VGBLIAeO`~>Cj78oLq0+$ZBw~={TA+xikB64s<$`lwu={) z@YjeHGl-rUp`7AwAZ~dAu{I#cpq!1f^!sw0cjYMbkv^aPbY;H?fdi$(I5el8WxdSJ zx7x()Xz;SL@1NH#zlLM{S;P3@E-!H*TGeO@N~`nmPk4#WS1_%74edaqm+^isLqGbmYaWv}Ojv2${ksodgYYD~0fRmCDLyLfHFezlRAIM}zZdrHz2}6jT}v;n zx^nK{KYjl9|GebHrwBSRH?c>Yi_W4`uyt*=Jyq6*{ zWBwLLyBh!0Mre@U;}T2y#8O$DO?`F7r*ECjigV`hd8rxp%LS5nZ=X2txMa)h5PvQ; zRfoi%(SuSwN9fu(?c|M_kAq@NO_csp9ryRFlr-1e#KVk~Jr-HtwGBI*ol;mlH?bp! zrgyb{4GOVa!DHMs*Wt31rBx`JNsHp(&_9kjT%A(iFgH=kRkNlII~+*az7wz9)&I(| zxz@!}!JLkQd2RYf+q%CM(!PcIuUt^#D!8|&;OA_?&rUg^hb>q=QbB1)!CXoVBfw|p z01BXIAafJ?n zo=={ksNf;d6>%U@OA}uiCA$O02-VZf*)aYn(w$0Ti@C@&Ttdg;CJJVepOTgI#aYI$ zCc8c4H}n~wa2M&tx2pHrPYk1H^zO}I?ux6D9QoYxkp|sYagj8rKA4!$J4voPhZ#uW zhDWOX=4N(j^PP!MUaz^+M9m=YG}pbKh2s!G&C6;1xI&r*njAvHFLxtZXFO!2GMHn| z0sbBMxY(yD_d&~?Gx+i#X3H@1E?3h9UhD5YPvrA{Ne&|@Xbi`a4pIAhvL^@^BT ze3LRg8|V0T;OW{NhItKt3z6OceGRF3gB*C%d5K;CP%-W4%JvJ2!E?+=?x6j`8C;$~ z>fSju<}_lZNJ0;9+Er}eN9?N6@f;O1aFJV2r{ckodOB5#q`4d;0q4o|Q&(%56fr@Y zdlF5F|MgD$zZ6O8;j1eoYtP&O-++MNfev=@Pl!lgkQU!v!s=CtK;V7SO|uRpG8IX) zB>Ua`3_e+2T;!S?s8hfCoE)R&d=0JQ3u5m7{sgXuAW#ULCT(gluhTP5Xsta-!c?Hn z`->Ozj|0ebNvAPdgj3Yraf>@$f1zn+|< z3ktDR(32<0cQhexSF#A{rgNo+NTu`|&cBvdAnIX4cGf^7`)%IWvDBt=^nbU1C;p%1 zrT^dUd_j?$Y~)q7+x8c|8HtEp3As=BOUBs}opsoAW-a+k{0mmjaT_A7MF+gvD;6}Vg-x$)c_VN45 zB!=0S#M({Uf-2X0kAj6LSW14S7EtLC zBTM7=J>t?b`^L$VY15Q)EmN!|(CLLvG6U`ZLgxhUXzR{Rat+H=v81{d@iBy&CjO~7 z4W9(1U>YuwNotQ~5!ScTzg&N`3TjOU2!nqP!d-#N^va}m`ce>QR86x9{7#2&73+H< z#4{ht=!TMk)&LwWC2ZWYkmkpd}FV7(bp$twNtgy>JD*Lk65Dy zmV1IKm+}&*C_YJL#~AtL-fU_&a+UR6N!u@2`m`p54|+)7Sgy6y0SO=goNNCD?}Pfr zW(|&ialA`xsw;=88lPOKUC*<1_gCTO$Fg+7`c0-yRdsE&#jCED!3$lXZCN^^Xz2=s zsxvPufEg+W(7X>o^sHlH&!BzX0mh;qUMNSQrG~~zIjL5{2BR!xd-UQ#r^ zV8w>3j9@VSQ=1Ut47Pb>piS=+w9P!)=09V3{-D|>pU!O_(xyKYYm`1Z6zd((KjF5MlAUq%$$x~DB*pQNl!ZTzE2)C`5+Uce z#+7v77;t;Mo8wAcsybu1k(4xm_``d@CnbFv_1gd`DOR7nZ;~@RDFAsBE?P7Rl909< zOx7E8y!eEk3fxW-si6t)HeyM-fMfkZqpp?0cpuJz_whS}pLR=hx`1CMev9#|#cvaS zHO<+oEaB-6UtP%eOpotbtYGY|?Dqx4M4YZy6&H0kV1Xs|_}1>*4z;ohlgW|TofSmr zBLB>N2#1A#6+(aBr;69R4?x5}EWE~!q;6v{PGWU=On0c76(?HKG(bb!Ivl*`xDq@Y z#NC>_uTf&YkYF;gR`x@no zUr6klkCek9N#rd_h^@w^-V@Fvo}J1(7BvH7B!+L>*BH7$-)qNvvN*-^h+b~K=o}lB z#9KRjwNQiIO7C5}SW9uAOT2a4YMz;UsY;v@KQDe6j8jsW@802RybO?em6w4xo9EL` z0{I;F@{aHC2WW{(3^A#QAQ{RsfG1tC_$IXDpDRh2jGdizp!eU7_DAV5nJ}@nT#a2LD z93Xrguk)O~j$KL(cyqOjh->^v`Ry|QyD*;ER_q||)Ud-?;zD4>QZmOJ!wHZ$rdrJe z5oalW@Oq5kfSsM!C5gx{-z0Y->Hd*c63OPK8`l_coDjK?A^)P^QL^wC zdt{N3q)TWNyRJj_QH@dz*2Pg{=ntl*}vBA=P98 zcrL@wDTh^q%(1ZZXl2Fb>+-lBJzMuk@wiW9jbM4eh}m-@0&Zp69@qmdzf%fjlut~C z$p^Ma`GREfK5Zs<6Raa{o+4`r*+6e1-FzuH>M^Qf^_;p-#AmNtS$@70N{_uRehmBe z6!N#f;#CkUvN*#2RLOV=U{>7i);LU*`&6^NumXTqV3rDXGD!b_2IsvADE&2#ZFHs9blQ4VWyA z=c??92rXA~@3|7|xrS6t{c~E&#*FyVIl3ZkMm?nPW!%QrT!{1(^5v;~`0lB+WE2?`9#7 z%!;i+au@vzc%`yS2qfb`&Rib$am2Oa>`acz1zaNWe6+A!Wc+SiwXEo9>sU_(IsOqw zhfyyc^Qb3)YyU;{_@L)ik53CrBE$nE;`QH4^vW*G02cNh`i?!>9cld=1&3?PG;(#z=eJk5NS@0T+ zKms9Ad#vb`uU`V!{V>E)6r{OH;wQ?@Iow6vSwL;gH;Rie z>9Y?x^-RkL*Yryd^6HF5QgsG&ogWTID?GOZ7{`B0Y-W1EFVTb5^XS5b#CxMMxbG>Q z49(vC*YpsRM@+z;LyW|>V~_UY*M^^Jjg=DerMB$3220z6e3u3QyuPN8`R+;f03@+k z#2SrD!@~F<_NmwE1@|KY^GG#gP6GmZ`&wMObyxOHl2Jb)X}l{CoeG1f>*%dyOD1=qL_u!KBmyGtAiSO>+SKFe?8%R^DiZShrhwrZlL z>YZ;(E+!nyp>fF%(r@!cX!ivctotm=TWc2GPs(GNu1JQ=&ml+X4v|{MyCRh`zk{^J zk`K6`em|c?XewU}?|qXTjW+Yq9dCCqTj{QDe&~9>gRFR)etQD;7yHO#^f`2bgd(2; z0sfk%K*GFy3Y5hN@(4}xMl4<2xaW96(R|4@|9-M~$oGrrv&%lME}c)p7G=ehkeKQ) z0!4I)W9Sh*i(v4s;MLzdysZ$p0kMBGK{8H|lK>Wf2VkOmOFXe zjPnF! zuP$tJ?)+ZYdu1K(IUuKPXDI6lp#PEr9h+D6!qG1&)sGDYb3zY~j1)*h@`0mDD)`hD zH}N@hbyb0CeiUzL$S!NhE^o-LsL9??lMVJ|K~>?b^6dNN><5ao=gWUMNlIz8woIUq zbGmmF=RSoyy;lmD+Oh=s4_}ZXb>0_iBgFu~#|QqdIRC0}Uktu*mgL4>;M5o1TeC}X z{#oHZ8+_p#k{x>if#p%d-)H_=alWc>pA5cmg}7rc=t@H8@W!7J1i1f>A|`iKaocbx z@wI<`H3meHd`&+Yn1FHQD>d0a0XLCTYO;RPep=lWUJ7beb!3yuN2)mC@A$3`-g{^ zE3TJ|p)%4-muoA_8=bFQCGK4|jiti`*+dgVe*L;SkSyZ0@0B7Bm6iOQzU}N$Qs3v3 zq=Kb#f&E=OIY~1+3a(2{Q=t0)ijRCmGssQ5Y^fI9*S0G}+Er4O5dJhugk3hfB^2)x z?v2dg7APcjmn@V}Y>lw8@~_HcqsoPqMQRqJb7j32zm0#tYMwwrO7MhS6Vt<_)Bi3-*-H`G6rEXVGyMI$hg7h zHX_hx{oQqC`2rcE=F?$t1B9T2(6gQc{ zO7iYb^bdL)xC53#l_ZNUzZ8f3%C*u&XYZ8`?+!ARX2Dp?H4EG%nL<x!;08UhWqhpvr1grPkr*XK!galrt?Vj~XN76JjF%ye;8}QMgE%zf&=336=M-<)3)pRO&*Wv=FYX=J&Yff1-n*xJe=YR#50LQ~L@_ zn<V+I&*K%vk(ZA-ib{r22|8B?NX`y1$1N@c$<) z11S)Lqu7}g;#q0NgWmss(+5prQna_NEQitv@&nfooPoewcSd1y{v4gYbf8_v|2W!B zq3bEKj;De^h!;;PxbYXPmA?TC#y?0~px1P;6 z&gD~6Zh@&v$P)+NqP#_@YDo)be;agrf~AiZd$cZ(PWEti4WCooVhVr5U)(kV)J;p8 zT}ysN7k)>p(DPom4vKj+cUB@Z zL%v&N={Cr?EXj#hNMNVB>~0}#y(Jye;upOi@RHAthwxE|h$PYOTKpou^!^Ol4hx$A zL36kOwu4zj7NM3`wfMHu@$b$rELokKoadQCUEmbA2z~=NZHMT-jlHm^-*z^ptG=&_hgu>3a?E&EVC(sp9meMFL5RK_6Sva)T>fQYT#%fiTyFoa<6p+EQ?*N3VyB;aF99c_CjOvEKBh0i z0uIsLf;^ihtRA?5Vwmd24U`6hn1S_aycf^-FP)*vZdTk9P)~-qL?Z9euWh3D8%6Id z6@e{bb1&RfZ|t4N+An5qDCd|3yW7`o>hW3$R|z6(M@;~r<$=B69=vE zjPrRX=d_1>X4Yq7rF;mK3UQsM$;=_r4z$49^W7({?YZakh*YF;6@lL^;D^s5C<=*Y z2>X&+3e~&Maw#8S+}B7_0Y8q{26Y1)!jR!?59621LhsL{wG_h8xcY8alpiuA+OSuR6y)UpqSv= zyGgz|lg~+kK4^H)nMjqxXg|U^_kz^!)j>drZ1Owxb9#pgGkEemP2mEeAdb%apqmrM z3S2X&ZvpL^LuQAjSVyXKaWy(!mbMj=3RcI-I&JJ4X6e!kxcRBkG1-hD>sXoz|9OQM zYIK_F9Ks-(BV?Beo-Y;uskii`v4eSMXM9X`NIf3GDqdCEa4&PFnSp~Y%qHtIhkQv; zl83@7ab8vk*NL8v_PA8sB#Wk0mM=3@!pNeCm*kdFWmDkFs=Po~Sa?r)pc*$y#RdA1n552(USyal7;iRywfN=YSBl?4{I=n@9KUM( z^aAwP=-+JETI25?{8Sn#w*Mk>%UR`shjE@&NOlaYyxsYgA_P|h(3xt^jI>N4E$xD^ zf4%cF>|}DAn)@WIezOY%#QhcCUXNTS%}wQ;|56I)QYZ>xntL>Y0_&akq5pRj%V1>s$qZJ^m~b2ZeQ7+zqQ3qp`) zYiPFX57mPs{DI-^z?~2)y?hFUNCpWXOMrN5C&fHeuU1_JUYo9@nF`Wf0i*YJ-3grP zxb(=+gU~28rnj#9A1q zE2+|`EhKuU=*|E)5Fkhcw5H(^=%JkPvq!#O`iI6BtOy zwHM=uwy7mD)zDG(t2Gp>U8c*?3in}k4dn1Y@Z7~7P;gP(mUe;k(K7cmT;)SJOf3Oo z!tEidsLVLj|L^sJ0R2R*_inY`H-1#_3ANt4htzwF<_xWO{Qp)j?my7q`_y`0{87EC zblZL3ka|Nuu2=rw>fNo@`>W zQr~|Pay@81xb~-#P5l+bsBVTqT&oxyV^$0-TL7Wm_8&+I92yw#lV|CNE@<5w+vw%> z1yZXvVwCv;S7dw}to-~mV@An7#L6t^zjF42y?xVeq^1j!Y<<WK9fTNosG z$j3S~tr|KdS+qNtk{RT7`lKh$DR;0!vV%_x3j7T3mIS>yBx@*f3=$divCPOaamkQa z^Psp)l=NcqP=uyD!&x#`ZQF=+>=5|D z?4sVxfj(1hhL8{HZm~X_`ujYb80ixXBB-kdC(GPpFmo>^xXpUeC1dvt^iPH7_xx~A z$O@?gIu^S{Ho}=Hxk|;?F8jz>$NDAPNRxMI3)Gj$yZ=7_)iFM4kk{5iD@n8I6RQi$ zNp6ZKlPGn8VS}@7N+4TyA*G7-`XHsx0_#nFu^n0ZOrAZ?NZCvbrS#KnL;E~XuS}gx zG~Gy&)q13ONR)mCF%s?Xtz@NI@7$sFrmOYN z{lC^*4%HgDDUX~|>wQD5_b#$Pt#|RzddH~sF8;sPD><7`?|r00t@lN>-d~U+wO;$s zdgIi3?f+}Nk#tCr;Bp|8ik*J-FBtvcHdNt1K)Sic*=4%}wl*b6xSe;|C(HI*!k;PE zTr`m;+nxR|l{4iu;gap?-mev$Mn-qUe_1(!t?RN+k?psFO#V+>6J7WgetzMcK%=SA zuvHpTu3?yE=IRPnQ6`6a@&uPImnSe+J#mKOB!x?;ajlv< zS9t0fn?tf|EX9m>>KSQ?MzU-1?7t1qTFK7gIeaUgImxcWGe@6wQfsO!LSeCo!a}kq zOG}bj{vLMLJ#=jj^6_$03!03%H975UWlv61tP&)n4^wcfu1%Wu!zSHM9;6wa(D#H` zuPIC_)MSBmE=|5e%GD%v2Wj#U4%7S8jK$Q@uHUK;^s)&T_`oZl_Tv__t=}gJMcJyi zAt0~&$wd_r%pW*U(qb$VW^>>?$w58nG(Ao9u%&V{ogywy#(;-9hFGrxJ^4SUb*Ll; ziJjJ{87^43ISCyy5F@y&evFcgx<=slhT11E^$8t5W5|bVrB)XFZ0OgvrtpL_jWr42 z?x7B5>5Yd37YMLVA?j)EFxoXS#6q9ApC;H=xgsT{O{v;EPhQa+X!}8xEXKvz#B#Nc zg_cD=@~Jw=9F?D6zRKo=WmMWV;Zq4{rc)uW(>K*-b__iE3li)a2m<62 zWF=c1sj#k_W0v1ulSk$eKF9l60?=E_v3C6qm7m7tB?Neu7|ecnhQFXz$fs(^@90yi zb^zwTCePE1Auu2LpT1YmYX|-Q=^uQ5gt+#vA!~kA1@pvZw4qU#8>Q2z(zz76Eo?f| zSUwEYBA1o`t%{wAr+9s0&)CJAOsxHtNKmr>1i+3YO?{X}$RF@mPjDp?<*{e@>$#E| z013>$_aUyN1A06#gFCL2xMEKYTuB2odT{h7b9bQ}Dm^f*+Q5~#Vo$$EIg}h=N%|sJ z(x;>LPTc)mNikG<@Ls19VW=;5E?o1!5|5f-24j2m^;-2D8Km!L*I0C;}116VlSQ}wdur`QejJI=CrYl-cF4gWw17~hF}jydqg^-%Eq_<) z!=cnAQ<=D_i?jJU)E{dH^$S{vZYUE+>)$n4{~JH3fBO&W56W78M)v;oIym5)I53tN zA3Ok)KhO_iFsUL8Sj?IXOI_uP@~%4Avj`vlsp&v2zYs&`s#dGN%C$DrSx;i zv;AMk=0(NH^eEBOkqR?lQ}Q~TD+)Peb?iMV37_iQISbGjCx0cW@qVC!HJcbgL11O@(~GkOkqT|4@|Qz6KI{Ds6>_6S_(%31D@> z&q<%I0%~LeGeKTjQO>Rr7=HSMnkjsJTmyRmxy^7?qu2C^nm$omkv*)g6-v@vHx5Ss ziFj%8tnYCOq^Xh}8efcMCx`Baufq<;P_tT9Uql!_rKBqV6bE z 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 z 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user1.1024.new.2.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user1.1024.new.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..4299e904f256747ee0c75d9bc21b7ff06bcc9065 GIT binary patch literal 427060 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 z zPQJXlfpFN2_zn2vsf_t$_!OvR8z0B#bgI_-!0+SY(1ZV0=h;8WT^Xm6+6ok{Hzf`|pATE=1pZfir z!ow)@-|F|z6&@y;pQ_)33V#Ceztr!&kQpK8@Cssvg0qeCuFA#{#!EAHXdY04WeIJ0}9@>${M?@g&l8N zYA=&(f!O`#2r|S&K$wAgLcT;thoLRNb<~F38Z&t*R03!G8G=*bU+Kf?QL9 z##*qHh;7SW(tR=V-)C_~j1iMJ7MljU7fUhGI(2;Zquem2MpleQn1@|{xq^{Brx>F@ zY+ZLU%dib+Qj(}ZfpB8rWRyEOs6naoq27WIbb*-FfEu zjTW*Zt4`=RAnN$bh~TB-@)_QJ@ToMzzICFgtC-ZFZ)&PC42sRqw5$uQSPRF{if(=v zaA0^3*|@{;3n}NRxo$&j0bMDDWN340qwO^1M9`;sVWkEG6i8*U4H?WrT6azNk#G&E ziw6|(M{Ps^Cep^r_y41f658mOpMr8l7;kK0uVV^2?6Pcvk;!ZoXT z#B`crk?$^({s&0dpfjxQ>t~-yuM8)|0a>y zG-qg&nekFLwPZ`1Q32cEb=$&m)=9rY+LI4p0;&5{=@AJ(pdENQ5ooff?yvhQ?g-)vJgjy~a;fS?pn zrk8`vX`I>(p=J1=k~%cU>^~jqPZk+&4x#%fVGxi(_oNm+J=I_uV}J{hKW` zUY_RkeINVR>4uNXYUbnQr80#0P1sL|+Gozqv;+E76irSz=tM?N`?YaLfN)5UlTdb#%^EnyM=9MLeZroy; zZp<~yLI?z$o4wntn;C-RCIWA??^xY{Hlzlx zhak9q2SPCefsk7WaHFrk&X{l;FAxN{%6AwX=KL>&8ePA3_oIM-p}}>0#1IIY|AdhB z2_Rs&ppHQT;Sz=vx<8uU zN$3m%4LIZPkD<%d3Eq3<`CelKDY=6#B_(Nr>XpW~jI|x*+OW-sTt+w-G+4=fjxHhh z!#3yl>Qju&s@f4!3h49$D%|98x}Xk|O|8s$=2QBoq!@`JsizTbI-UL}QT{HByvYslL3nU055b`FH2m(dO9Uegp}M_|UXH6baQzngWb+D|KZM8=j*qe)la zGQ=cW&ipYfD*VXRX*jPkL>Qu=6wqQ{djt*|fjBynL;*s2EU34K{x{ua^!R3t~hM{reIcF(FA*IB%rZw#N>I|J?+7#B0O&HSMv^@O)}Y;jteSEVXGzvSe*y z>cS{+UWYcV!5TMV3$rFQB?9i?H<^Ztv_QiW-6UN(;ty~qpMmEp9ZITzo~ZoO*rzGD zEdfa7YVE2+mk+LpExL>dk@~EQ$|)whn@F&x6Nap5+E^I$HH7>_xw_)&-wf25KN_PF zL6=p*D`A${nk(gpvX3JI1GK&T0fipy0{E-^)hIm5-gE_dZX^S zSI+L5HtAIGC(yUv_C4Bq6>cxe-tU$Dh)6N+P3Fy*KM8fFC#;XyH#ygqF0EKl8!@CEzbI~#uT-NUmt4pcn7?cw`h+A(3riO0g2 zN!dl-nY(EGTN4W}0gaiWom48}mP z8@4jjN|`$c2RL67H^fZ$Gf4WwRWOsg0vu9PcaNLHjGIkfFXZrU1#=hG%aNa%cqV}v zXF~qES|&+gW|4$K0#`fEjK`=tjv04%%eeXEdmGmxFJX9V3lCF*^pS+@%5mT{N{BzF-Yps?ADV}1*OmCf?4qYTd^JP_8R zk8o3TquwA=9J2dR0nRTkLbf(PKp|0jF~=BKlL4tzT997YFtO1v0buY3k`&=_yo6^> z2A&#F0UNj$!^{iO-ZJhHzR@rVkMt}k#*hYAB|O^4XEqvUob@=6kKF=DPD5h1VIk_JdPy>OL?~%7qCDwFeh@x=>NJ6g5J)aM}UUDS6}Q1@t|r)yayFK?k10-W_LPijy~WpV^6loYZmq9PIK2O z0=g^3;}Zzzt_V-?6bC4H(sz;#rV#%leW3GQ`s_%nS#K6!_2>ftEoum8ak>Z35zz5S z?kBc3i2{3+b_-&w;Csu{BmlDSkOxi#1oB&~&*1SQ?c7qS>k#KX%zE26eOqe_{oY8u zpvQdj=-U99Yb204#zQp`$PSH&gkAMj9L4U7c2HtH)%=`i5B6?S^OGLr@d9Mub8Pb~ z9ye-PD*2w|+)uIYII{iTKH-sF)!vu0LatyM_kQ{@1ih~p@QsPdk zglc|-MGpgX&7V9D6>0g8Bj|oS2GGra;=G4gOp85bJ6$DINtwPk$cSBAJY5t^sDLIu z1e!#VNzmFr(BPFYUZ)PN!5m0um_8{*QfYxl_91kJU6jx+kQ8|(> z7EwiJeIOVi`qp`T6dP3G`ZjwIJSJcARg>2NT6}@LUPS2YTFE9+;w}&W%MpSmkT@iY z_p8;w>1G$_eu4!*D=93pB^6?Tw)vhEo5!I`*e;MaTWX%=8EyjT=6sK&4iejgq)XM& zF6!9+CR>*0GkFBL3<26UlRN~h#Vk(BVI_(KM14Qi-_%q`Ww8h4nku&Dg2#t+f$%h` zs<}q!U6bhH6oNF;LH74jK~GN=(5AXP$Vms7l*7{nk}Q>|54o=Q*{)0uJ}o7gdAZG- z#Gb02%spjQTM-J)^|7ZJP0yD06uZ76U|m-{00^+s3<9Yq0HD(Mp3Y+G1FrqFn(+E-_0fY|REyeAffxO~9=w7RApAVDY;#z*jxNfY{mA zbO(kag8V|@bGDjb-2&C-t;oUU_i2qgtlD^J)+ua z)LfAex3J61o@l4cVyC&tj5z`5=v`C}Qq-(wUB|}|uK9`!e$568xz57&_ih%g>@=qf zorRzpAaf=H8C3HDA&Ug~CSGzJ^XLcIB@+0cXtq!}5``RfB^HLafTK1QH}aC7S94Z^ zK?T%CBKM|Qlun7Rm)H_B7ht7;h^dfHG4dV2sz0C)*ygEx9@F4U(h4-#HIEa)ew(=d zrq8@Ln-28{I@_A>@$@$Vt>%XaS|B-aLY)q?m}lPDZsivNH6SJ}u{h3ofEdUC#QIcL z58W%j$j>iwS9#dmh=Ge_id}xuTgjGWHmi9i5$#lt_2zlf1N~&!W3iId&hYlD_%CLFpA%gS={dhm0LO1eeBH+_H- z36hlLA%om3QhEzmq+S_D#dl&_qgr%OIB6k90&ZcLq(vix=rGo_1@5aJbvnAwt5Yvq z8sZna&yZP)_KHh9-t#P}wwUWF?&C8~ue@2Zxu>`XUaZ~xJ(!QaOc8zN=hIQKNuFrp z7dz!_2!9axMkPOpfI!m9$3h&$5GB<7z$4|6?3SccJ|+-=A4bv%8W@680KLHhr0f*2 z7P`-|J%n+d*-HiomZNMbufXwx$HY&>+h{|l*&V`BdN$8&k~1Mi3=cGii!O?-xgs`G zVmbw9#e|#v!6YhaK(AZF!;XvM$Uv+CmlFv|KsGcK*kjpk6>Li^;09Do9I~1I%ad6 zk>xVE)=YuVI*NSLyyj-!y-7+^=J4>~9D>l`VuH=!Uq}*JLU}=~7qECXn=QZwD<-NZ zxiFEc)hpKWnMGz~M|Cxcc0MzyN#HYU>Mfi=hA$lZfR_z&OP#pp2>5M%Af(0DJXUGa( z%V(jInmU3Hsc@;}E%E>)THq}qEr49csmtCVNAk87trqXMcm0FX>}Gl3{s?~yy5_Mq9a)D_k!vPAWQlXM-b_DrBRx%T)>rNMjY*a;y-#OR)y)64Y zd&(fAke=kKzZun%YpR*6_gn!sEw zU@DD#<`6ISH}&yLo2n}0yMix@E+iRl68AJg9DbE_t7yiYBi)J?weX7o3UK=Pso3U; z3XAVRycsD$74FEy8)({aYg1EUs{$z!SVGo-{M^D%1w}B(Kr7^;29_8xL9hvRH3Fg- zEPXm6got80?0BDzqw!e$w z^X$%IZva6c#I9d?N-&Cef*%%N2>%d`K(3+H&4b<}bCx{dAh%h&50 z^mW)lfv+sVv^&vG=<==w*|hOE>XS+=R6vBx6?O!js}EqVfcBIsbYbL|@=Ho6C%;4= z@XG>TV)!LwbRwDv78=YD@E~k8#;GD&A(#~&1#%87SDQS|>YN3Jom3Ik1xal!*){;h zu1%cde%4XO6_q*pJ61e;eW$CatccRXIQI?)ObQHNL;4T(0YkiFqr~9PJ!{&5VG$Ml zDTG@xQ-VbnbsGY1H^;-s(}CFF&j@0J533awNWccnFR2Z(owryVgy0HpoIt*VXt<+? zWK9IUH#}I?P*qI=$6?D^$oY~zt%a!V$lB{gt6B?NA+WdbvDgSX1ku+?W(*cg0dwdf zPf`GwVrmHBV_?L^A~zknlRNMr_CZNRQt51Kk!N79iXvbQ5d-gnYGAjWO+W|>Gq6D! z1U^)W)!YaCED|JaKqk-Xv1Y|m0nDsBJF7r-Ke$kiDmkiUq`x$z7dr(%zhn>iXuK~< zq%!~SkVGL0Vyu(lgL@Bhjt#7%io>cVcF=Xs3vd2U%|zOBHj&#h3brOCB0-Yb_ft=2{4i z!E%AwU>l-lScdqlW|Ldp_y!g}B=-&xDu@{pF}46GCl^oR2m@mL&>K-pKHiK_j$= zv#O0CQp-$iawIGvR*4$)w044Y*z}m4q7RGscVsEUj*hHjM(#Qr?6;6jbzM_kt(*r@ zvEHl_7|b4v0tgIs0a!Zl;hy7ao+a?|6w9{Z;qUSk&?L>uPpRPZr58yjLmI$4jeI_k zCBaFs0;mEMSiM(O6pU@VUmz30tF8&Ym&87Pde6sV6D$3~;(7%9yOhtjHHqNOt{vje zf#ye9JpusrH1)}ega0PP!lE_0Qk-5nJoq#b@la9oAGw-ZBHux}+gZWK^)xjdaPoOQ zW#GfW1``ALVKEw=N!X%bP+_hC5NPP_AvDA~0<=Jju42*sxuu)WD|xVHK+GHPtrWX@ zEZ#zv>cs?};VTre1ogsuuBWi1aPTYEwSl08A?i?7C-R(OSExr)IsRY{C*@;l=JW$r zKC%DHl0wAQAj?V)kSek}`9y(F1ag=gcv%ueD?gPG@&S*ea%E7oM&0?>^6@}DsZL*q z5m^uEV;1nX{f>xsXbHF(c?`3*UM$&+y@a2?3nOe;oT?hPL<*$ANm z!UGvk5uWa0Huc62Oa`VL}o3Y zHroab{?j#F``P&A0jw~A~t(XJYlI{0j z1BxJ`;~kFF0&U_y)cvzX68Id)0NdO$rmA@pThgXFpwWcab0Pl*v4G@Y5_9!s(8i!C zP!Rw#*YC$LbG=N+NaRg)71R)*?P9U{1xtOQi-^~vRBwSe>8lg{e11<8VePqy#bU0N zXBU~FC9LIBfEgq$8~QI>vhz!QpArh92W{VQ2wW9B$F6whS}?%%1TcI%-z^Fhfo<9O z6gYBXr5DpJKo;T;wr#+(mgj9|F}=6ua|^@;U<+L+nFo*o21Mv)p+Hl$w07)|=Aaq4 zK{PO+DBhw__27K6Du_@7Ek=RWnW=q}tY_KLw-C|S;k(1$Px9|cM)E^Hw zB3D8nZu4MFp#rj10Y|@^VBuIbR+C6!n=0rP8uM6a`RQm)*ZUUr`<$jiFylsk4w`i9KA{ts1@1SQ z!Ay(HXi)Pf9+RAkHZ}i5Z4)?5ljyLE&4mzu#HO8&Sy;g>8jwqP&F8(9WV7bgJVM5giOgGpGiYb+5RGP%NnzGMr7F1%nXY zUiNUn$s!Fxc$-axx28h=`c>$ti`JuVsGWOz0%DQ{44(ka!6=Bw%+C`V`FJb7Vogxj zd?1YbSg0C-^HQlP6GJ6W0Ahk{#<&7nzGWT>_!dab5}{U8u`iRgy+l^Yq)ebyk_ndQ zRYgl^@oXOwd;!P>2?_Fe6W7xue{{9!#gfdDrn~`&vj9yFR&XS+oD4vK29vk)3D71S z^*{&#@>mlva-m$nR<;EbEk|mt0{iOb6Ubf+yR%->d3Xdkpjmq|A-3gV6_^WjsAXa> zlch4nlFXh=EGupmGa|dSdK@ZGyDhuPN3J3o-eX`t(0nUad{kjcKy9c+!lMwFtOP~Q zNjQfD5jV*KA8ZcN8niz~C!YYBmunLthC@@G4N6$$c@V(hYty$uZ-8l&c0*m1D!W0uRLtp%1%3{_=W5AA`eJ<>7Khd{;DJpk8c(&6 zB@iy!Xn!}K-ztC_Eqwkc+M{K_mQ0K`(e<&X73KvvBV**dF?xU*gt=z*$RYSQks}&> zR~w5HtDuURzOAzjD*?(0X7MbvrbN95;o&1h#bUbzu2TRvYk%-+(k$r53p)krHL|9I z`J!o11`;fwH+>uXNzzZxSRi-f4i+b%2((%e&WbFR*^*VB4+R|%!ae|@^g&y$@+T`N<+4&635#gG+WJ<1puerN$<-l3bik$& z6+lz#0st`4deVt_A8!s1K#3}OhWJEaO_ci3n?ab>Lv#k)g#I4dJ0L!IFTn}2-{5x^ zQGw_USrby`FveI~^Yu|ZD^`_3mG^_EKWGH*uB-J8J%OIO&MJtl zkUneWm5uVf5I`$r`>0A)kPA%m3SeU8=iBAw5Jp>M8yxXl_~lURc`*grSfDP=^?=P2 zdafr3W5op}v9Sj)KszD)qmk}4DnC=i3f?9a5xLU+1dC?&AIGbu{H(5((0we&8+JY| z*d`_^(8dV73G^kN`Q{{LNM17BCh*HU+i;e8JxSE5QKk ztK#~2ds7uy(4HsjtAJ8H&PuSdVi84S(4npuEWjH->z@aw0JhjL0tm2$<`vk2WMl$k zA6ASpywcWbDG|EPuulG7Jk@0O^T~~TLA}{AAVNW5k}ddxolp8e5;+crpy5yzJ5GKj zrjdwgWRXm~%>hL_^f}~M7QM*(t^k*wf06l!-59!Z*pk#s0$8F$v7_}(x1ePve(tDv zm99W)!;AzRCvV>=V9=EE_X1%;86uB59#Y3rG3y;BxP!pKIuYA|`ZAzY%iD3(LP&<~ zHqmZK?wcGr5$bxLC`3SjKH&N*c5ncFk`gR~P}0X+_U^l~^OyBy5d6%g@*?b%Q5}@u z*gu0rP{NQ=t0EQr0~8E|F+yI%u>~Nayq2FwC|?X2oQ&9SRm}?!g9I@kmSCKt9nJk> zi69Puutd^nhDe5GWT0~ZtbmXW)#1kPiP{&yA^W;gh2&T{+`63|LQ*mzGr7X2JF5hKc_j!5W3&;TOasA>`@xm`rIbNm8BFvnXb z;;AI1l!pj+cd(8ny9+asze@QmZ1$AlI$+mI^kiUFWXgk$0e3Sv$RZ%roWM1gu~1jI z1nx-Q6}*uMrczbQ&uJB~V+Km79nKclW%S0?Tdnv^E`?d8O&)*0P z3RDPWnnPppJfR{{L_##hX6UF0QL!ihp$cO&sIu!}uxn`TQBLSo&w4vOHuW@yE8=V` zAzyQyb?urf_0M&-b=I{OgPQ{`k>()N{gn(a)QK1R1K>8m6TBP+qg>pU2~M%3g-`ZZfdY|D6z@2!96mT}nq|e_$T6LrpD@J7^t55``6=h* zSEMV@slvc1?b3x+YoEQgd(G(~J{p?}IL~DR`6LArn6Tdl^s&5L`z2NttTbR)UBos6 zOUk~__B^?#a3>-H?=0-BtGjz`d@avnwP~uWD<+{kVDEZOzOW*kKbd;ga!P~vK8T@3 z4c@2MhBG}v=?Sby}s(+0)z`2h1W;m z{g=NsCBeslEr1zlFcBe=HjY1O*`Yb5>3Tfc_5Am)m$o-rw6zvpg(cKg>~UH&j$Dhw zcG+EJsj!6DEwt6bkSLZGDoumH+~R%no0$+RmEjiE*xVNsM4BPC>4wKTzEzO!o#%|( z1&KPE+}wP*MWPQTdkL^~#i*&dTq{LXtt0qJkvrCvN>Lj( z69gr8&1ReJvR#VK-7Mu=tWr$cW|K7DSgs;8;b^&v&>aWMRfJ;qmDfslR#mGAP25qf zA~b1ZwTjT>HPv=$N^XOSP+VGriqKSJgNo2yM;lI9TBK=X;R_IaTs87s|9sou&-_8x zo|IVc4E?bD?jm~a-aC6;;+b#e+_7M7s;8J6MZ_)@WeDWrml1;R6e5{b=2O*wUWoX38Cv>Ybtu79`nJJp*vYrPyXWQ3 z$7Wsq?Z~COr~d48#koIE+q`JjLvLHIKf?cdyakS*+b^&9#bx;iW$V_gKzVe{n`-zsv+<*gSL&xXr;`~SNQ^5wBMxG|0k7?alvkC?Oa8tusy8z&^v;g%gQ zR=u|GfrHzQW?u7L*n0K1=O26X(w{!7JN-oaBS)AIMufw;Y2Q2LJ5StamnWW?vF5#Q zIodC?8$ZDLZqf|KcLE{h_NIMdoNJON3$l=U=(xcB0U?RFTno2myNE4VCg--(F#U21 z(b)arr@;Nu>i8pDWTKGFBdn4YfrBa5$1{ce$< zVQCU;IZxAzjzmw*Up-W=jq*fjMAuPK6Wn~?MV8(;XJqJ^d?%&rQTd3F69BWwD1vc-y`G2FQ^yV7M zze9v*@g7!0O!bT9-<^pQ??$L+RxIR9+#id6cI9#Y5})NV}7tnT~-me$$bhSLrF(os1unCtz{8`k6_-!^+>0c6xZE=%?um z^9rmoj9O#+_}GuhgHHyYq{azpJcwzMqfPuYlN@8>r!2T+La-MZqRm|kPMi3t3qCXP zcx~dxuh9sQDBlUfuQDOs#FShb(HbY@YKsEtADm@!(8|Ec7-$7gn9>A-=Vb0_d>PwRSsyS2|U+?l=fdg_o{%hSla)3{(C0<){U< zYb(N9(i&kIxN^Q)(6Y8MtUJwLPwg2kII-f4e17XyPdL~~*ic$uE7dgiz zs!^-3un_;-YnBVCXL$tO)85n^n6Q!&ngy@>R0JjXK5l_`=fbE0Lq8|@C3?Xz9~QmY zuXZX(LSdTS!pv??&wz*4&zp~fbb|2nS4}@}DGrWHiPW{jz#a~RKPRBhO+E78o*Q6d zPme6Ng-{5zqh^yJakI`^F03FCzD(0!6;fL0t0b7$0y;68Ndc6HLtB^-k#c%nh*k+h z_iUf;d*r-n|I4u*^u}oTA#F*qZ%M`)=t{HT-~b93$C~Yg0j#2Z#Yh|w?NAwjYvXo@ znX_)09$nI zaZMc7FswHK>#HKROwBO%E#@GjJi%_Fo}|iZ-a3(5eHd|6BA03DZ#vKl5{6~WQPt@k zgs%}r4O*kioZ)dT90Ig++YmlT3v+*v#SOZ6aghiHh%rIpOOTkMiF*(IuK13LhNle| z6Zh^8LwJigteJBO z8m2{~fdx8}M09H?Y5>;gG>oC~vt_fpRukH&32D*j+_08zi}u!WjT-HfX18kJj9;~z zJx>N6&-iO!4AmQj^w0SN7q)&ihY9&aN!*+0K`dA9pI&`nf!vq;C_-pO(V1z$Zk0(J z+_*hx+aAo_wnGkz+n7*lO4%dwXB`SmuJe{-A}%s%D7%ibYAJUiO~FXs9F3EQNJ_$~ z)&K`aL=A}ff#Rp<7hC5B-P?luwgrvb>DQHDa661?-4$U}Z8+5*#2ZNzF@vw-7*G>! zqiEP!1kZC*dXIYcZ9O=ptIn6-_NFJ;BsOk-bk(NI#=RkjK=>*6=f=Mg{KNV>8sn9T zLCod}K`Q#3jmhRI%Qa=i6-BI4X@{b0yomtoX4d{Z$Ejj$XDa;B#Q}-zM5% z=6KxF`XtOvplb2e`EWjfqaXMGh_(}~`(w+VeG-gWZodF6|NqC>`@lt2rT^pi+?hMf zz#W`H95vAHy_(M0j4^}dP@v3}F$ipdO~PGm88Xz;R@ho?KU#>5VbSM<*plvA4YXOh z?yg#^mhSE_Hl{YTfMsIRBK^}+L$dro_xC<`fT-Qi@B8uf8oB43d(WTeob#OLdCv1E zBQ33#O8y~O12<#Jrk7FmU=DM$fvCY~f&t8c57LTkKix}%M?13;CdJi=7y`73&>?-k zQBZ{I@L8&SsWc36Uk972?fd7a@Q62zMa)FNaJOVyHeT5;b$ zX`RI_0^5?doLi{PpPiqxbil5Fpf6sqt$0gFbnZA%vers$2`FhL8){>EM)ms?2iCnkzhB%$|` zC#X<88yt+6X=gTe_V^?yF2MPk6z-LLV;dV1`b4p(Md)Zr1K4pcp{F0HmA43T3y$&| z*_Le8E$5B3fK4?f74Tb5CzS$R1zmLoH8xqqEYjvP`8gl{_5_|1RDT@k;9^kPQ#0_ zY53mNnnZn2j-u1B1ZzHUsIqg_>2;Tz3_dxD$!p1H4Moy^Q*BYHZaJD+TLiXpjxN7q zV&hjET0S4m9{4H4oA_J!X}mGv%{R~U39W?BTlGp5#9dn;xp!%DcUf{;MIdciAZ=@a z5t7rS0PC~t^d*CaXz-0#9`{ zpLtR(Fp>5A+LIIiSOs67OW8DLSK3aWiEC2a?Zu)=7R`mlY1Wev9^`pI$Zo&h zese!erUoVndt_~q!MCUd7}WrKJ~M2hg2@KYh9V4N!V~ahx5e{XeEETEAd{Obs-JKC zY)|{=DeQp<8Q#$JrNS=_wMP>^>hO&XMNA=IDnEKmc$$Agsesq1R|0t zG+BcrCd4fJ##qlwzGO@bLbyx55iStH*lj)wo!x3BikG&%gi3EA+mk802hXs9-QiI@Y*p3bwJ$GQBggy@sz>SdpXE2E%~3%2Nnc& zs@~U+FBfVimB<{E^6O=v8d542Y05c9r)3_~G;mCP{rt^y;C=(-iq4@k_HG{i9k1i{ zlU_}!1#zIku0jVMeDJA_XAnS6wZ+tHCKZB6xHnk~|CEGDDO;ooU;f@OQ$4rg4GBUL zxY^Y(Q}JFeTFc^7vh#TFMWvMInMt$f!29-~&+1;-*)D;Tita-qKi+^i3-C`4_tT3= z_!5jt8;doYr9{2)OIlrIMnVV`!9Exqyd2m|_8tPd%O!53P5Wi~ES^;EN4nH_c=jA4 zq&!Xsf67C>=2KH;#07{e4}f#8W__t4-!XH@3#sbB;O5kOC|~~#8RW>7B{SIzX9`eLyb6k z^T>+LqwdH0+MG16|HEwf@Krw?A-CkfzPUG+8Y#CR#y8iWvdAq3NPQhE8!NXIqKR_~ z)NrAC*DQ{OSAXb+Z%)x~9?fmOf&Dy5yP|5%&Cq~JEEb2kMB`3z)SIM6G_5ro#B$NR z$Z7DDi=$;RDX(awPZn=r#o=3487f0!vaRXRI&7Hmc_N9XmX`p`^YG{UDFq*pT^3?~ z_K}mZR1!^nL%L$A;WTxD9FL`vY3f^Yl%}lhG;x(2Q4=R=;u>kA2}EW;F9)uZ2u)D$ zonus|ovGBR1L*K|(dpIcCy6r(cW5xUHnbdS?>yPcw*Sv|I3ql98sGT#O(bSu@^8WdGMdj3DRZ~_GSXxnEel%Ks;Oj-6a+WJ*wGL7^J5V;eK7RHb zr~hkZ`8xd$TU;&Av+=cS`2!=F)V0rVC`I#uEgEirtof!r{F}7->1y+@F7dP}<$?Lu zma3Oe(Ozh3SW?Wg4J?D2>zB1xSG5180xkRu+FDbE(XdQU&MV4uW_V@_G@S0qW9Ri0 z9LC;b>vkTwyz|}X-YjZnwL4iZur;uKYkl+aX!GH(w|E*@9jtHbHwFS5>l-?w4TpL+ zI%`;c18bMkpje(bS%-q@cJ~#YkJXh&R#hr#bR*@vjS_C^toHKKSH#{2*4G+hql z*W+g|trTx&epB(YdBq%oi;asyk2R4uOnSNDE~b{(lPg$EYfi$(UvByU)hwpf*b?3R ztYOE~i4>xh!Wj`P*%{_#?8yLr7#HP#W05cqfv~1f_r9bwHpHF32n;hEQF@p%M}eaLk7B=H;=;n58%AZZ962oQpO1vz$B{G8DV_hYS3*NenJ5dJQB}6-kHVIt^3T zQ1>fxg$i@j4bi_90IxwAHVr3pmfcnipA~!;`+4Rt1ORFF?!J22NTY!0t||z3Yr#+- zBtNHPi?w*kLu*pcR;F9^C1)UXjM!Ij1M+T|n(&+zAIU(nFds^*zAzElZ2&F8xS+thRH;~!>?RY}4|AKXd@i{nk$WisHg)Tp}+Y?!~}91;am}V%T&-ql4y2He~G9sx%l9L4;1;I7fW(3iu(u3uF#rGr0@8) zH4wU$0WJkHPI@`;kh&)fglOp3h>ldukMnjhHv5Srkasi|dKC%MA_UyffOB-a;7mnh z7#>alK{gnCj8X4ms03%$9 zKA3dcxh-Tk-Z=J0? z(LWw|uRF=;?c!A>C2gXKWY~xHcJLkVzwl0lNh_XLZ1(Sa^?i94BYvgm?Gx)Y{P2t+ zZ>ZyiG?E+=9XMga$7x&LN&?y%m0|yU`0!G)@Y~$amXCOhKQtmC2L%7Od7lkBK1Tf+ zz=`~D{{hDBLO7~Hud)4bR56qWA-MfCv=Xr1`%K*#cb5DDYt8J=F_VpSI)4ySiCID; z+B-CK4%D+5PJkA9yzOup#I-Z*3vB2`Hf|dt7B~`9GPyUAjqt~N82z-|EUO1}$PF8q zS_p@JS9|+%e)v;U2_OF$lMu;go<~SzO(0$1Zz$P!Jp(hBWjrQ=Pc`);siwj~w@tW?h&G~ne_PTru@derwP)ENXu;{Ye5sdP468buz+uz)Ij!7TK&N9p%Ra~UiHLNZ z(l;!dF$N*G^zOn0al4p(DQF zxYPn#Uaz|GLphL~^AOnRlI{(FwI7iZK|vND@(uUC1Rs`;#PDAje)x5^)Fn5t zt!!aVfaj>MvhmY-HYJBF&co1oO}RMYEGsv%*4yZ^TSK9>Yx1O67iJ}fPbsA$uC(g@ z%8H{ec^D;d=_NQ&%Hr|DtVB4`zRsf0Zl~11PHl)wNk_uJjyY|X#T1@Lh568eyuq3! zi>bw8it9NxcS>P;Fqj_9P7k>DUjwH^KK=)tf$8on=>@juB^EMW$TOI80jUE5t5H24 zM~aB+}z&ZEm_!};7wp1CtUZt8O^E-raf!hOtV z>n(rQIfmhaC5xS3k$=I?w zz}C8h%YxO*0#zR>`bKJ zv%g@ebM=0tl@QSz4T&Ix&V8QR=PqJjVjZvv3m&)t9tgOMauJ8bvl`S1h(`P?n9s*1 z>dgm5gthk^bEj@9n41r`y5vnPa1{337W!R6BI3XCEU#Oh z8UJisgE;|&J2N^PEb)WOO5>Q?rl)7miK{@M)(W1jU^*eZr~<0~0mFrM2R!I^X&f5z z^H$VrBU$W!&2aEvrPDs7i~f1oKdr1x7awi>Y1()x;dKez<`K7MKF_n=HRkv%P%bIb z)Tx|nf7=>{aqT~pz?5b(qp}~Ioy#$+o1V_e<0@+UJJb4uFlz9Rd^5$e}$F64+7(-EGy|%l}%qyvp16tIZmL@zxF3{by0y;(4;!?*jsoCyn%ukw*r@KLo zWM@N(Gi}|j^+#O$r|K>!SSz_jsgZ=7yrK&2zJV3N`w>Cnta2L*~gmCyiX4WtV zT#%Dlbi_C=tz@&wjbnjSdxc`dT4bv$%A5PRl18&z7dk>)AYz z13<$4D3}8ZPM}-DCN6|exL`$K5$U|m`v_H4GUkfMhOX>4sf0bh06#k{+ z-V}?9>jznnGhX$2itht--f+5B&N;uRg_7cQ4*Q;Cd)5Otn=Ut9IhU2_&A>uFR%tEL zXCBLfA3oRRb>UpbTItVaLcV0WA2I>xZ}wqyP-My7;XaShqpYnxVfLI=!2B5}m$#g1 z-!!s2F1XpmyF^n$@6=bdr&i6xc{B`8?A9IJ(e|%E@V$Wby!&Kb($sxL2=_|m$_UK} zxu&k%XDRk2$vy*H$J)d27oSey3>4 zk30_z6K3}WjQ(P`pg0hkp1M0KfN+ z{+$-XD`ixMrS3I)1lvffy2iq8&>Vg@gGiGcubV}K(}9ZNKw3iR5Q8nBoYb;C=D_iC zrEOKlI)fARUq(Bf)$!PsrR%UOZ6bE1)m3`yoE^3%(o8|f^R?}-?by(?k!(3%zh^uA zX1x~Jabe8P@g%Mvf|E(>`W(9 zD|*Yyg3oU! z2^9<6aSJxE%W%rwkX9Cyd?ukj*x)m(WjJ_w!_)o+>Ba@?^|EM!T=UMIgde@czz_e; z?*sR*-%aVNKk2KN2J5#6dHrrwxNKQg+_D$gFZLpSNLkqO8;5yn8!4^G(IN%DpZ;L$Qkf8=0YAC=1n?3g6T9-Z4~~KydzjJ}_149-_N| z$|k)jm{%@^A`EF0>&}dm>=T8_3BvNMG&ZnQ3M^#Z%!2e$Q*XN=b|Ng>c_zj$_U|b^ z>A+P5B76krM7;xk&)Ei`rKy3NdIhslGx23&1l8|Ze~n2q7yn^KTAI@}SJRztCJ%p% zxv^!ko7fKnNxa6I$;=93c?d#)q^g^1E=w7-W1_mm2K!ATC7wzGr}wyivbE2hn30+w z*{+rJYAA2(zo_U8Oe%YF8G>9r2wLWCRdSpt|KXvtECS+^AWe7Nr?E}zxR1>}gXL^l zG1Jx+8BazLCQCNb0#Qf{xQ-~UanmE;Y!-|O z40VymIN7-@WDrA`M-`3((iQJj1z$S&xIeKSb6FbSb`V)oT<^SG+3%87)5B)BvckE* zY4OxFhoAu8I&R+s^;c#CVngq!EwFk%qdJ< z45(wB=dQ}HWOPq9+lt8TbY0k5so*y}T+z4M7{5Vrx8g|Agb#zy^`8u}JW0Cn2Hg zbV4U+6}_thod%hxLklJeqaP0D#(>5S5uoRj*zDnMrPYY2-+?i359@RL9DGW8hL8U# zc}$fkz=iO{@uv=8os5{{b0oTbxrFKhugWrdk13Wa{X!ofSGFVwCVt(~&CFx#4rrL# zbt$!L*HJXW9aSuS(GBZbjn6yMai_jzOC@F_(Z81tDAE5f^aChlRrrXKV%)P%Xj^Zs z+?~qyc9|0*?=-wW6HaoC2^kscH>K|-EGawsdYeZCA&{%}{~lEwtHdh#2$jsl^&RTv zcB%Dp$B~uLb@bV9mw&u@q<|>WM(cZr;R4!wA?kk5k$4#NQTW?vekAwfl&(7+JqL;P zJ!cK3>*W}QgLz5}e-p)ES9!mQQmPhA^)O1UB+&q{So{>em4>3zs}A|jf+Wo199qkn zILqJTEKkN+X2-#!uqXUcw2O6n!WW_-Ike!>tEeoR)@vgOj%-BDm}P>3&(LYA0nYVB zZBB&eGID345J_vozs48d6YzXYqeF+kgo|>w=aiHCGD_EH_%u2gizTCv^$Q|@DxXB( z^2i+XBJnXNy;wK+x-`70m1X5@M9cmcdXtNp4|gfKW}Al}=b}!Hv5QV9ZcmrGdAPGt zTM-)Win@ysZ2-H2qhrWz!FqWTUFAm<({IB2=_YcSWg&;5N5mboL{cb1M$??=SwBju4OCcf-xMU*D)x&qhjeKYmU=G0W)c;zgc$VA#qW`WE9 zTDlv$9gkR8=uUjN>C=A`Z=x=B|D`p=;$QS@O&&6TKAhDFO#2n3C!q8NqI@QA;1l?G zTr|_GyXxxsPd|&lDa;q6axQK#AV#oV%j?%LOhxAHDO&^3RNEj_+%^8Lhw1~)l)cR} znay@X{c`cHXHxc70H^2VK6>yO_m8wULH+_1%<_`uqa_9h)hYWDd&;hRg z_W`*DZ>QR@o-i$F>4Og`Cv zlfsX87sU9V@c1G8PufX!ztc0_;LIR-=F`48IC-q>qRP4?j$`~!N1YcHAtcCwUq}Hf znM~p7#$A&wG1q*m@=!xw4UmZfRAa+^93ICiRQTZ*{n6+_k8R8;-?1XDG1_mLp^iId z+(6~(mKxo$25S<^(altDL)5wn2vma2ie;xJ{2a}-`x~Ryx!iMfNb4~q?|Pa$*ZW)g zXL0PE6IX&fX?(00L$@_3RQ zhVHwC;9SAaDnMT)*_T+T8UAI0iJkeea`Ut=7xQq&-VjhAc0593lc!*d21{JuEf~kn z{7^}mt-Gwag3*#A2;a*KUoO6RT1vWngvM$}VJz=|gSQT};w?mcr}NM)Gze9awp`Mb zmK!{|#rnsr4In-dEY}kwnV4GmKCj1b6Mk5)As?ZWwy9jbehc?T#mkC2)!Q3&+r^7Y z_-n+98AQ*FP)>0-5Vt&mSQ`*zP|n6#`h7XhyK)rzNS{xCy0Tw{z=6_X9GX+lvR>xq zTWw-?GU-ejCsX3sWN2y^9)PU3So&Tw&es03zJir zw%O)fEyHDJXRniKXz_{l9}n3C7}Iu~cZhY-R1Mpm4&Tpvd~^GJ^AJ}&i*q+>Jd!pI4tQ)rcTd4vZ+%c%1Jhky(lCQMb zcQ5NJsq)=Z?wh@bthjE<&u&Juhc7fA&JjReerM{jJ=JzwTK+}^QiWpeTj!QeU3I%s z=JH(WTN3BsuAH04WNU<#iLY+_=LR#r-r24|??kwbEd63t$E2s2@6z(O_I?X%_}_Jv z^?APRp&xzOHIGRfCag5>{@n+!L3ongfWaR66dx7#nmTTNs<2zg-wXTp-gCm%uB8`O zT{-vfpFaQle_nFpQv{uuo7f}HMQ70|*t#~`o+@iYf7?DtyR!B8-X(Ew?d)P4+*@1c zF@KArU5$TgBQ!|wafu~;VyP_7roKAk)3?rM#W{2MywnW)=s~HTBXn(?cJju|$3ZcsCQ5&)j{AF7N}6kK;$cS09*eB++J+s@PAM#&o7j;< z)4STf28GzI;4yBR>u_1h(kc|qq(yOX=pV-%u1=|Mn42i&s#(*99S)>y--%c5>VM_f zT4{XQ!Od!xpR_si3r@U@j$w5#Y0P z00q!95W7+Q>@AEylC;1SR@NUqKCtS6ALe)rJ{lUMb5%xBmyQZ?A>AbWr(`r;_3k1( z&nM4NRPd1Kia3y{rHQYMlHCDggz9PLY#4tO=}slF#av_>E}`Ra69u!#PsvL9;wog~+t!wjTw z!z0yxb2GcN`OZWruh-mZqGphHn(N-r!f}Y8=H;}0Tp`T@O%5U9m%EXyGafQh8O$-~ z0RIkrTyhJYmsF?P2W%~ui;5lX_chG*}3@%R~ zb?=-Sa~iQyB%y~l?J73#BX-s3c#eu0xX7)iQ}JL(J)J5=(p-*_fb(SfsjIb2ikP6y zJ&C5o|9YqWUy3C4@YNNPwP$XCZ$LosKnJ_{Cq$$#NQ>_-VfCs+An-ovrdbCPnTn)Y zlKpOe2A?c1E^^Hc)Tv*6PL9!XzJ^xu1u^%3e*#xS5GVvrlQy-O*XbE2wAP*^VJcAP z{l$xa!XMqhulk3wJhf)d;-#OjKb@)f0KfC6Di6j40pWE-kOk*%1Y!5cM!2J8K}4{WkCGSZY%_`oG)16aUZh z(*N&vzM#lWHu9?4ZTpMfj6}q)gxn|mCF5*_;6-k_1rd{9qQwKtoz{;nz)HkY$oOy9 zfr;Rr(e#%NE%R1zDD%EEzzI2P(ANEG@1SkZKqxqzepeCeoZ0Ge&`4dKi_hB#)`kO&Yx0N5MiAEG55E3#jyn zk)`qb9&u@zedA=wv}sDYmMPW}==4G-nSu6yp>u+Fv~}kuxrSw`SW;b!_!vS>6aQ44 zhEIZ0Fb$W;B(+Dg2q|1+}IFguy=t;jTbsdSy~OeJO}Ds;1cley78?iuFAa z@>TcvYO>!J(moMjv*T*fv&k%5#O7-A2=|D-u}@p-jQHyoKO=^}RdDSDhXVWd!TB$L zKRHdWhqm?bV12L?=aUC1koF;#4N$^-vVf+xH9v$PzOmQ4=<5@++NoM;b%(gBN32l; z%RNDrOL+-Y6rZHBV~qTAZ#K0Xxyt&kr0o|heOeR32R)>3EZ17SyCV_7<3{U+0p zu_?P7Kj2_>@o1#LeAdTin7Q8=TiFveh*%AcoK!1egHe{UJ$mt=Q{}x~fiBWZ_ZxsX z+`q)rTLXqb`RqhS1PX+;?#yQP&~HQ6UYGtpBaJ5*bnI+=SZ{ zSJI5o@~$yAhnwR{`t)?D;aB2HiuDfYpK#kr$<8?X1NJ<(&{NcUdlafA-`fY%e6su3(H_4fu6o9-57cH6uNl04_ zChHA4UVK7N1#Tya)X;=?8?hu^z_I?IQP)agybtHV`}m!~PrD^LUBE9Bzs2~~;d1v&I%%Q zk$>hsgu}wW3ZXymQ^o7u2O#1f7G7gVQnxV}C$YLbraM&4iW4nq8la(V9S+`eTnU~H z;%-ge*C;VxNHCdLE7*e}@tF>>uBSgN;?r~k1nHOKE%gL4iB0MFvNiUlf7-srnrmM) zhYyEX(X>rK$va9hL&_mnqBY0RQDNZ)E^}XF-{miwH_;apEK6x@M$g~=#m}}p|<7U9)6goe%8J*WPVX-6|l<98(ADEWFVk@96 z4iG+$*LhA~$1bG?yt&#%#5I1T{C1iDT^LVnD|QffYS>{caUrl`DVbxA;RHw=Q>|u# zh_e(wcs)jNz|PL=l0@W}ZziDYxrjcW`zPKaE{kblwdC|UT6 zJ+jD1(!IIKH%lam9>Z4R&omCktHjmg9mX{foJs+r;t`x94EH*Ewy)Xwx9ip<`Q>T& zGEZ&okRshbYEwsUs$7gtkpr|5&z*a~Z;vm{O~q?hb|DAdz0Ekt!d8QRO6Ha6kZLjk zJeT3;l*6h)=2+Nyw6bFJb$MKmo~?VNc-$wlMzB0!#Oyf{0k<-35A1=K-zkMM$|okn z?uKZbpK z3i;b#@hXTFSsdd#u0WkfQ(SSsD+i*71!OiY!%HZ05Lr8i98iZt!dKt)C52%=J@Y~D z-ETFEW2$&<)m_nb?<%X_JOaZ(DB@HtyiTJTZ>BZ0#D)FxTYM6K$IgNW;kNU8OA7gI zrDS{`VhyvtF_!h`i#0^ruXBa3dB+%Gt`c6Rl+@rgheApRIa<5_W=LTYKV=$GYZXIzt}S-$y-cLg=ffj>b9=LY{6 zWscf{f0?d2-@sOlNl4hEice9X3 zX2sSZxr_bIO1Ayb|y#V0xpqwK3Z5VGJZF%T2^$lb*!g?9RCQT z!>AXJdDIiYwf~}ee9-f%$ESrQ5#j+7@%ry2dSw^paeSc0z5@n8f^iuU{E@Z1$jsvX z=O8J=#-7DP6dgW`i#7Up7?w&*LQd&_O2to_$}mOEyU_*}#2xaS_LX|ivZY*$;d<$# z2l?Wg#z!(&l#rvU-IeJw8Cx-0u8$*7-@G~N}6PK80#b@Wy;ax#BS z$O)FbVWNTPKYRlq;EiiwYG~x7f@|CdSVEq(-6f6$tb^iEpXIml<)NtMw)iSLTQyNr z_0G2?7ZZ-<(75CW>9_eJwEF@J)_oS`tu>48C*`qBS0qE`=a3_Ghe$2sU6D$e-$B}9 z$p>6ezn@PcG?g!g_r6JvMw|KQj<-9Qt#ns6KXg6cK~}s?zdZr_i+$uV`W!kzLXl5_ z0DnzWAYooU1mfNdSw#12ECOr63G3V7NySHz;InKit&# z@+c@tHIiZI~MhYY$`M^;n6@2Q7 zoA{i$x~f1mKZ-XrWS2E$mp5cr)MRg{$p-tfpsH|IdG`Hs_5;P)^W{IBB&D=kTP9G* zIo&&obDzSU-YW%6ZCQf+hc8HxI`50MkzxSg;{$(JoPSlgF9u&YOLAi`aOw;1t=XkG z|EzGI4ZiRV$&S5%!1Ac!?=%0bIA2w`PX=GOLfo+zbS0s4c;n9q0^EN`5tBQrxNSI; z_}V|e8Uvz8zNViHOu#tum746IfSbrEHQ7G_6UnD)vVQ_>q?;yV7jc6uu)4R+ByyEv z)J?tOeY>o3zC;ewYxrE^OO4_vtGHhtKdo*GF9o%#I)4brNtl& z)MBO^>uJ>H@!5s=C2t*{z2`+dT z_eN%L3lx&NOBPBa$xv;JZD*TE{1hlw(Ro;bKJaRqP>VjbImzQ{k<H)MoRL z53aE#;oiDFTG2CP5uIDCj*hZ>C80EyTTkZG+@^}_9S@F@>?7-B zT=#b@9%)Uj+eyFLNaoV=&eT2jx;wbj(N6m&5ZNtxfPa&fC-in|8G|sHFbL9pWZd9$ z8xiQU{_eW6e1VKn^XV`_Ee{M6&9)OMHq3?gy4%9X=`b_1hKVK&vlFUmDQZvotDTzI z))=DM>xsLXtF607nm>)oPF8f#buY44t*RiUhn{yh7r(cWvh?UqUb&)Aw3I<`ikr+} zC3$xz`UkxY+yP6WN|HsFUy4J1{ngwo>Ora_9w1R0keT9sn z>zt}s$eS5*o)!&sv45XIIuX-jpy%_l5JZVC;gd}b6NZm;1?Gz%Ug5Q%Yez^OIFH)M zht$?4dPMqrw2!>5 z_6WonP)1s;&XA8X6|lN_cFzQ9829WRSi7wt(?SySU`0|q9e#g5cFi?FY+4864Eq8G zheC9MYqEGwA#Jn+;*=22gvxu^@=v^PDs>@GS_s!x^Lt$LKheQY+@uhHD=2iBseOf| z%@oGkrpM13G&|4l-(#ubh(KGNkaRaFZ9b`AW-NZIklnNeQhmjl5(2v|-QU9s`2Q1@ zffR_rQS3|#@vJoCLGORR>4PRQDcajsmP2U-`GM;P&OqR;JEJf;e~wOHI?yiTe;n;5 za*ywU5Q(rM7Na$3A@Yu=so1nydZHz-M?J8V*D{vzQSrP&eoH&TcaU%a{hKs6w^)}k zu_X5xs!a|r-&5BEW0E6Eq-t;=ko;YvW5@zsHIX-y5feA^>?@fd6 zhAtfxB?(_}XqCa!w#;1R(R9zd(ER{)g;?w%@Ih1MVM%8Tx-h!(5cEm=-n+5)ThHbj z=klp3x4={-ZT>l zt|h;s3%{dP=y|VO2gN*^J1dbap}FPaXxJ1qZV3%>CS>sbQ@$`mgGb$B(PImcDInW-jWV!@r&LMc*$qSL-;5}M3QKCEq)PSdVhv&hlNdm zpgCLs+rca%i%`p}T6|mS_;=?QmaNWA&hyNnE^vxl1it~Cw!?cDFSQ65#uTd3VXA`v z9Hu5RlV8*vN!uB@?M<@9ys>DlXu!pa_cOc-H)BW|~LkmA9bFaEMQ7K@}4ezm4NJXz~e$rb9bU zw|BM_7J25Z>r&&m+ciJ~Fct}YYFp+1nwKIas#lm%v@Ywawjz&Rle=yS`7$Sb7P8q? z?XeaqQgN#N;0`j3zM^kRqW0tr^CxN_Mr}C_&|I~w*6w=S%lF<{oxO!fZ}-~Feg`a0 z_a&`hC#FI@3sSl}cvr-Po8l;4t5gX#*YWPWZ0~CHCSNKY<1OX4?F4st8#K?r8A1-L zDQ4j?F7CHeQ_`o__c8N>i^k|hC{f^&KZ$Z}vV%wt*44@j<5u4#u^kG_D0u&k{h%0~ z{F<{=4*`Ga#$MRdZ#x^)Ro_>|L#>d1Ic7X7u=V`Q4r6?TWK*kL+=9Oxvk{mSq50&F zSZ>MAYZSroAVgn|iCgJ?F8{JHE=W#MF1LTz@h@Z7soJG1vC~hzmw*#d6Ms-7AJZ3M z0f*>rL7q($Ru9}jF-&#i21j6oo`H zgndaZh3egBxs;DE?rS8efFH+egSr6_sBN6gLklLud9{H}z5NXsXaloIe-k!y2Ci}n z_;j^ulm5I~vr798se8tc>h2v<_R}Ai0rL)A|C6oMjfkN4IACJSkXLC+Dj@bFP)u;` z-6Y?f$>*d%A2ht@Or*+Tv>)M|dqHaV>L4IQHu;_UIlV)L89aHOrf`8!5J%^I(9H>B z1+E#?w}5udA+tkMtRq#rxEh@)N>qJjSdt54Rl0{Q0%a<7{VPsLnOLEI7a-J?Dsu?BV{_qC69a+&_%YP>ma<;sSk0Oj2h?FEY#&j5iyBs&IH-tPQL5rV4$=u9;{FP6uSc$v=B9Gae<_7?DHMe;&AplC+I7z3O4(wetn7kt zfaXr1xdm~~qsr110;WNDhvo`2wrT-P99?M|3^4!98W0NM%*6+5MiHWKcj^>@G~gT(X%Vl9l* zl~ife781QvbZ3B@amg`NcSfQQVYJzRB?JS*;ZwrNLz?5p=`8Y9NQgTVVt2Qq2@E9U z+Kcf++td=7YUrr?)f$S`F4N^`h5N9&26FfxcT_3l>deORrx_DA(@r)BPkht#|6$MxP5tM_|b6X#WhG}E_mVyz}G zsqa4txgInhT>DeWrv3_IR5!yQu2l?_D>A+fR(^h(v8GpH9_;UvI^(K^3%Bi&!cVv3P8)dYH|lq^bIW5-S#Wbe zeoddB>H6Y@&L8nO3=Aj+`uKx2gt=ZwKeA3%VVCg_JP%nzK3e9UJOp;CJ?+rB9)g?T zIpzc98cP?s|G07n=K>!7rJU$d*Z-$V?CQ^ZT8V_HZ36UG`aRP8z}^IXb;SCLEesMo zlsi}<*}1Uk~Ne#28j&%SY~9IxMWDI zc~D#?N_sJQs5=w;X+vyJ4d|yylBG+tttPgk;LR12CDJxrb_+=7;Vc=ewrxZ@b_o1n zc2RHUK%c2LL&yhpw^*M|{e2!zjPwZx5!6+KlV$EPn7J1d+-AM#lCgUR`lrJ4dw#el zWQEiL9gE!}8{y29T&3b`mwjZcWBrnCq{+Lq1?o%W-G86|>KLCi$ZKn%m89A9iPeSW zBsayANtC+4u)$e3C6Fz;f%PW8*p4iHCeI#cq--XJQu^t(p?w~xSEf!T znr}ZOas&0|sr458U+XP)wxZrCBuYPn7>V}xRV*2_W!lsNIIlQa5)f4#ZJHa7mR*z8>;XhAl+Q!?6TbfTbq(3+|Ik~lV$rY;m?$7 zE}BS_?N0xf%9(PSaLM*`@7D@WBcnUwzpR|V)^*vZ$o5-7CjY0ci7tE#KfiEJpwZN5 z*eVSv*D%a7b9IHPD3e1yd4fxq%aa`(-E8!ITp`i-u@mo6GtpO^o;X8slENj_xK>S_ zD?Ig#%^}$}mSV;`^^CMcBiXfh_TPqQtz_r$9KIFLoMhMGnWN7-sWsIVp|IFPVIkR* zr6tKMe-AtB9=bLM`FOdh1x?1>nw)mFvL~l0Rtb{Phbg#K*CtK-VUunr57LZI=zBt} z*AyldYO=sOmnPpKPfioP-V;h!NaXKSoJLT_f;&L+ulo`h*UjG33LwQY#C7HuP&-Q+UFe#+n3h z_fQA3^u|Mi3k2Aw5cRZn810%EVxdpmPZMmbT#=H}rc`a7C$DG@wEdt;7USY^w3UuAPbau8$C-NS9`GAiww@Tmke)2Wcx>6>aZI|iQo1qpTy1Of61 zvXU*1R9M%|G0ShS$s_X!pX2>30qCveSi63Q%1`6+5&}F+3}!z(!(UJ<0Aok7B-z} zEFT7HkxNT}R>jW5Q@lR0XYArlCf5E+Bq-T`0$@jyrasIf`w&;s0X-g=!5vphT(PGHuA~7PJvjQ4xw}vfl^&Q@ZQx2=v8Ugo97+zbBz=)9 z>C;hrC+>c(q!=nac&}3_*~wY)B!zO|F|?#dJCInfqK^LWsx;_8Y9L&}oe7~+8vi2h zjBDUczj6YnJQc?99Jh>%H1`*HpH}K>z#ZBXz;n?r=oz9e+-3FvnKp7ccu^3|0?_h2aJUdaZhn4pn(G@9D(1gftLNh)>&2x9Q0e%)^wDdA3@3aa?F94ptCR- zb4j@tn~Yx{UdEN|q*l3n_;K!95;f0-O7NK)`Vjsf?nECgnq>?>$Dv!0hN%Flpxr{g z_h(#PA1h50LMP8p&Qo0pK>0IVE}LcTI}}^0OnLBe@@eL z-;L`$*KmP+u3l)vnHa@CuD1nwyovPCyunj}VKf8v;Ie`36ho;GcWLfjthMt8IA-Kx zEpI=dVdC&N6-YWLY58oG$)a2TJ+*ctKaND`6D8MZJLKRGT0p4M7~M;!(JmZ>mcJ|Y z;ZW+5sZ89|#o2rv>W{U9`UNdSH8(66 zr4FqWI_3W|zKgEeMDDxznKv;0JGhc64r_~l-Cw|!gn;qTiJt)uywGA@$Rfd|3bQm`*(FXqknIO9azNBu<(B!kJ`Oo$MZ&LG1H85@vNQ6 zW$He)n(CV6h~PQ_t_umj6+W&F1hBf` z=cG?p0W~s#nIJE%C}-CQ3_pEB%@n>qu7N#(+-5kc(QA4{O`oW($R1YL3MFZ-8waER zM7*?k*7rCC(p1R~jW5QslS6mI*I|dtr(u87#I>l<-|2-z?Q>Piqz`98H1(@L4aEd%`6e9px1s3gv}lmJ8>EwdSO*nvmH(iQdhicS^y}%{@mG6` zDia1B*W=Tu*pxa^IjglmfN_D7B)7LUo}M=01Avv=64Hvj3b|t&+U3&P`J{Ge*$E8m z@C%H92Som0m-u52zA)zH(G}fCdk6|#4nLD_q7O^_b6L_ukK6F%cCZcxpc6($aSkn( zm-wYXAvvy=+uOwt6>=kOObS5g3d}m_QgLvMz)QF()AgG<@fLGBEpZ~ z*&dSs3%D79Mj6!CBPFS<&0~XKP)ZKHLRFA#qDv)*+`}_`BtUcQxTjGGq8Hez76IfC zT*ZPc3Vm8TYHels-UNsh`>!z?$$2`0O|lha9iP1O1e-dk`R7x(7o)hOpg4YrG@0VG zfA3Gl(EhCYxBjg7fA{C^A^q7!T8H#!{9u26`ycyL(=0$Yx7b(B`c`%LR`>Xx4EbvM ze13qduY*8Iw+p7ea^T6nf6jFbBR~BkMtWN8G;jP@68h*Z; zSFI2t6d(VQ_M*-ui`9`&S*Qr5w(uX^TVvyKZ=N~`nVJr9b&vRDpXhfr3#_PmVsjP# zbw$t2ONxs*sMhB9j*0?p$--ThKV0jbjv!10<*nMP_pVhfezbh?uc3y)>uVN2TC@1q zy026d6xBx(#r&tC40e{iR&99{E~8qt*L7)+1|IYAxTOGC$SO( zpy6(`i?g)p9U7=M|A9N2L{{{L#BqpajQCY7V$^W^*EB6= z&BOWk@2oE2rIBR^ivhCPf5jP7Wlk!**Hkehj$cz&CX^Qq-@rH6?y9&c&aSV1N~kGH z+H_eGMe@xxfE$q>T%rhXrNiMdpOx;yokbQwKJH*YR_r(Na1CX$v|gDoL*HNPO`D&d z3%i)vPptVs#l0CY#vk-|rPaIm_bN<_-8ud@loA=Vs5=Wz*h-qIdigxy#S)g&^Hye4 zpB|3T-mmMOAQ&;zZ18=)PbxgT1|E?4YL_tD@<|jZ(dD>Jc1-1VD<_&k7CDCJ67K>o z(gUJaHC*u~!hBfxbTz%PJ)L>Xc~Cs%Ns1XCQU8SSYHeum(&$~S>;#jE$90b(^Vs== zC;J^gTUklUw>0bf?_aiT#h^=D%N@7s|5W9eQr9L!3Nv7g;wob1>{!(F*gBWP!8&e{ z9rhYWdV|B&>~QXMq)Cp+Hs_l~TYMWU*RIMl8$9~!8Dd>qIkXT_fognGTr`SxnCjYU z7^Vt&s@+Ld5!_N+dEEI(`G7iwc{R{IQ`~GSGzVS2l|9t7iP;d;kX>;9E z!U4b*5CuqNaV1wm30ay-hNC!2$l`H?cLx>L;mIvKGQzh(IlE>X>xNs7G}n4btO;My z9BpRt;9nZAgPNdN!!3>P3233X%!-e9h}AudHLxoQiBI&zwiw=kj;HrduCWRfluN9U z;Tmx^7ipl0QT}a;rQs^A?jd?m|3Ai1h%vxT@sKfu^9IJCcK2r5-F?O1ch}2lk9Ob| zy2k%N{7l49KzARYgo#UFEc+RLKQ=fk65SxcSIteQ~d~kkP9r8U6^oA`9GXyO3e^x9_b5G%FL1aw904J8j#M;u9=?L7qJY00t=)o)g~}FsJ}t*+Jo2eL2>_$NOR+R#&__ z{*)*s1h2!J@ECqXws*Z-<2P$zjO0l4&!(M2ZI}%IWDEtf4WR|R17>o#ir|aIx%^1E zoh%$fxrVoM%NDE$RY+aTX5ntTbPR7PELrc}tyn_eITFK#@iRYyd-V(#wSJ1(GYzgd z3^VPB05=!FN>&aA7rZocG~;$!eyT_jN@`?N%wAFz)r%!<92B&JhD@Cqcchx{suQGO z)Y38B6})cw)o@S>0Zn5cu0BA2lJGu7@~y|r8R^v5t0ivLg^x?(w+IHBg=iUt<`C#ymiN}m5N)?Q8UlI0lR5WHx4jHkTV zB~4?`1;CTG2;b;vae@^0TIPhU?3!-H$^%pK`-{ViM0Fog3>~YhBAZf< z6@~19v6PMb|9E>J@FuFPe|+vFlO}Xh(zFDmfz3>z4cfBJfVQ|)+ku24plyIqG%AT~ zfVJ+Hih{nVHJF00-Q7|YMXQFYs4Kd)DC&y4rI1>*?3S`BC@7Ra0-}qxB1+r&e(p?K zihths`+T3@^Yd}&WM=NY=bn4+zjHt59Ii>XUOW@ei))GJwRm!{rP~+!M$2o}Kwgow zK11t3UR=h4yo~b8kxQgQx4!ucjRo94FUrLBA1#w-1~PFE?`zqr@UrI}1xaI1>(*OO zfB@S68fnt1ztR$5Qw4#f6G-45G!qpFv(`>kRvcWiI03U+6p>+aYrl{Ly=``%*hW{6 z9dxAgRrI1M(|fh1+^s&6dx|E99{z`uFJ*0!^N|#|_TaZJncOVgJ7Ayn(=y!#?!#ut z#-Oj%vXg8zeQMc9XxV#F5G{L)T2NOH%6_ItEBh7oQS*7@*S7NWGDEyn4^2b$;JCM- zJ0oXUM)9~%`LD24+Ja{D4tw3r^|k2WUz@*O`wir}Ti?gGESX$&5N*q^(;joWK7%^% zYW)~Y0=Kk&jCD4(CEDpYot~|Sc>kb3P+=76a#)NW9ho(HetZjICTrw;zZo-K=W07?CzLR)Z04xMSP!x?^R4_xHQ!vMLeQ3(?&AV52?7oxciC0tUtB&12G`IcmUEL|{BZlJP)%4+yeDkQ~sCzoPyE_P9I-Si6 z;nNh$Fr*M@it1omTgZR9g=aGSIi0 -le7sja5Ht)`=GVRPH>=&ll^`$^H#*ZGHfB?>0>dzJ)PSbKJ`1}otqBh5NDoaV zw%MiKQ~`dD{&Hp=z7q!x8BlG%K?!hXSIh3^Q|e{`CRAb>VjN_O(B(F$Z}WlhY#Q`d zCvU_-lb*bwzMX})e;@Q#53^wC;mJnz?TyuPY}=r>oV@W;Xy(ZV`u2p&dD}h#>HnsE zF-}#HYo}Wj8!ynvf&I>zfO&-VVy6gqCeuLt6=Wx^3e*8OAA)v)9Y5T}ioYM8Z=R8b zg9%@l!$^LahB7(a+3u59AodaCuy{jSYDJhD-R z?{S*Ct@)*_JOLxlditw6d=QfFYwN{KY~*b)nJ}M5WXvqtC4jIS$Wt0&+dA@-W{7CF zC)7kQ=bK;3LKctFUk73LQRFfb=h1QeuA`=vld5;K)g7fPy|EPuV^h@ZdDR8ziKTJ; zJyaNmC1&nDrRsZSh0FAL6+prObffPqr5vL1Gg>=)^|oyZe9|PM_Mqtgz(F2_16@WI z(^74nx^34LE%oX*O8RJp{y9s8{t zUz%IZ0PM7y+iogdy6YGewY!p9%}~%C?UOhDk&LCy>FYT+xYy;VXQ<$FM?l{hfS)av zI-r3YD>yiaJ$(xCHAlCeK67Z*wwZ8(wlWWGwIWv>SH1hCte5gZ@nl+XomBm=?4d7B z#_v3p5H{_r_5-WH{cSzao&lqFE?^Xnk0(5PqC{=kyx&_2?6~OO{KA>a*6#<-R8q7v zmAG~v>QvQH?SOWFo~Aog&r_t`y3I_6V>DE%IQ%|Ibp~jL6!Q7N-7$Jc`{KY@T6iHn zD_VE!+G+;9Mn*V~`Dh^d2LpHNk!@8s+7#(;#CZ%f3$zO(poEScYt6Ira!&KQ9|Hx< z-mxjJZ6O+U%;)a?hcD7wW6&O zNU4M^p#su23A;2M^8$|0rS~khvJyxAPCe^JyF4VLo!2F(MozwDMpl4_?Pch_GRnnHqyxL z*0Gi{%zOom1(@wP0s_fZ{DUS0X08JuGrI85dQ|PL%&j3B7;Mqo|8$c613bBY ztp;lYc0r870RZTx;k#T(eWaRBEI99IHW=^8yRm3iY5wBu6{FUeYnz=fkQdnv^&1)= zleY4^c_tnnS^%Wv*p z`HfVTB9)~!mf6IzWVUP=?5*!$s=d%Q;tUo5C_t331CBTTwga#uIj`c^p~0g^Rof&) zXaEB0vXj7|L&L-E0gSC`g|LuI?uH+>yYBse$ zumR`7U+N}@UCq6uAkHnXzWVQCbB;QCPo~d+fVZ?srm_~exJNkAhq6en`q<@q9i;V< zyI#RZ<5sGXGa7p3XBg5&-$QqJ2~18|Sy#4B~P!en~l1b*6|qt?ai;_W}jM< zykhfzFTZQ^V`bHou%7Ee_;fx^-0jSJc@l4Yd7OQhW!KAZWxqJ8`cHJ)kCiJ}4?>#X zQ#k6o**%QK2r<~yia7+_A>yW>!X`ltv&eU0o<1|JKcAUaw`l2{{J6*HhZ|LL@$*(AVblSDkH@?Poqr?XX; zJ1X6{&iTyn1t~_7Aes_t6N{3aTc*|Pv12@o=Drcr-@GS3p&1Uu1&$N@ec)utF4vd3 z*7~ky=RW@3UuBLZ#fAer~FgbI*1d6+5yY+?q~#=e<&;8jJmB*>n5VSr%w0RD_$#O znX@jGW6C$9a$hP?Tdq8Ui1FjadfKT-ggd zrBrIGMPsi_vWv}8UMH1}sD4LXvX|1Tpa)=Wap*bRVrSzrDv_%}MC2$Dj`v|WId)>t z5&Xp&^sy7Ou+kU){Z!<@2|AGuY#j#EDD1<>?#>fxHO>r>N#{Hhf!8pR`)p9%;DZR5 z60DK2={Q*kXp`P(1)i&b*T;SbBHTY{7HDrqhMl6kM?J*mP2^Hab``@!eo*$gs_#Wl zMo6ScJG{l8DC}QU4$uS_H#qOBaesl%A~f_x_ML#~%S8(XrwH$}=$PN4M9Ms_E$)M@ zUmt!y8(7sGc%VboghO>wFvcNmx42XF>pRRV4#NV&HqUHxm>;Vy+Gty1vQ0E02y4AC z&i0(qcDGR!?hguizRm>K%AU<A7Qp}XgQT7^3%OxZ9MF39yWsg%(Z;%G>Gmx)4Ni{1#f`BWRl$Mx*0K>XTW_=Q zK!*?!sXBg@>L!!6;|d8UExG8r@bXgIlyK4Bb+H%l_$%=E0y3WVr!#AUc%FynnDt2i zI)=vEfm9ehcs^(g4B!!cjwQp2iruWYgxU5+o@lggzP*$c{@LptR#y1%caE`e8(|T# zG--faT@w4fvSMXkmeKA_rZ!PVEBrEgcs=7;2l`rt_ym6fW4T{lkG4~vywo?ZQN}4O z1`TM0j4Tg-08SCztVwSRGH?+wW9l_+xizO%rF2bXsOd}A#~LsfrKnoJ$90ZQ2ZZ!- z9o7Y(jDvVg01z}mDb$*^*|zEzX(FIVxbj}WL9l-=Dl8?OPX{=N z_99Zz3tUDL#{;brNi?-IQPoGRSm(2v@C6@{6<>u>y>lzR4%G_{Tpdsk9rV<9Cg@Uw z>BUMx7nItiW`1HR$EO!hTo;jaIOA5&|94opNjmtUq4|Iqx39NHr0F@oa=KOmna{-E zM1I?QAPk44=%b}1Hbd9e*q>x^udU-aG^cK2qPiJk@~o$d)Ci;gWK31H3PXLBx$0o| z_`A4l?Z=5S0AxfIuO<68(LRz@(ouG8b>$uy{e{O7kB$L=hidViRz%D@$R5a7f6E70 zdFLTG5#0j^NwCm&RUzD;{M>4C4L!br*D+fVo|lUVVQ8j2>{+C;>*(wk7eWT}t+oyy zv?l^c_H}w@qhgjC>D>j)lY`9u(V93P>94|NQDwR5=dfX1?Bvg4!=6w}0V0fS=)ZG+ zZT$ZV8^*0RVKD`4*!}&Pll%JbVyBG1j17ydLhRn3V8gEdIX>O0W=OGJi|O43KHW)7 zKjKrt&!xX%AbsgY={0Paipm|d{a`YX2XuH48g1GpGqm*BdKUHHL5b&~_eeJ|wy7hV zs;R^1;QIb7$=AMy_i1t^y;aBCKhjy0d=f{i^e2u>=p;;BuHLg`e7u}=lBM0Lc=i-4 zanhfIh#j0R;XC3ONH=DbAB{Q2oP{yYYJYbPBBB3*I(Ibs!R z`19Dgp9Q%x43mVmTBGS3u!F<#zUoU6Te;TQ79*58^?7s`TOGz+|92yforlm<019jR z@H{Gsd&$m{z43ckB!8)m*W5NEgmX|2?s=FgkfZJJ!PXJ@H5EY#6fkC{3r_ByC(8LCqAFNHKx z3M3(i5(EVMEB(X?Ii!_RL{l^xjl9t!IV{z;K(nwz6Z~djd7U>&cR5 zkfw+iVd#m2Bf!l*rnF=+{4_p;A5qH7_D$Zg7H`?j^A;w|Vr2g&gMlentG6vl4*ECE zGE}ilLA~Dg-nSL_l_2|@GIm-s#tfD1&lS9?x6Mf6$CwRJRp2*YS&*)`NvX3iaOSZ7 z=VbqOb>?h?E|k1O3k~92FM|!G+*E3?J;JR(ys%{7a7^EJ9e4N1^|k+TP542~nj>%e z6In)=qx6M*fXF-NkY{KO^I5TMj!pbh&YC;UUEo4J*$KMDTM)|*&cR|CD}t_CJG_K*?KM}T** zJ;+qZ5Gs(kmqxK9A%354*6c2@O?c4wBb9}Qt)&_?8Z%aG_HZ|xTrZme+;ra!Dr~iU zb-tUA8H z_c(b4V0J5ex*li0qoR>U_B0#+lI!TXfE0D_V5t=)2B|k#I;yzu0-p>l!+!%9#cg$y z@-H$kQ`f=RsA0Q?y&4Vu+}Xi)j-E&XtV_TLcmw32%e9xAknSQ}DVxoR4xEVVs=aWC z(|zdZDwOpmOIZP2dSn;tYgQQ$X=CH8;M)6H;l2wHVQm@KL0O@a`vF+TsdxLpT9qYW z&#pe7+|Lp2?>(@E>u1mI9R(T`shdz+;TS-L~{ zJF5a9a92(jvRFC0?~Q{XxxH*Z2-3Zey#RuAzew8$i6c+4DhSejvk}>HHyZ(OR!{ET zHyPO|bZ$^7UJP@lbfc{XoVStdj4h)W?hzKgAt`TnaGM}ESe644{UYQB z=p7@|=5S_JH&f=u)3li*MSmBDLn+W^bC?Solf8)vz@3Wq4!N$w&@ zW^CF8hEFp}(P7e084jHbJq@HtPa4lo#r8yt0JZGQwA_@@aGO0n*Rsq$b(-ZaZ_^jH zM~wE+A_SK+1Cf6b*3(@`%gZeH&P@f6|K@$Ff4Pc&Q0o#lVsa!S?j55jd)L`82s z9ozethw9pg;yUTU`7!$Hf5UZBx5uY1%7fbIKstC1raZDv1tU#$$lfS5)=~4PxYCwE zc*%noC8zTJQ@rHAfBel)@rf7VB@fXx-bHxHPw11Z{}C^_(y4hu4AyU%!F_VOWpDz&vi+ukpGc z|E}VFp~Gp;f!1v~EsdUKi*#Zw2;2sqb9Fd-*!1~3kK_Ho)Gpy-~Hk}uu1f5^nED5Rks?fQNkfx z(>K0$Q{F9+e?g6bIZnzJVqXAih^0tgK8{`C*PA|6A%tH6e-C4syn7IM0ZVV({Sj7h zzD^2Dd=jy{R47{B%Wm93XO2`>_gSbTbp236xb0ZobGpl!oOdu%({nnAWM9U*6>6>` zWm_V1Gn@1Kkqb>AqVf<;cOLS%8ofrTAy7Oascky++QMjxG{-2Z{9w8z^Kwb7yf zE9Ep0#QP^h?D!oJI_}f+khLlNPMGWLJ-?V=Y=eR>G{SRIf$|D@%`$6}>Q3xK%!;xS z{^<0{@LWap*upN?$&&qrU+VeYyK$NbL(p$>Efz}BMe6WzgvCNTtAuUZSNAL>Qxr#- zlB>HgBpy@R!gjF-}QKsRIWv(y8#G~VWZQ)z3I#t+Ak z`8UO`cl>+R{>d#zm42K~+?h5UYhNJ8o|0>^QF5Ap>hv0bs0&o>j8g>|8x0rdKA^PK zO2WM=T~#X19(1|?q8w;c$pQ||-ORRi(jR&9_(|Ne=f%LPHfjH4&rwAhPvj`cnYb=i zK|Z8guvM{x2_W?#Jb|vFO17=+`k)GiTtxwRJK44{@`0n#SCr}s`t`>NaA1iW_s0qL z>=u}P_n#As)}}0GUZ+t6r_A3MhD4m740cS)hzF1XE~?;QM@rly3s1`9w)Vpo2e&@=r=~<%}Vp$rtZ(< z%2k?^V8k)Mk>WBOPO-WcBZP|zEcOFHm8lymzZ@V16CLi4QD423^p*} zlmGx-M)ex#(!;B(zq8DGi8cdDcf(h0;2z*8L)H{vD*+7P8nNTS-^eQozlg8|PA@}# z&35E_K=tIPg|tS|j=rvQqQLU&MC?~y%a9+*sL0Q?-Z9O}0&9m|TrpYSc@`C-z|Nx@ zs!?A$IrJP(m4LznVy_=#$^G|v4P%K#Wh9-f4}Swvv4NaLxHq+Q2^ysG&TcK~?E^{O zRp&izlu1bHo&d)$|3Ol_`i zU?JdzSZ=UU9(`ut(NaQKRj)MWeFpxywggX)j&<JL2fa+s}I_ z(v_bb|6Ot3bAVEeN2|0)vGVg(AH^R%6MyuF^DQ0p5xjddkKmH)YoNbs4s2utQCdGy zCq{>5S~xlD3EOMKDMQ^McD;4DQLr_^cALp7^v1sS4YS#f4ATIgxoQpAVW`xWR1NS6 zmt2smjua;^V}4W3$>hM(P@g~13o`^UBZaL>hYo0tk+oGBZRN%lR;mE{C_&XziF>dD z>L!1G3VA?VrT&U5tj5!P0R`WKs1mZ5m%L`ELttLgJW5KpNP&oyHHVBtWO-B4pZQ`Ropxag7OEt}bG&yjIH!y+?jEvmUOE(Q(0~CT; z52zfkjx8cs9g1xZ34ZJ5#JuMVzgF^A2L7Xzmc9Cw^1{ruz&M>&R!m;wFE3wJ`QWPP zORL}oFK6Pa+t|X-F}GdvB6%=*l54&IGYK!;_)Xrr-V4jM5${TXz%>hLtT0k@&8PB) zO`!%o%oTjBxY!bM$1Qkfr?4s3tjzLqODK~X@l-m(v#mzfi$%igSR`O#jWZaVISqd! zSFfV0Zi!_=TfWuS+HDt}ZQb$HXJ@DU56_qd!1L+~`;-F7GL2<(gO{|WWEr1cI73f!Y60|n|!~GFjZ%kJiRxU$iLlVMs((mi0sJjrBku)j* zo6PAxJNslmZ|ZKL@9pVcmXYyAKmL5$gwNyYZ;$hn)&lN*)LLu}vRfOEYgthG5L?-N zrh46#G7T=TS8PX7Lv0WA|NpyHaeB|D_qXem>M``0R-fuE^j_r?Mu4shbpABm1-Ti> z>wj86=l1%QQn8m}F?g*uOS4HFYOce`ad~_y(s>n?!w_gUeXSs6`yI9iT;Yp$Im#8C!a68#UhTjkoE_ z9l7Ce5`t<||KIkTbec9U8^3fvhkmnl%Q=ll1e&p11iv?jfa{_ zxvhKiTq+BLtehQ3qnOd5bI;>J!uqb>8ErFQ+3=MH9#ide?!#KwR%@a=)Hbr7HL(JL zR+wSeVUdc6H9TKkATbQU$$(j=xSs?l0~NG__`hSjj@wL7_78wIP}ecMj%z}-Q9BC` zFkoJ2)gx5ptCDa}>>o;x>cArjl zSOjY;Zp>29I%zx~u&e`dG)fhl1iHEH;JUdZ3V#bHpxGO9sB@i0bB9VZSBnE4L^1%) zZm1X+8ijcY%5xK}_Qr2S_siqNMudn>R8 zj%8?j{*|m3ldxZI7SMD}JJtcg=d+qcVJtWSFE2q_Fb{_@YmjN8vxK+sI)r9&1~?pv z)edo%lm_@zUWff_>>=pEOwR2PN4)AZf==~LHaZXE?vF^H;QSi7{s~M4%PbI&KZB_T z)Pr~bm&PQGW$qe{NgB)CYn7g^0glxwJ>o1JDpTgf9#&3!Md4Bi%6c$K5*G1#5w6FZ zm(gvpDk1mwZ<90$QR@$3Rt-kX4Bgp2O<++420*6y6h=oynp=wUdsQBAw?l$^RS~35 zE8udYU*>+ASLE@Z=H)Ka^2$JU|1gjjefo2G*@DSbSl44uYPp!E*dnMDhdKp}8j#ic zB=nP%7>HxhczDRI11rr=7fQh$w1mPHl90=%x*taIiO!{Xz8>zqp5pIC6(j*uI69V7VqQz))AjcKRAJR=F7{74L*8%CK5)3K1 z8~N#}48(2)J&<$SO!(?!HXVe({RcE16^vM!azGS?WZZ3l>QCi) zY(8KU*d|wZYR=4PTf0FHmG2+7gRR~|+cS(d_z~|Y7%iMcdB@!c(Nx*QLC$5fvk(N} zuAYZzr$lZBKL=PBsRTb%*2Tg|KZLR_f^N`ha)Nan#8~cU9p}4I}%!Tm??0 z_JAr6bZx3UO@m3Y%AX?eLY1P(9T)LJlc$Nlz>6*pyolUH)(1hzU|zU$F#l3kxNlIP zuBY;H6a3+cf=#V8ZHwWcV=3A~Eg>>qEgyV$|6ZwSRsPRWdYUQw-9C8a6NOY1g)USp3d8X1R^>pKDC9}PBy>Ieh*OZ!PXQPD zB?|h-F8BnnRj?p~yAFCcA_^lAL%_XQ&A<+({|*^o1Xbbf)EZ)-3UnT!bqG_waWlyJ zE;QNTI>hXBG6UZL@jV@;e2ZN(h+LpT`^in~Cl?(4d4_3a4bbYIs?j9j6-d|rD_SFyG+HkKt&!RNv~qL*H(Et1 z8+nNXF-%T5g146_r&$?J6fDvn!gJyd zhqR-psdyCzG)f05uF@f+mm!{yTJb>(+x~u5PeZLnQZcvvsGqry_hBfc<5Myn3L(3Z z6gm{r4wr%w)IrI8tncTgwSOG2N$U8QMAp~;IR8U^r<>LM6X}>s^EcCiX#TiS$6W4f zuv8mgKmDbG;^T!{4-U@Oe_W5){&+oN`glFKgm^vN3H|km?fa$dcU*s8SBHGfm{MQi?8M_-SquIRbX``~bcF6jBlcYOys=!%r<=%afoy5X3G%{LB9 zoh5jEu&^4?)Mg*!qpJ01m;=k=HmAE_R{@w?BRNmugGT$-0zqbV63bSOQT03s z!RA<|1!T)3GbZFpY-R&Ok5CoDg=oZRo9%}Xyj7T#Os$ltcYAmP)*}wwX)JAFi0ivY z$xFUL%zgL_Q@V^PSO#bJurw?MZt?tdZqO+)BBAZ4bailedgv zmOT4(x$4p}<6InT z*v%q3EJE;FD6S84o5c{0_VE+KG!U}32LZxna#;7 zlw_UnkLLh}N{JZ_i%C#sTBwhf_oX7yX)TztYO9>=SiG##OCvpdr?SPRh2E*UIL5_j zJzIeG0-#5;JB60#B7HR87sucK7v;Rj>igfzQF_=4Rl17uqLx#U=Z{y@h>EEU%Nw)c zEu!m*tQq-0du%%H3-(F8IqTok)_wX#)~$FJd-gcCBVOK`_2HsN-V@tW9>T-OGsk@$ z=PUT(S^HK$`nuRQ;-!3kAy=^_yu;5q;PRVcxTVY~hB;z$P zVH5mQJxFAeetI%%;!HxL$?%q|-jwiSVc2ARutYYQro#p25Yy5|Q{r3q*PHkk*M?2z z2RF*5r0K6BN-k>}YT6##`x+}));A-V08^14ljP540a0VgqmlwckaJ;i!dHMru$LuZW!DM0=EHY!xQz z)o`M%%NRM%-H3QcIIAnWLKY{;2rCnuAc~iB$2c*7bDyVdwxo)zD{OC=ZDDgbi`e$z zOeT*z&OJtI%ko;FM$XE0ALHr;roJpUV?4z_vst7wE3Yvt7e)ol-`BlGG;eWm^{6`c z)~vV9d4#Ce+ZsxHzy=H@t5{53+Ks2*Mhe@6*A;R*&Dcq3 z1fAoYA*OKqIqZ=R(tdX(`1z)WN2k_IDxM#f9xqZ+qykT#*X}5uKPP7y`Ii11K*%%9 zZ;+nqWBb$gD4IW9HSJ>;r&S#b4@x^Y-IHfXb-c`U%_A-#Ehv+$zPP|?DDT`)>Agow z3yTZ26Hz~#c0E%6nB0qKb)6x97%1~L?M^N8cNdpw`e_{l1L zQ*qRN1F%D`QwoverLQ7aYj-#?g0qglX~nnh*>~8uJsuC}8qjc&ZODXp+7yzb-Pv`p z4Y^NC+TZ)t`J{sm#>C{BB%BQF0y+nF7t>CV^mzJo?oAE@^aS7<-r&e1os*XVXeLvy z_^b@<3%PZm95o6+HV=EA5PeoE)Wskj6G(92iv0x$&G+1FZFP*f<-Vj?edMpwJH$s6nQ z&cdnJK5f)zFx39EUB94)BWk&-M_f$?X^FYCltHpPvOg{LMU$=59P%H~QbP*&)4L0H zKUe(3K5Ej>rB@x|s`gd8E>7K^?aupegX3D-D`Jyrujp3D%6M+8$ldfVA7cRj zK=BriCy*1BEuF)~8U8*_$U3=k|i_6K(B4#E_%DAlejD419XK0ZX&PLIZ3p(8{yx+^e~90_;OdkFT$V=tJ#P#lg%R#;T-LO(PT` zU{vWS&^trq9_I#j`P7U*?yse*INs-2_~Y4?{5=efop8P(HZOEnpr282SL_}Rm~cC& z*;PVL(Tva8zho~}zH7W;R|y+EzneL9byIE**{#E@Bt;LB|EAyIe#T@f!Br}`)c5yF zEC7c$?!3DI;d z;!4L~qVn%5YQ>dl8)}0qaTLrlznLKK>;>u+;LCV#!7xn^wEvzqwjdZ)jWP+l_e>(Q zD2J_@%>>}!E2rjn6QYRE{WatHim5uq7(Qn_M;H$*cxEu3PnnjF8P9a4s)%Ws#&|wp zTHa?2txVNUrb=cEP4wTYx0#kV7{hCfr-AXj%owg>3@no{#_$kRwVE+VjK{@PRPn`y~n3|UOoGN$TM zrez#s7{_>=OjRb+lEGA!F@_~f)o&S3kg2+fX}O*;%ws&WnU?FA7SKGJl3L|vJa)!Y z$h71$Ehs&WfxSb^aHeV^)`WwL0R0OMJ17U!Jzco@w;UAV7eNkQN#5WD zL%WjrTi^O_IXK3%Td6>jkG_$Emw4V&!nhxS`w^aZmD<=L-~28)ILxzCsmJ}}Un87_ zXSoBuIFa)eoRNbWhHbQrb^norV?A#vLFDn_SJP$0FqVT?c!Rl~*HA`} z@6j*iV6x{`C98B^9^2BWOkOhYEw-frA9=jNX@-}S#OHk1e<24Qo)_?JvNxD-*hC9U zJ0%By<#`6ra=by80YOB9+hme`31msl%fzZ!p{NxFW@V@aaC6gM#5v5OU7v zIW7n7hKJQku0A$h@~p+TdEVe8!=Kg479Ev?X@+W4_KferBXV%0;X$>s?{&(-;f5-u z5fx9wz0I%+yzTQ99F~I?LnX@T^Q}5GJ?yy$#q{|;{7epx_S~(oqJL`*YgnPEB2W|- z{f;$J?_zI-=ucZ-5%gCrrM3Lw!1P+fACPySZ^nV?U7j*E>zYrd*HRwA_LU^!b+WmxH5P7J%?R-<$iUcN%U2-F-gOJ~?=q;RahU*6b_ zEe0KwDe#qAMZx!%j@OaNk6@%Uj%v+*Kf9@U)qCw9ZJXR=ZrW5ZO={{9dA5t!VdL&l z9B0mSf0r(0C*3$y<{61sfhZ~jWX4SQ-vB!yGj6`V?W4)f{X^W3y!XPNY;(ZO26(Dq zn!vH*EL*$&{mK=N_ZOD0Salb{BGD_(${VB2hdEcQDjoJvU{dmYAxn27F{bik*rsli z3(GWEm8lEGrF2qjt3`2p;tNFpV(Hm$dvn0V28;ze9oy!3+j@*CMd|O~UNCLdkcDtK zx#$u2c)N{wo4U1v+%aSb(9;9tMm0YvuIgxAYrJ2bY6oNL)p0tG8rD<$0*{Hg1}OT< zEPeH6k-0As_9cmJAmZJLFs+-#lj~`oyZ)%Lq<{4Ss(;?5#7b>Se&JmTeOEn2hIs)H z>l&USj$p=`_Q36|)hb$3LYA>1D;jN(UBgWMM-#sko5#&UoI6TQM_HQTJBl5~{H4}M zwUf}nPNE!k64~^VfkBLxGx)0B>qYr6f>E(OvbTV~WFT8sYgYO+U5Zys!IQFo`fC*T74)lE4@udhx&Pq& z0wx9$thLV2vm<&tS>H>< z>0LUE7N~i_Wq{6q19d32kkkqZ?+5V=hQvQ27yYE-VX%f~L8*0rMgs=n$0+Vdyui_J zMDXgO&m8V!)Rr1|lv4bl1qvweA4#jp;sZbv<%k= ziZfl(jd0KChs-h6pncye#B0n@u8!hfxCnwlim4eb|K;I#72eXE#Pc2RN|$>_Cop_L zan7p=M~0-eH8m~!sO~F|k!r=*Ho{&DFI!uLQ;HPb4O}}vj1;O_SU##7fp)^j@-G0i4^(1=*1m>?I*v z&byChvvL{?ZbRZ2r#{SHQi}v5jPGu+ApwlOoLoISvJsz-U~;a*cl!_XHzxjS^QGH6E~4xw#R$Br#9ju~5U2EQ9{)u?sDgrY@`AeG8V7t81mU#o;HCfs+B+fz~i& zy&l4T6Lm+FhfYvr>I^ zeN}+cW$8h|C{U0`PSUrapgC2g;5hx+Pr(uTgHL76m+_nz5Zjs8<&BmRSwOcc5%QG05|QOXDMMVB#{;2H;W8U6XC3B3my(tvP1Q$|=`z^W*XNhzjUhg} z8`98fMMudJgau&|{xq%*EZ6)@=?`qi4GuroDWmbxOT zc~L5S2_A6pRxpVjozTuW5Gs_tDFJI%iMdWvA0m$UwIiz!CFZ1wxXEEabhqzJpO^%n z5Kz3wdK-oNm002y-pchhZs#B`#7|uvU_-eQ2JmD){lT-5CIxQf$MZV;((qOTD*)kk zg{-2)Msy5zPiSh_yQsmHdy_Am~y0UZM4 zu#5%0BKG%Jam)e7+cdydp-F-{DnWF<*aNQ`UFzs%IXbqW0M`OsmAKAOpF~cYPrDk0 z+~5r)EV=)#wHjR7tP{77*@dN%dvilRn_(3MMC9;MGTdg=4QO#-*C-beC6yweu?Oce z7&wvoTp=^*XNI#%B--E$Gs01Y6wxO_r&9P(pEpW^0>kSPLklinB~2aS`V?_#>FcEr z0MfB5Q=DcIrzMNitm3pw+@CjYzqgNj^;Isakj;HYM5@lPh#^O!`#9kyQb$~|V?=o9 z5Fn?%&a*~$x$kA!ZFN9g~fgRu)w{2d}f7*^Lq5&sTOH!vNY97+SSC%`^Z1ln@<$d zrdeOQ_ce0smB^PQc9?LN(R~^$7Yt*Why_$!Q*v9Mkqa}ULL(A4{!4jb2yd#rX0MTJ zWJZV5OwcqtS)O6#y~2A6c~i}}Rf+uh6X9J&6k!_AxU&1?`V_KFC2$8NFq0DK`xydX zP?KNRM>c76#s1mIu2cM z860_3&Eu**@`!q~Q6cN%neA$HU&chTnV6l4eM;PWNvui{^nD_x8mpO`0&x@S6!JFp z%!U3F*BmiS1KLQPd&&2`&f=b+$RuZ216ZA6wn|A79zy+{Y(gW+Mweb@t4!EhT%NID zu>dD4FVL(8kisGBdlHi@GuBYb_KZ}Ym$^h3-e-&GDf@!#D2W{%vb{|1RNze*zTQs2 z+qqSub5z#mDWnWfofadL*+9&AyQ~g9ZwMUI`-0!`lHqfO7hBNu)~ch_)A|vG5i%8Z zJ=jkB8|DnqANNFnrB<^5f3o+h)nqZ3!6__%CSfu$^9VLD1tUhh>SvJFa!jqemNxRA zc-o41T0K)&ong0SWTgm*LVBCVxPkQK)81W-;k=TAJPL3v!1cnwdTL*Kwd| zMHp%SzllIat+1&VgVMn17h+YT{03ZFTfW(Av>Yf#+z!`1WE>*JDg|45$EA2c!M6&T zq*CzLUZ)i!eV2mJ(Q>qmOw`J^Bs;i87f4_ZAz$Wrf8HB=jSemE?MQSdnWW}j*E=pf zp0}vx{aCM4)bjotK3hpf4dm?(49Z*hlUhHh@9M0sm+|Fla*}3PxQ13RbwE&s2h{IG z^*e0Gqc!9+^}BoNcVh;=tB6*IqZFBIf_K71#GPNZ8um+^OwY#{eGa6H2^6NyEiPV` zu)tVupbxN+H5)>a<5k}%7hZPC&LZtdu52SstuAt!@}$&!_?Y75 zhRaF({K8P`WpHcQsgONu@rvh#L(0g>l8zy}>2Gxn8Y(*}U~t<-A8?12)=_OMg?$Q% z(cd>@e78;`PEC3VD(~*?y>}mB$*WZgMtJ7e*T>AvP(2u8TJJ znbx+hZJXR`Zstb_TrcrnF}Bjt^I%KD(3CG+SL+_;{lD}uT77aWw;;|CV+Uiz~G zWsVvG9zLazN?IhMMDwDNan(_M_(gvCB>uWdYg^#!yWn%QF|J}i_$vp>+vA7nv)Y+>WqANS-9HM5;MJ8%e@qcPyvi-yYj zv`{LHI^lH!O1-+3ox5!&7xfQ7AUnkMpZ|hSX)!u(@E!A>k;+IB^uszd%S2X$d zCQ9~1**?T;H+lU=*>95kLxO&u^(Qh5x_PE4r$$OKS_*3Ltu%+xyht9Oa`VcaxzApo zw!FN2*`^eI+M3GBWue?_ylWY0EfLqU*H5@~g7#@fI=}Mhw3LL5Tl6cRo3}1gRzE42 zuqQ{_qkSRo=(Ft{e%Wl>9mB;PKiI6pZ=GV>X-i|!>oRg!!)Jgrh2~- zbq0O8|6p5oD)7Z5+KrOklwkcN*RoHv50UMOnU;S|gTrCJQS_Vg^`7^YMbVLgdwRlC zERPu~Ht1`X*Hk>Jub4i3v7yxE^^CYb2}T8cXvFV?)e7mU0ke72hNZ5hJw;3Nbiyj- z8uEpoHeXi0Tp2^c;b23}sb!X*VQe5hq z_bl5|%2XJVD&AFW&kqY5%)X*wVw7=P6<1MDo~~Xua_y&m86zEmsXhGgiYX(tT3sTW z_)u!1P^yr3X@P4$=!1OlV4+dvB5o4FNGds1n-$mP$VpxYqZ;5&3JP5EY`tht%$ZtK zDK;gF;v7A@PQS_Vj(43wUdI(rZSuV~MBI_gFGK(Xbr^7s?FpMvnaahaLT6d9*j1T8 zw^BCw#3Bbd{YL+{Z_&P1GO}k4S7Bx8myI zi5q+yz7#H1$YUyJhrGDd#cK_c5pR%MjlKO1vhY)v9+i-E7GbnfIf3NlxyXa`6VJ0s z{cOF;4zn;qArH`puJ6x-^-~{$X$Kii9~j0_1L)@!LnhX)HR#7pxY}_YqJ0_{a{_x# zTozn8xT1Jgi3_^Kj)18vkk}kBngZKjJ%4gzEB__!>s&_TLAK7{^-oKDgSUuQf1o4Z zzi;h{jptr92GoP)@aPfyOKfZU_(V9bHnUMhxT`PtPumjLIDt2`-xy6hcxY}-?XZy* z!!D_LxbSylMfQrc5FSRUb`V^=fZY<*slxv^rbfg8_FxYc|+5kH5J2kmi0B|E1D|i z(|FP4<*wt?X0P0}{Kae2{t}HY+caFC_I5+Vve1=RNoyH#Eva40URm+@a_!TMOxoLr zCuA(5z5UU&oQgf=ckStacO&Af4KK}DG~DG{9M>isRA!R z(&~5EswTzrx)O{oY{5#}t_#}r%dLAC4Q~(Ixz)qplkA4v;X7|cC3Hw<*sTZ;oOiO` zS|)8S1EpZG%j<=QI)h_wO~ceCc!`_KNVUxIbhhexMy_S0T7q*)-@1{pWlG7N=S#=V z-`;iyHkYL5&uFE!OV7W#9VE>dVKmj(Fw9?S>K|vYynf8Yj||Ue>Zgywyj2lhvwVFD zymHJ)m6OJZNn-&5D-a#x4T*U!z@``8AZo)&{!sesZIOIWC5?3T=56P#<8&-z_LUD6 zLQ2V3y$BCER(6}o0a~~aRLIBlX7TnVOK%M=Da4?1lRArjK%W*ZEiJ?>it*&QFkd0< z{a;E#g5bkviR69yNEQ;j0(vz4@Q6@?$)7$A?ClL2Fyor@whOcHv7R*1$AWa8Joq$j zME*Li=T%`t52>O*g-3f_9le-FSE;`q?s2u_7v|AQ`Wp*OS+5Q=zfmwzl9y>#WLGbp zOY;QWLyobd_v=KzUi5RK-+-p25^h)n1w=_hZ(0E=jUurE%e8V?Qo6fe4g7^tm>BYH z-Hkkj423*Ovo%ammOk5yCPD0j1U@v}EI1UhR;As5W`~QOsU(a3Y;h{Cr+ewLD!$+s zn=NDwakOlHTh_CzW#Oq0xxWw><(jKgP1IKKDy>$ezKyJdAlFs*pr zV>9LGnXuo&+Q)e98InJP^{0pJW5fP2UjNw2n(l%Pme5-wQ`5~%op|73grS&DywNj= z-w@i#Pv(%eV2Wkl!{qe$s8EZZK?YC|`Nw)``gA-)){kyw4ZGk)Tk}Q z&Y(RlC$R>{-zHq`xT3fkaFyMuV%)x8YI2@V3>xM#`_yLJ1_oz@W@*{QZqlfr0s zrZ&2;KDs6tRhZ%^pP0s=-7C~~FJD$z+28Je`?hQ76=`oTP?~%<^K@9e^)y)Y=o3bn zACZyD;)vMG^3Ol=t41_@n%3}LTEi=};m>@#u0V14ZcaFUq+-+FKQ!7c%ij)l+Ar&} zUz&D9qkY`GN2jAojecjBe_W^kQptZA+V>2?jZC%pxp@y~po!rCykNN{^wG$Q=$S*s z-Q{yF710IDA4!y><(+tP#4>HPgo@#a7^#sBGDA*yf{Z_JU@^3|7VaxK5jeM$YO5ds zkay2N6+WfGG4TvUKuo?AipFbMe`X{L%)U&vUz(FM5wMP?sma$&$gOP>?U^(6nG-z# zS=-H7!yUIYEqeYM6K^mx9d^_GZ}g~(D?6OXKcUEI+h_lTwiPxYt4y+y-s3BNI$fDq z+Miyxf#(xJVI!sU(nkMfhJ6YUx>X-4iDwTZ_~)5rok{%nLTL05;lGvqp`?apV0(w} zY)gNezaeWJ;uUr69*;n!Uq6W#c`$2f^4&fJzrUov9XZS3n#G~WyqK9v{Zin?=k&!a zmIk6C_favjRV3i{u=bco9C2c!h2YZzgFdaIpQ3LcXaHcDM#3tm4-Ryd{8x{c<1>cQ zg*KMhAxn}Iz!kh-tma*xSaLi4AT(@I^_*w-mF&fl26Yom%e-`ja~Srh`ca9B52Q zJ9Ow!cjBk$W9W1m-UE!nB z_n6l1+PME!K!jK}#U!R=)sGr+DJ|YMWF(&?Mb~simEcCj+fFbPd1ICH@8=T^-4tzv z&G%RB>eySWj=c>Vnrdpg?|!{8@rtzNXWnk|B@V}KB(&%>s-5s?f{1}v^i`zFWsCwlI@GV_C@oTPItW(X!PIsV&PpSVgKSs`m#f{5RFwLt*=Z zu>WS!zrgDcmBUBB{kM(wg^m7OYW=^h_b)vAIcu286y0AMn3l;_6*9%e-Di)no~xOy z-?D&-NLvwN#GP;5V3tn9!1ns6GVbKJ(us>pn+xA^GTht^Gzg`>Cl}`1~dF5~IGqnS^x;+3`m-UQ0To zkxhHtjg9`B8vQpn`WH0%QK?%R{UG+Yjs8$0>NJW@6wm*iH9V=bZru0kiS6h1Q1DlQ z`Ah{Si)V1kGDNsf$vaG5rup&=M(m=)e9ECY$xLbiGhyS(?gA)T;JV*G6g!&w3_o{1j|NBkqw!Is;fP`s5*B>H+LLVM=MoESV}^JUhcc2J z%K500>0Z5HkE5V_^}_c{3&FhAzumD0<5y*6H%8w?N9JR%$xVGVj_zr-FNK?Wqxj&F z`ue7xhMMl@H*8?}sfi7~w=+e%*&!BYVs-okqp~w-zd2Y)y!Hj&LRPj1Y}!jQlDDJMD+vNM;Yg%@VZ%IPOOU=T{%7ry+nxIOO>^DKs3$xE-B{}JEDAg#O=_6^H z9HA4eIm{0~RGQ3;C}5UvTzRf?c}{uA68vR3@;&!CzMw%3>TtH-&|2h zg7yW$LY8alL#IIRK&OaqX!0!?8mEE3Ktp>U`Jq~s<^LBN7VcGPn4tu|`$1dFhT4R8 z`p7YwWz~3)mIKnJlw*NW$kf_zt}P^VxF}>RFv=9_xUGGSAdp$u(6BJ!i9f`tJNCl> zhhFL<9slptJ+O;X=NY2}+T+w!H4BgSk#}g8h6H8ldp}_ENnGw5zFny8BX82j9)cwm z(==AOdJe8b7|YM#VoqU=g$s-Ht5fk8>t`B0S~VMhSA(`A?rG}E@&Y=)*>=MOOoq?V z_VtN<;%*BzMyD|kM%5>5FS?Y&R*@>9r*BD>5plLV)!Wo#yL{M55-M)QMA>OKhivwa zwsZh1&pm-`u#T9;zLyT)j?Fh{+3-5y11NtN5ho>G#yVrKQa6V;56S;HOJuK4J19=6 z#w?17abEr@VYfo=qu(K)x^=u6XE+~2nR-3BJDxc0AU>Rye_Yt9kUQwJASU3@g7)su z-x&$zruOmg=?nGCkDfZIe(---dmFf@%Cvv{oHOrm24(>9Ww6c}6$S#E87xN^au@+Y zz+e|?VNMn*STM=`~AAE`?~1&y#mfeq$^~rk9TYO=IXWcpFn!Y zUO#JOC-oe^8Xi2w!X_4lgcx~>|1(N0g_O>kQRSOZ_&r`amn6-iYecX`pKh?rmfJHn zm#|4O`*{6zI;;tiHA*hD_#C9}8j61WhG82dC2(qjMsvaa4UAF;aZy086sSU@ITHB{~DXVNpaH_#7@(8sSFElpao}< z_M&%RC3>_bRZ_pVj;OAfxQ_oGcdi;lU*UZHLSdt4-GJo#$hvUVYLxEaBN!!;1 zwf*6m0cQVL$!|fij`S04ui!=&?I6_x1&HjY|iW#&i zMc5D7m{2V_mpZyJ7nq>>}hrh)nhwxcL*o@dO`|VV9T-7XafV9 z!Sy)(I|1l|h2C48D#{dgYO&$0H;l2k*3sLAuftezsu79@L_+>sf{aT?Ii)mz+H3f4 zq)QYz**18E=rHy4z+!&9(&Bo7PV#lpNEY`?qMNiPqs8^o zoM_m{e~3irqDR%5#HrD#VPk4dlG=|BR&jL%YR zSo_0D#r?EDftVhm7hUO{FV{VEMAUAXc$fl9c1)xsCWQ&L2NI#mUJt+i3jOITfDm1# zt`^HoQP1aB+Y=`dY0@DAhx|x=9pjc=7Fgn*06_-ee%Nydgo%5QPBM)Uel%NyZYK!{BAGtr%L~e zz}n7TGjv?hJ;WCLtfjvv6*97HQLqx<{sDYDIo(UJaOKl9TG@X7_b zSkikfhUc%avmy-xM^!j-H<1cwFvW&T0ax-$%XERK4jCCuX{kP~9Fw>>N_Yp?(`!$pOY1t(7(vlomj8Ah~py@GPyZq3OIVMHxgvu_*<2#8dre~2Q>7~Nv(&QLj9H6 z<|li`o^!G$PCT?l}|`#s;w)> z*)(NJ zQkFW$gEgk1a3~*`Fu8fc6stra*th;QN|kI-0-6Z~!;y^8>^?PUcD9uqtUE9_mK4DN#(HmdK2k@z0T0y|Ymnu#VgiRPBc@QCaz%P)Tka`zL zPDGkT5B^^y|KsdCNsjYXXu*7tJZQcVB!AEHggLapGDh+jDBR0MO$gOPoGXHzD}n^7 zhi-3Sq<{7%FZH&DDQm(4r~~d$|1(vb8=hyJVS)8}cWCgp=tr4mcj$B9)S#_a1W4E5 zN`}Nr$*q|Ygr}+m*9Rw}{1qxBN&0l%7H>@$Oy;Z3PI7>ZoA0S{hJ|c@ok{-63);$F zXP^cM+M*cJ-QI?OTotIgiud3M@I2_n`n}zg(qjtbfA;u9pC1rtZjYugFSBe}Pf_-1 z{)&fgB|!eNhi(zRd8?8%$FRpI`ur1trSy!7K6{Ah^SpER!(;+XH@M`yBayCRT2|mf*)+?L(p%N4_NW;KvvQ0r)pj# zbp$r{*msCiAFA?+bQj5r@6Qc9_u#qvE!pB$Ua56a%xARwSM}P(N~)#o!=9pF4JK^8 zinVpXrY;JJHwH-gPdp>S!e@ngh*L>D4tgNnf~x8SrucMJQ%p&(7I?+vmaYD zMb7W_&^94QrsIKIL`V{(T@kEZ5u!zR=Y^KU5UbnZ)dk)y(NcjCotNmgeBl`rY2l8C z-O1!T>Cz&1&bCRC-+1|#J?x~0+^cBJ$eL6oolNr5%>yYzn5|SQqo?YbdWx~gTa|3S z%dzU!iM!{qlbs8vRLrYUPPc;ourvS;34Q!AYqBC`9$z5zMFkx~a4NEjs~ruRB8}tuhLY+H+q(Ic z9y(y;YenPO*DCULAiiEId>u$je);Q65AAUv-3Hb-7L=xWe7c7$veyV$J}+05^X6eK zmRL$|%#6^QC)28{f{-f#(FvX_=uudW#Gl~1dBS(!k?%SudK0c*fy4!JNFpZl@$uk>})Gk1nvr2^|UwB(E~mSjG8a6F5gb+A{x3Pkyf0=oA+PPd4$`K3FU& zd|RMxSJP)mU37tn%=+qzK+s@re!b--G0%DEPkp%{k_bFkdGno8t5dRS0wdL8*Q_@2 zIKmwy3553k7bN$(z$ym~TSQe3gRe7hek)`Yt&5=T4sYdAjs!Gc$dx{o(U+3q+(RQh~PVV8)-7;LdY1#Q#`bFUj zCh6AAPR2t~F6>8I5U7jTvmj(5lp<^dzakpJfl!6_Cj8dp*M-o6upglx-?%X1{_ zgsnAbk|N=HHT~g_=hj`rtTlXpNa)WKSk~$)==t_X%wEo&#ZawQ?~ZrJx%y-4$p-bZ z-A|q`de9O)*%&+pl0p5f1k0i0J`D@m8Go1n1HV&tM%Y!TGE3c|n^jBzySe^et>2WQ zpvkPt9xy$BN&s$OqAS<~X5{5<#U0F?@PKWXl?&cxk{_g)DM7RKOmZxxXv(ZAI%y!BtS>`x4C zMluPsaf;e91zhJ5*^W7u10zs7Ma@hJG`fbMi_J}+#ZKcWE{3S7C=3v!p!TSGiUE~} zKqWbnve0zCt9SvJ>EYBm(-rWM!Y2~A5hku*Snv_)e*7z5dKzgb-^chgnJ2{s7kas> zb$MXxJ(E!K4?bp+_j-M9xvy1^YCD-LisO+*UShpgTnQEN#LC_AM${#E8tU@?BU4#3 z8t3_>bI%t3U$|P|Mx;an}95!G0InZY3h!G?2c#r7DLF3 zEOOomw9u4gq16-*RqOdncE{)YEoMGllGEvD_sc=0I(1a5-_mdmQx{HY{j$S@nB?h{ z(QipO)P}W`#m{=>B}Q5fYLtK)op!p_FDqU4!3T`Alx~^jj&{y&W|G&?`G>Bqx{r}Q zLE8^rWhd1vT#U^}C7<(d+U|I#Us_ix<7b7qn(@ne6-U*dn1!%`%oYXRlM>ITd5vPL zMVv)#XFFw@Sw?eZU5oeq>5TMU zobxT_%8K}W8mmXWCAlJb4=xu6YH3QlFiRefCE1)^_g~(k>4Et)mA^0|B_1NA#GKBL zy!J!4a+Y2c5OqGprBK&Eatk9#v!sO{l%V7r%VlqBSvEX9INvYQwXxnVt0*nf=Mx;n zYPw#n!i}5F(O(VtS*eTeU9T@<*#W=EJvWB~qlPZ(2MC^~3z)-T|GUd5uY33(SFc9@ z3%bW3PScQ(GJ}+(>$OY;N9h?~%2wfsD2wYK_NzjALl@nli&XU1pCAk&;)+`yx|)z` zcf8iG@`^T+lzNFH-jcGoBHprqbhG5j+;~=GNlMejM`JRKqCYO|5<|n+q>|GeE8`3R~}*NW_ek& zi>r4sl~*FwkfvHH_Q$uh)HkPLhyXrar}FAoyB(nA)%@QK|W?TuR+#QAO6|XJk!-74bF4XuHg6Pst=5E-j~2aw%o_S|FLg ze=F7oKFs({il~1;`;VD)0V%TtbYWe@R!uxvZ%@+N_AFXK%9Ijs6sKuo zjfoheNF?XopONaNCp=B1{Av#yVmt|Vj9C`T5^Z}n7TKGGV*DzPVHMc_b>z9o1G)78 zc}y6(EG&JIe7=YNia?;to9FosjDdahN%B6%=6J+Ie@Ot?(bgV)mw)F+`gKxR{_P*> zCi2i6Bf@n6h2Ma3dg$->3dLPmE28N$m*WFRxWUrBo_4=1t)KN(a>Xs;W2O`5jux-3 zfet4rKsK&x=xF!I;~6S~que=M0HW?CQKt9|Mtd;I)IfhgY7<(+?vA(kO$-m2OGs7w zUm%qgq?(XUX!`J9Vge1@huK;5p9Ey52c(T`pp_)0Vt!Q+nI7TU`qe1*v5o`y)Q(TL zt4T@{@(Np@oWmVj5kUF`MLx=4c3>cCk3`Y4>hOwE-FR65?~XS$5Uf9vjG$zNn_0p| z+AR7H1Y+B9c|_GIo@YIzPu11|oEvYEq-hc{u#-RcS_5b1lwT&3`^2KqNw1O$70}O+ zuh~hgjH}obx}99C{n;0>fkbrTvVg*A79EavrswRBccx`yu3oq#d5H%zqX^wX7f)u3 z9$y*BnALVf(GrsN9c6rqB$iz3AvNgqAr}+m&M5juEuv6Qw+~!F>iJ0&T|&ONBaK1= zvHkk8BOa=sDQP}gQ+N|rgPvQY!l`wLPhO3!5aq_6rW;`hLG^>MujwU*KxB*!mcWu; zeYg6(OYE2MFe|fAVdxCALxNtDQE$8K%T=1j`ueg}jhD3MFnL&Oa}_1O41MC{*^~vW zk68@tC+vr>zm}CQ>&q%lAC>J6oxyf@m#up3dsfN%wY=u4X;f`IR8{5nZE(+|6mEVa z-_oeo?D<_5Gzv49*W)0gT3%n1O%=^ewKmW-4UDrvwA}HEqb3Vi$jGiZTt^fOC&|K# ziDKan-XdUa{MPK~sd~O=6enltq{ZRInH%5UJ}J$A50S@|t(wZzedQ(GiadRN3pQq; zMVWSMkan@E$o0LC!4iJj5mx0$sCh(ZXDQzX*#1c5;dRHW3BL$x)?oWnghd3!NKKKm zks_>u$zma?qU3XI=;}{vSSl46EnzNPuE~z72+PD_p(26W;I<$0*mI*S6Qbk^%M+Qzu;WVl_k?f5OpQ88_52Dg zxa_#HW@^+G9n+Z!=zZ+u?#Oy=P?Rjl-=e(7sGLf4B1Iw2BQ%=4XwK={Z64kZ!w+;% z$B#Gyei+k?yW8)P!t*fr8saeSXHq8_{g+$(AHn9nDv>s)7{JY47^@NKMek8G&*X+T zYoc19KRG3;IX7Z=nCov6SB1pYG@-vy?b@JjY2;iVN?H!6U4N2v?}1hZ=i0#4Z{RRp z7aL*rEqQW^(I}pzCl}Tx>x^1vvc&!_FS|tlnv9LM$8pJ-euO+iWU>24oIRKMUJ^t< z-g)#~Lf}>rn0k{9Lc`<#3B+vUNfP{WOWBxBn>I3fT4| zUikBHtqeUwoV}LNK_t58?9g#sonU)eMfck-Y_f%M647|6v($^t?8>OlCm~zXW2~7G zG7<6+st{ZV-3UVn)DU>32xf##ggk^&gbD=1>u^=jePZ4921Qm%&=K3Y>b6gZ21U7X z=HdkVgouHeA*DDYb{?msgn4-NjHG5~v21sM?*aqv2xR&02z2B*MORNPt6?bT%i+F0 z3fcRa{ayj3)dguUW{#jy?WOfVB z?7iIwIHG~zXx+-3 z`H886R4Kk9u0KXy`i#rIJ&HB&y2@Z0j#Mjl=En8ct1~%QjWfE@aOPT4vunusvQe&v zUIaT$>x^DbG4)Yg%Pg0R97Ld;$nD{vpBO`93ZV{gtqIiI2^~3}lmz+Ch>##nW+qfi zO5gG)b3o2J*Q6hL>5w0V&ELJ)5MzhW)+{jk^E_c=5skp*po@-KOI7;@u^)%KTT z;UH^y(Q-%4j+p#y_dT8XLeb-iznW#9^&X5RTO^B(+2J{d!jMu<;(awVRg+|`h#Ow8 zBsUImIkPmak{q0q4@~KmEcNfpiJ!tqvY`mtGFdBG0=*<7eyvxWO!Bj^B3Bae9wXgI zGm@-yvFtBQawSa}-O<}-?_%nnqV4ThH*idH89kh|xaQzhT(o$e5B>AX-oMX;1bjBR z=e3)E%Q+7(v&ak4aZ@HGd-lh*`bR{(8UgrB0?%ONagdR_qv#IOd5ND^EWqfn*cHAT5nAtzwcER;oiJt@r?4+}P6VCXn1X zZNS6%lF1RFy1iDrWYT$A$Aj$>d}A=t5UAjAYWOA^0%TziW!)n}%^i zba?(!VPES9eZv`E+CdUY*fuQev+hZWF7{;J zK7;1nze%?B`((`b@VMLQUzT&M0~?5>$lSOZNm}TjADVsR)3QBURvDfV+$xF8yih+7 zP|<%t-%4;0tLb}{Lobeq`Dy@c-;3@uVC6<&%ne8)m*XyE6oq3FL4{(2B#V()fr||s zX82(0r|IA(Ze;CCdIdvs19m9W?;Q#h6{H;EG zUwhZR;bAjC11B|d>M~dCk8AlWIdze76)sR?cKoTjS3E_kc>|L0k6%BHyVlBqzpFA= z*0WWh{p{)A*wN9hP9)>_zOBdtr>rwf+<0=-x=4;%5^H~d*@C~xkrIwtXK~c}wG~ILmnz~kzb}2V{^@6t zRaJl4@(uY5o>}nvpd-$CoUV~uYf>{wzfH^Gq^B=j91OtJ68dY2_U|)kmgIhOfJ{A- zo40&Z&sKeW0A`PW3MZ@DI)j8RN;qhue(u;tkZI4&F*UJVDCoMI_4bRWf#SL4s z<#EI2C7pqol2QMzL`EX;ek9=iFiGKBSpy)D*WppJCuULH$3QP(mO<5hoMNK^^B=Wyc(PYq5LbrKsOk_U;g z1t_Jg^}@9_41v7m=^VsfstS7|=p8_ph`%K05*4YKO`$l zw$<>&Rm-k&T0?SzI#H06-*}Oz6GaJ}<%t9=s1qe!{j(-ItNbF=h;kob3#|X7t&&V@ zIz$8+{w#f%z;EjpEdsELJ}4mn(@R6oazwvK z2RjH|;4z~Oh>pkbP(toSEhWyME(#AS&Hs|NN*7r>XlwGKlv$Q9Xp4AJ^!f$wEj2uR zkxevCi-IE5XR-8mr1$ZE`XTG

?Sj*^r9atke$9#wXqR3!b$=AL$h*L3rZ_iQ||d z`YIG#EW5TrA4ynU>2HRh*MgpC0nV7J2SqN(A4a*BFQBNG9-m>J{=^LP@e)E~*q@~j z4}r#!G-%w(6RBM&s<+#A*&8jX>8y8{SXs?++Mcp#Sts32$_CGQk>@&|J7)OaoAPyJ z2%D(;+C)R^=wqSa&;DTh)(a(^;xjOmxJ=qH`xsyO1C*0$=N{uX{Lmpj#+UywrQL`Y<%UKMQ0Baal!UmxiP5y-g1v+bIcV z3ztf#@aAFxBOH3WDwxqhT%MNmMe7WyJcnotooQ9+jVg08M@HHb4wkX?Gq^~DiRO=Z zBfv=h%B$nSse!yU#lSNDiEOZW+9vEIHV(+w9rkIptzr28!c}(SB)!+B9cx7eq&8z5IlY2gwE?8@ehi(?4Sq_9i(&A?6vIa$18+@xL{=8~+an!N0|D5EZ&M zC?;T8b;-J<^IkB0cyVf0?e|`og?P(5$0qsSYqF(e&7B2%ol(;`{pG9BNPmbj?DWEh zmQ4ziQnwh#RFe(&Q!v)ua;#$=XT8J!P(1@MZX=hPFUJQAMORg3A^fc0~ z{nqQ4dVw+WQXuu4F9QV#x`gk%9bbDdFcsumQvxDxM7w2_VY3%=f(XSKKqR6ZaCjia zH$cE={L_d=OCch+x_I5*UR=*Ld{!4pYj;xGERptIio0KB%wk|ju4*0)$A6JLU+%3c zqPZdthjR!bz1A#IBpt?RvzY6A?$mg?#6XN6qYn@tAk&7eqFMOXUuf_s^Jl<-A~E)jb13E@s!GuFtO&Mo z&p9S4_!q=hN>uz*X0|vqo6UP%l5@pBpJL`1tQ6&xQ_Zd|u0~a}%kfsDx>ZiMw1l*N zb}Q#Meopy4FoB6nJO0hYUZ%K)l5veK=)rl}T%(!|t#YVwCoVIVb2&ITHQjmI3qC~^ zML!RFJ{&BV)4S*Fh^(6Hrk1%g-`~Va^f{YMhNZttbnSMt65BCveT(~p7TSML-s37( zm6^E}VlSk8{sAWlr`}IL|GNbR^310YciGef^S^vu`JKufxcs`GKXPCMP2N?B52H4a3zYQr7D+F<{RNyQU#XFUGW zYgk>nBX42=Y z06G_qyIueV0Thi1_zVFa2{477jGe=dT0|UK1Y+3FVy#e^j3jBnAwd33m}rGHKClx` zKu7R}v0VewNg?Z*oE|Z@dxW{I!)S5+fh-w(Bn%+2?FLxEi6^)MCWB8*>N(7uAcc0M zVW=*rTue#O8HgUNpO(-Oy2TWjia!4nG-=5b zJaI126?=h!J8zJI*uj$r>8AQ=Yrn&!)ui3B8q$;>Nuh7FLYC>RO|)rgBr zUw=O)FewL{(8CQQs)^MCt*9Php9l{X*eY`ETpZfo`LH>!69&B|ciA{Q$&9=w^h zAy-@sIt-PF_h&9M?+*DeWJliHnU3j=(~C==&&!=vGHY3><&bK2M9(hmGwj5j`(LU) z=SAL1R4Kb=4^Idwu8qqUk>>n{`U6&0%dlh`8x`d`Hh$!PI(^Qj!>7qMP4O2^B2EpPu z427rvg}y+j$FgSUFGnFXniPqW($fJ`fe#0qMUx~h?;E~=~gz{t_(W$SCi;(Xlq_3B-XdOgiIizWSidh7@W z#D3tG0^jA(S6x&C*eq5KY6+kSj{#uO5G}PLecn90N-s5d$t!R-;Fal46Ji_n_1SuV zhz-q|JIc(v%S)@u&2B>U%)D~*@iKjX`OrnzP@ik4$Tf7pHPq!Aa=3=}xP}O&cl$Zy zhuQu9#nR)-!2q+ld??Y?f3fDnWtfSY;;^yb9s(qhbL<_c@3sod<) zqj)K{VyS@W2GxqHTQ=yC7Z&V7&&~z7z{YB%#{pLE;$97 zpdW%PK8m0~phJrI7b!te)zl~@O68-Jpa>=8lzxN~d6ZtLBWh0_&{qUi$;&|(6s1^- zM16TCR)YelKI)EaQ?wvPCPj#m%TRrKeUVk@Nw+Yg?)Bx!wJqI?&hgR5kFS2EY59shdodFI*psJj-2CqRIotJ~6Z;fxM01=f z#dY28veIkiRsH4PoxgGOFsjLv5&CmWA%rj z`lqM5^ltr6a@t){ZZ}iyW|7ehTT=<`W~Nt34Fpg|e`+|8+TU|H2zvZD-(a+$flX~t z$iOJ*?$WoLW$wXpclS@dX32nAeB3aYAbc-9%vWe@RX>&PD0iCWHD(25S9Y`CHDkV%LdA&9(O7-4%_^Y)pt98%i5R4r=$Bso zusLu@4{1#~?EM?od)A8y#Wa?eNUY@_J2@h^-=GH<_FSx&`|K-H^OO{t789S#S3m zb)wobuPz-P03(%6R#UoUgV&Vav7lec=#+a^9d?|FQ zahxf7cNY9WD0N}E6Lv&>wx|A;O^tAM-%&t)IdBaw3!d=8j63QqtmS?R+mUtW8ctMW z9cPY;L*EdG+Qp&s#kxeKzXHd=&>9hh1)U`Q$gJa2!Ld9@o*7?WpFM24KldK}tW6n= zE^7|vXgK!$HT9(vi)n2EEQX+pgbT-uJBqw`AXOY}xVCdd7>gpi`m5A#txa#V83t_8 zj4iU=7S(IJFSCQo`;udNXvTdgzlYB6biZG~B+sGjHl4*5GvG4M{##JIlnq)*!;486 z6=c&xzF{+H+c;K~E~djszcBK83r|4wi-d+2J_gSNZFzBd`E6V}&^arHRkq$r*7vi{ zOZm1*O_#N8dG1**rtP;H${GW&M_A~^X6Ib&O%X1bNvS%8u#nLv$Z z>3!yoEZ31N)8Ub0MW>~WixDF$bbVxnt-4|Ukv`Lx5O75XfS$s~m zFJNoNhjm2w&M7#{54ZF8^z!!(@No7~&+t=;4{xd;e5N&wWvAJ!hSB)cUfaR}TiUQK zow228ZHt(8P$5G}Yx#_n@Kh?TD2}V;0=N)rhFH zSZpeMj@#^co71RO^~Z7((nU;<$KK;j+fWm}K{emp9$xDVuX3NNRwbC-A6L6SP3S(L zS6R&N1N!#xijNu*LoG17_g1?PCUo!7yZ7k#5N(N~&1pp&wjD^L+IqeF`Q7Rrw8LbFw-A^(n|BQ{sSUnxHt^1Q!`W6!(kP z)3!&`o5?(JjHa^eot%%aVV@5Z zJA(YDpR@ArcH2&Diwl!X4wpZbf-^V18g>4lc`BI==PV|p?6Ht~Vf z%xZ0V3AR2lEOoJZApLR4KfFvAw>#RkySzDr+7Vq}|C2L=c0{Lj5e=FQrXtLqAxi6$ zHT`Rp)i7pynXDZHHb2-(E6J)%SjI!@zwSu&i3V5#5#!D{-Ql32iR8cuU*e!IFddsg z^`@?-cbb0R1j|h(bqefP(%V{b(lQxRcu52OWj?iWNMVD5R{u=Sl$Dau@gIoCx{f0m zd_&akfO};a+e+z)36#7*N7{(_CwP&Q;J<*{TKX_du*C!tBWxYd(K?%aouDp(Ht~OK z*R&~7PZ3MWnpg`%S#iJ2LRl7I#`oW_YT6*_XI`&2@EOsIm_7TiCmd0qGYGs1@$)tv zBNtV!i*U)`kzZhr;^sVc0q2@`L>iBL>f2eenStnafgN_LV%_d6hb_k{bC|$7Pnj)` zuTWlB?h1oRI+oFBi{<;pX^ynSkBT0TtzWEKM(N`oz~s{OO$^(KqYw;UoejJ9Y;#!u zB6Yu3?U);tn=47v&V8W%pz4SZcY*V}Ih0PBMs0vxT{H)U$M@T>Kx@7j-xK!5py77g zkTY37(QzVDB2t?R;^T}w$-OiR2I$sOHV!$8J z(HQ}eGa<)1=dFWuR~gS{1YDolF*srzVQfx7nyCW)eNIsZk={|!S(WVE^rREsP6gF5 zg_0+PGfE)^>Ks@5jTfxG3}T{(>7TYKk|XS?q^|{U4ugi$ zbczkKg`-UJ5GGMlJ6b+HT%{_W79Q%)N;_U0-Oq3Ag~utxuVH|p)lKs^%Yqba@Wx^D zw5_0BkxCIGikD)G4>kK3X@_|9J1Rw+%Y=u7oSC828FfrVtaP?fM)vN6uS;BW33=A$ z<7gnKe`5r}IOBWzSf1mibJMrZ)siWK+QAfyQewA<&s-IGzsYEhbZOgf>gTw?zu7f8 zl$AO}70l+@>J6qKzyZ`0t!n)4t~|(S6ncaBf=C{8lsUsm*=Zd!DdO=1-62Nl-v>Qw z_(m z+F)vn@d8s9fJW&HIF}%&_o_5quvM}tgDy7UC?U#z;n%XNcbXptSJaAr`fi?p5Fd7|M+b)STcl{3LX@!}*EX2vb?n2`g( zmaRhz(2{oVmR2$`5AGc43{5L_HVha#X%UVRq%(9JM6ZI&7=Qzka4PflkaqMC=_PMi z%O@@s#5D)$Ou{lkr2>$P0H`?+z{l;TfRu;)Mdn!24BPq{R!jw%*@+%sGyWUE ztC?g*996J0C75E&=FEmt2=B7FWx++%X)GKe)RvVPXtV_B(vkx>uSh@ll0G;Go(mP~ zqfEztdb_Nk37y1HW1}h8XbNIwmD);XS1`LqrYWkFqy(j9F9^Rp(w9cL#ri;R{h9L^HB&nXN{MC}ThU@|U`HGU2&|MQ@C(6!hIzXyXdRLBnnv!I%QZDEJs!H zFtF}jYF65>S8J%b_7YicSX%5-ZuoBc2swym2Pr$wc(>TcRt#M0ithZ`w^ti$V+a9w z?=6Tn;y6mB5V1iNvsJ;4wYIRYBRc}JuY({~ydWqV{r$A}l)VmOcxp?%CSDgehvi~i z3OGMW`T@Pjw<3?s+Q)JG0-gAE!kSPrkqNnBQ5j38`)g)lApZdQL(cHcu=mgIQeY~i zI)bSj=B9vuOH8qoEr z13OzidO-D|=s24edu)0ie6xY48d;6mf9JA&C2f^GWDX+x9MT4?In*j0ZsWp! z&%#(aTnNas&RaBnG2r>iW=e3h#Ym2rNk^Mw0;4!>FPtFEQ)J~>Z^4HhCaQG*zHlX9 zyVYG1-JNLYn}$YMys0iy}$^xnEnXEHkp^Z1A#Ezz#vRE)i#Ph&CqYL9zw zwwsin#?Ddti*)h*>1r<4m4EQ2Io6HY;S(;%KiZ$l72z4~a+Zb4oI|*PfKATGCZ_4i z9o>scVOGyakH!j;Ycx-XjZT;43$JDRJiXSnr9h)KCnV&Q5sw9=JU$Cb=rw186*1zZ zkI^}jrIZ|ehoOE-Et@8b7k7M2EbgF7eeB)h9JStwIUVEfAe};b0Yumb!Gj4PJ%|l{ z27^||QX(k(M!14g;xHDl%cSNOL`rkf<`@kzN=IDS!Kz~}`pLuiWQUT>i&L=e-?P(y z4+O!DN=b*e^OSEKxGc8dcH0ET7Sd}A9k5O8lU%^I7bc(d8++^gsHA#t5u^M#2GeAK zq}AKUz;U4<2mx2a+NNivl9S%ORyLTMwzZv~(94Go@Dmw6B&aP93#`(@2XC1LXX{u| zlvwo9q1fPFTae_i7qjp8NDX5EN(nT#5@&u0%B(h(!9-*WeG~62?nIM_5jRTt_ zgXzc<-lf=Wp_3!sS|U==LW6)k_U-onbzrg#Tmb z40BC$75E*)w%4q-m-B5~8Czqo?bUYMD+9Ks5w3@5!1hwdac{5fgIb_XDosoj! z!J=^6F4eEu0LJ#bwugb~op`3!NPz%$FeB?N03A}f0|_8soX@{F)TO4RW_RX3Ss`!a z8+@ODL`y-U^OifmIAyW&&ucE8efdoz|FRD==@l=l^gVVYdhw8i|M><!DX=Vb$|7u zPN=uLUF{xHPw`IaYPbD9hV5gM=E8HE<|0IVSD~tg{N|9xZN6sYx8|&u0)QfSJV2_) zT)p&~S2~$8y0%12i(oVA;0%&~U2EHN_6=l?#5(4X!W;uz5CxutVsC+G9P7^Zh#6vb zC2T0>zd11?T+FUXe#N`)cV70H2$+C`$D|iwhsy{u^7WE%l26UhrCNOa5}_5}fEEMH z@&nQw;GJPg>K-%IxASCMJS*8Kl=K3_zqpH=0f8wC*kqw0&RcpgSdhR-!+dY$orKQ+ zV))ndd54Bt<%)AZsCM^bpbSm!5 z-j4H|Yxr#%N9eT^PX0fd`4?LGZM*0CA8560du319XRWp!&LcN>`!(CPJ8l2b%Wv;~ zRWj74?zL_23Jrbx=b}(UzU>d_kmqlANd>96<<$5N#_-Pr#{4Uv|3mU=473-a8CmY8 zCYq^|oq1i{()tyoWrx>od<>ep>Katy9De1ID=A@us=@C8sUZbc$RAT>BI2^`^yQ~=aT*K z$Zi;W!dJaGcd@2~40;=#-J8awM%W&Vk-WM}b$#zyl#7U zQ`2{5#=0U!hYiOQd=eFsval8l`(Tj?oI8E&P~A z><4f$pWM+ux2_MTq@&C=vJ+)HlHuX7kExS^ivIH?nO^#`_iBrl?A$ZxjsUdUUJGjL z^^oo8;JO&)wd&(G;l$!YSsB=|h;#%eh^zVUc;$(Pjx@|PL-U5h4qa=&`2iHJ75e?p z$Swe_5!fO0oSGXW^cRuX=Ig|PwM2sjk;6eMxb_j)Ee1s^NM!HT5!9bOcpJWgw*a(w z5kqdukQcPp8AOFzJjq{>KI9^`yj~r-bI!hHZAY>c2}i}uPVZ7~vYbf~$=;xq;xj{N zV%<*DzT7s*1mIT~4cV3y0Ucbie5bB0l9p3Y6+EL_fbB6Gfa61hsV(=k?zAR5YUb=_ zTEUunmYq(Eozt^ms{v|lC}|S06G%%E$ocL(?h%YvrXcIJh!yu|s+TpS_RK*##rx!K zI40Uu9OYg`@w`i8Yf?nELV=KizzNY(FE&rAD%sMcgJJ27q}aB}CIFIBNF3lcblgo?!_R9a$cM;bNzrSGtr1O`g=rM*X9acuKjA*`sm zM?Qx_b~{d_QJTialiPQk*P=W@wbQX7HN53zdgQ}B@_`9N9LCm@XAez$i;%6jML> zqY@icrPR+-B1SRm@7hyC?e%)KA|dk9$mkcb_Z()9fK%1qRgX3B8d_IIJSPj4f!+ z>HcoD?vl=EI(<^BW9S(qu{H4clESi*DDi?8sAzsywe)W^JMroDGNN{v*7vj&xxJ8I z(KA%1dLG?7;(c`Qy#DG9ul*;(2kqZ?yy15TKHS%Rz}@sZE8W2Y`Mb)Yw^VNfb^8Z2 z8;Z(Mw^QDdmd9@vn_;7B1T^2n?fd7 zZ9(*>AAr^jKcR*XX_#=s&IkS9Q;6E-!W7aXPjFOou!ZL2um3JN+jf;=N3F#4dMRGX+N*`8g=cObIMZZ& z@IjvE$I|zGR=5V1Te!7lr6cfUTbXS&S6J~_VQE>(+9$ag1$QJ*=~7p(E?i|>o%-bZ zGJE-B1ZTdje0^c$TwemZ#g*$Hv#nlz2XI^xx^W*`3(FoWPO{tA+HYg)(%0Gw7MHEH z7v2>yl7=q5@TtPphSVp^3hnmt(z4rM`Ve#pt5>gm>^2nnl@+ckv?rE4RZ>uBsa#%Y zUwbp}9e5yBA_))@p>|O7(ZohAMv}m<$ zeeqZ>ev1>+xTgw9*6X>))~+c6LkdI1>D@V`^ z9-UDT&6SppzRpD1{iyYo>&pt)aHTf8Z4HMZxYi!cVfb^%w2WJCdkTpQaijChlZAlf zuU%Wl8D`G9&yOlASyO153-XW9hrG|Z>wWfJ?+;W6fau#_jSWvBy$34i&M1wZAxvQ; zy$A04{=vK6?Lg-q%jeKkPnNGlRR-I9fl9E{uPj}RX)CX;2f3$?mmPP1eqpK8& z@%>?8c$D?lUT+9xB>QGDwXXe{(rl)rSQ55r!#zRYGX$#GG3X&m5a`OHCzv3s8*_za8v`=THK0G>ik`(dE zr7lWc!abZOfXCiZF0z?hUs~du@gF5a;?a?Ep;jYx94m3cYC9P+Ss+rz+JceUjH0ZG zTw=nKgt_|M8N!S_hChGplSL(~#_*B9kmA3MPsYFpMxkxh>cU4?Zzw5!w4?~rO+oQv z7$1dpEJ1{5_OiLU5lZ=f{$KldE9d=7A+M_9y@=pHtA}urEgl^=o%FCInXx>bo zQvfG)BY$~-jl!3VgA@D|%7>o^_-MNni+QsHfqYv!4*mwxF)==P)wpzy2k_=efj;;a zz#(26`|DTp=8ZwTxoKQFqmlao-wU{E6oB9TlYQy90S_DpCyyy%yty0j(RwY>sLU<| z5_byl@#7+H0&jjJm^Xg|IB6HvZ+&#s<5yS3nQu1Urhg0Sx>4%OSN@7;UI0lDe=7hR zg-;p>C-^HQK71YEqy3=?_^ahU_$5vZCC_Hf-oZzR(eE3TMA8p4Sz<2rk;41(h zt#1`zqwwN!aDxAm!iQf5_-Oxk1Ajl-hSX&v;G_L*2VkRc$2hov&-(CR8iBu2eY-z* z;n@ZFXnje#uHXCO_X0jzPIDvr;SL{s{|J6ulkYtjzg>Ue%!dFc^NDMx4}KoMf7#2K zy8$QV9EERr%NKuYBps5c>N(E50)ada0zOK&)$br(1Ogu#Nrya>zpnRu@SA{-&STHL zkGTec#LHj3ozC8mIP)L^fvW%?t#9c8AB@1m03RJMAwCkX-j=icAF-`DrYizLta|2gM;&gXpoo#zOk^U?8d{6mRPL40)m55BL&n-L#9 zFI)bp#Al7E=kRGIJ`eF>cut>D;;8-bANYmZ<+V-aB%~6@Kw)o$dthwI@~Rdugms7} znT=5R7{diazok{a)sPzN!ORdtLn^S9zN*_Ixx$<}_;s202uo%Vf>$?Hi6kD4;z{ai zm)|dQZB_H+5=~&2D(Y&%@ z(N~3Bh^?$`997TaoJEl39Qg&I64{Fui^RHxEBK;tb;HW#5b2`2HnJj?H;AHtX~On0=mm8jD_(zi)PG%H{&LM|op&&YT1V2!|DGL3Wb4e}~9?*6a zC@Z9BNzRg-kszb~DC?Da4c(iJcw@WILd&@v&)1bl?PAWN+aetwyMD*kx2y`fs0#0VnIz9011w+)m5(F4%bLSFyla%u>xU)peS7>vC zS0+C7wT<;|7(vA5nyTeuedY2nUV`4#E|&?{HA(V(5PsA^eYD&SJuxl0G1($%vf^n> zB5I)WihAUWYluqw!WzCV{ky4^_ojwBgZ7B;Q7EAT3-%A$>JaYo*z|C`+*y3(7h0os zUnLwGAbITb3vFZ4ZQ%iw)5r1`WA}H^x8t%^*yL@P)sNCX$Ok5qc2HU`AW5ly3JMtGV4kfc|(w8i{W6_;= zEefYA<4dzf(+t$EZU`sI6B1pX#(wOWN2iC!K6=c*ARVFzwWTy8r;E+*@V2jnt81}; z(7v<0D#FRj;IL+IBWQm`MO9;CMyNd!51_PHFr3n(+y6p(h)m&5QvNEBOfsU2DUIP< zZV&wqC(2>jq7#mZWR)Kx>7ljw|GIqzo(6BY1L1I(R8SaZ)Oy;mWr7?Ym{7M?0{tSy z3UL$$a|Z)POSxxdb%=Fb6lO0O;>2ngAwjU>NzU~`tPI&D<(d_upZTSKW144j{<)&J zu8!=|vLi=TWus`TZ=@C&)?bE5pho|OpTqHA7p8pSKVM7j3YZ?2%@u1Qz-EZh?%oTmrO~?+zy|3EW zG7lClwAa)mx7O6+@sNEUQ67)4MYi#Wo@En1o|`Hw6agt*H^GC2Q`JJUtzzU28Ny_1 zS>!7^fAlkzcis^Zx=8e*GNZCIwTy1H(nAKl4A{8vq2I_yDV91DBHYZ%?}$`6{+eif zsrR8?BIJcQLD~YjfHeb)3*-p9WOJ2|KoGsll@Y97wa+Dn${4hNqc$YFdUG_e>gkMvjd1p;K0sRdr%*^$7k~)GQknhEvMuFf5{!+fzZlTJfv` zVk9-ba=G%<)FP7qmpt>b^)~{U+fN8}knn~&Tc(v>tamr~cqj0fs#@K!BXx&^8bsx|`9@&*VK zQC@U)kYUTCyhs{D?j$Qi57b_RuN>1;-mtuGbva2J(Ic!du8nnGab%1mjp1P=ePqm| z)4y)~tD^>p5Ch?_93aa7RRb`#zv#NGzR3`&qQ$X5Vs2*WMRbsP zz0sq=SV6tJqPWFbM_vvzH54w13d2)mWHONszEzZYWW|SS>~zWL(Mj{>RgQA_q4g9N z{-`|)QzgE7W$N*ZLy3w*XJjgqyHlCl#}EMw;I44{YS$`E@$_xtoK?-U>Y-G zNRJ*a27QLiqBQtG0%a+p8lGPx^EuL9?Q-wRQLK;L>_~cjRbx&0ij}n$_eaC@Md`AJ z9$E{r9-d}nIyjOal>7@CjDpweYw%QMh_!G|gG?Xl=SX>Yx&e@A8)o!4wN7O4bWn2-ay+*~PXB-T6>VRMh9lG`eoUWK z|CK&bC%u#Kl_02ZVYkR$$0u(@IDRr-`D2m8L2}`VvuHC|h8*_4jIh=f2@f1YSg4DH z%~KH`pA@ODFc;x*(<1c+HX)ptC+EkL{Kw;)=8SAb27IWmlku_OLw_Uli=Dl)A=))t zPG9N8CQ~K)l-(yfKT(lr%#^dUYBAGhu_!z<#Z-$*pj!0FdpDJWPg!I^ct*Q_vHXzo z=&l^n*R6&Z=4ga=d&{x?jYN*XkJSrs@ZBWumSX0uz+usx+A_)orWt(x@|F>}WxEea z^r2?39^fJvY7B{~LKk$@Eq zSJMp90dv#5Q4o^PW?0T`ST4Ivg}WyIeqA~^f`}`Y3}9_lWppjngZ~12_chcm|03{M zDeP}|7K@JgCHZ$Qnk!Q#g*Ss+t=Af1iy|<8Wqupwk7Sh}#^hhQ{Ql()&C7`h5~CJB zwtd+$hq+LcpQvmE{}ggxz6z5I2Br~4QDXPWa)p%zt_S!7d|E~B&2^&3T@g}YVM2*C zlFdJC_iuUDWIvA&qGW%t5o`_VXG1zN!i9>q#iMpC@*h)loJuJgCYAyy&IZh~h%nA{Ofrc20pMR~<_UdrwM0UfH z8R_p&JvWf0$7`)Xc?G=T1vjQKr-K#iab{CDBUQAY7cCcVpKrHcxP9hali#Tqvzl+#g?MUxhTDT%#@<(V;2tN zg2nUkCt^Jl{E7O$<4x=YZiqTB=uVyt;)0pdkA}=E%5YUfmZKN&pdLD!ByMT)`}F=_ z>o=Z+>uc0AGV#v-ibNh_q^!3FeB}OYM1N6eWuonE|W#+0nXvlS-d&8+hVEy%nJFPFtK=7$hgdy zbdIicM~@5()qIL3_Sbk1fjNZ@;BHd9AP?+6D)G@6NUqUO<_R%(cJJ?76?60#3}6b{n1;{p z&~Gw+Y2TnGH-G|*&T!D9Sl^g| z$ygD^Gsxw`nNWvPfYdbb0$E*$!$(w(Dnn7Z1_fn(?q(SbFA#-%H)Iue|Uo zLrYK-29ns9^AIjbo+7@UKGA>qaMlv%!vP8W2E`Y;YkkeN7;$2z;i?7F0CsGo!~#$k z@0TSaTe$u5T15@>b@df4yhB_Bfj8U&;U>^g{!kp%7cFGOhnP<+Y;e*wSYyz5DTWz& z;AMaKkb{?uG%&+N6Tym_DsWP(8&=Bh@=diBSj=HuqW0WXjhXUs9_UdrtCm-U$C1+L zZ>4t`{QTj8U+a;R!eO~yG!zb#O0p5UQSg3%xWc1g1;jZ=K>>82SS55|jTDE3-VOJM zVNk+KD&=dqKN@=Ao1A|n9sJKIl`6T;k<#BbOOe==oV2p!Ll_Y~ozfe|NW_f(L;i9P zG%W{|M{dP#-+HwnO|h}AO+EuzxDh#eVoK1bP>qk$ZKe&^cs+WKYX;n9)jM{)mz z%#D*#qcq7%m&5cPen0a1CpsT(kt(jjIVkK;(^DI#6GH;e&MM4KWNPMD`I=yCt{^4J z7v%|&E>N_}#u_O0m7Q;dgk6(9W*J?RK0;dL4k+o<8%251hFx!GT>o2!oO7iNOAO0M)q(j+EaY3;Y?Yz ztf8q^ag>Q7-LezSNOpFo@>+y1%@J8oB78nq!x17At39fG7&jetfC}@Y7_U%WZMEE? z@c4wsYi$2lj`*jC_Kv8^@ksf>12_1USI&ZkyH zoO3A&Vc%+R$i)_6jPIzi8&jOQsh=1Gb669VTA3c5Cp;eEIKtWnH!G ziVv15dMcp^X_8$fu+L(Czu@LhO%oAfyBZZEdaet-ysWTfq`gFuWIjbK-*uBGG7`3n}^S)3C|S{S_-Q?=Ayn1&Gua{VA~ zH06;nWg?*IL&_>g7l;SIooVX^ub~Nk^xMe;J#BswNvoIG(D4sgqQ_@(u(# zPrhTKccq6Uu50+EG3iQI!j&ogBljR+wa-lz%6{ckTOCB3FR1aF^f5IyR+Kj`udS{Q z?~jcYb3-f`IM=z5w!noZMtTo^I?5j~(TTUlPqCl5x8C5?-2;$vF z)gRryoZk2)>DZCKARSO=(D>8Hl4)ct1X1wM#k)6@qY|}^^b&=|B@Qwol+%F=f?NhG zDnAUjjjKligB~rOKbKmP_j~zhc2mPBCEViqM9pYxhHW9@^*1u0FdkQlbm%`cR>&WM z96f39g}iP@@_!vX|DAN%SRtF4iG>OE7gmW{-~BkX6QXCBPsbe#R$>hT0Di%2|L@o5t6c`aEgzUE zOo#}*4w=mWcNmYosj{r@n&;i7UAC9S?H*)T@( z)ECT9Nh_J}MiNIAMh%!hnh=uk<=HK1Rc46hhsN;Q@Z!b!*+e^(no3$1&&Mlb<`>Tw zLkXjCq@-2xz$6tc&hn9)=O`>HX{DFEG!s7y7~~Gf{R)4Tv{Ka(azOA_t%#~ZPFEZv zWq_^?e|dgtb4W9d*(wM zd_Mkf)7R1SRnnST39sD<+8|spIxN$>(L_+08u>d!55FRv=rKrLQwuAjN_eCTptqn;(e#_>e{@*Jz!CZtmM=pjAU?O1kU@lvN~TC( zz1oPj<$fiHpi~EfPG%IDuIIKAD<(f;IC96#2f`zrL4Q%cN z4%QJ{QFNimXj6Uvz4-~X_oe$^ZtLjz3H2v3KT3F{OS!GNWKDHa2SOww3Oa&s^!#CT zN6lZZvVVW+{4Jh8vfK&V$ls1^UgT#-zy9T^_Q?&YcJc>|w$};XRC^^pu!n_BjmR;^ zUIpdRDB&FGuv0bBaT-_zYbgI26%*A=XNUFI{?00j(br%WdhOpj~TGsZ38uK@(?DO%Oht!_y1a zCqJT_iQWgL+gQIUsUMe~&2d|YB=NM$V#9UX`6~h{d2mktCgl!hKRS)sai>m3cHBX3 z5SN$4o46}d5ckJ(+-3UJ9+a;zW@?N{OD^Sw(uf<9fH&K4P1!euB)n)nS;^bW!^ubv zUXY81ULnlb@Ta%2=Z9~rixn;wU6q0&bEf*~@~UhR&(_P5v&x^Yg6b!Rx$4xydrBMU zC}Xkcw=dCImQcoGmml9I(I0#2@79l`EY+q7K@~1L)@o8?JueIw4Jb9MT-iG0%fBi7 z3S*`o7lONe7Q>uUuOgrcnzq2Egqdk7vk>FsaT#IZT^4Ak3RgI$z?Y~gwo2=lBXSwL zH@15H`?=>Ox-Oa7x24*>_yAVAU5h)UK>Ija?iL@zw^RHvzIpM{&p*-{&r7&tFGiA% zb{uUoo|ACJ9s*7$u5n&zuW@*sDw|Vt=%edySpv8IUCR z&m_m7RP>bezA0w~W>{od)4VfjSm#W`mnrSx&K+!$M~~;WR6p*4rH3kiuA1%bVtC$> z>W5zzJyiLPA4t6u+1fKwf^7<%1oz=4Ztn_XLUXWL{{UQ;5=_X}GR@yi)3BOqx1~Mo zdrq2ELA84@_0^Q(k!$aKo?wxiq)0Tm=M9S4HEs7ZI#F)%>1h~mQ-C=GDIKR(K-PI& zT)%&hYU_%J)_V7gBL{6w{M4-2Z|4(9xs2@~D*av#^4AIV#x?b>zlz@Fmj zf~DLqi=KAJIr8=C);UIjpU0)V*7G{k_A5A^d`P;jX*{!U%4YUQlf@9O4-&!{FH3k+ zy1X)a{vdIeMk5i!cn?eEf%P1Nzg)MQKjy|wH|onp>3DIr=2do;@Bdsn__@Rf*1U@g z&QwgN7uydq1P4sP>9-otUt7k8zL`4Qsy^HDE`oWSv(6uWlXm1HMi%ny>4 zVFzxZ=;fHu7n{WATngVTZstWxa`l9m=^k7voj5SvgKJ(fgv_ELx=U1E#K+E_S@O&h z{6CWs4ltxNt6mwpeiUWi{&dgXiz2QON^Vit= zHMUm+LN<3|7};<`b9~WpssE>Vg}<5?%{7VD_oxNadO(zQ)B7{kH%vueov)r1O!gbs zS^qN3gqvP*C3p=R3~j+-!{Lc*e=F?`UN!tKdBtI=J2+&xC)pVsG^i)G1+N&)6Vtp2 zdxMt@znj<{{M;ZUFE#9#&)R=4nG+A&%t`YEu7@C9$OEJVlbF$Fdv#a$YgaSW+6C#2h<^g^6P7W>YrHd0OIj z$e7nDaX+O8_oKLPNX?sWSk`gficX0)S(`if-s@Q!Yt0n6EtCZWIE`t886x*61>1~l z_G!My${9CEI;#kXxqqX0BX8cgOb*o^%d~MT zDdEjdzV|P0MQ3b7xY1kMfM0~*S^8MdEpH-~*i>=rkQGI@$L8Ur+&_?7bWh5gzC_;<uJTF~021=gt(x8IM@sa^Nm!Udw-s8?1P2l%`CT zb+uHwm-WpPjsK9^b6M|91{64ZxAe}sghi#viAC>9hi>B6-^`3BrJigSlfm%k{;PCq zJUg^M!T64pGoSUQQRJqd8s7%OJi0``l;w|sA$eyhRZYrTw$lIe!9cxbkQZZ)+pb@VB9Yq+N;NR z&uo@^i8yS)VL9671nyKC_fQvZX3xG;{KVadUQ7<2Og{NZAlU5)9u1s48pwT{@*AI) ztWQe>I@TnCzWxo|rkeF=o?E^%`7oyOh6u=9~rTF<2WG z%+r7c?=id{?<>5K@M(9qTYvB@?mg4-De<^RZ~yLPoJbWLzcq}#_Ii56KG{yFUXIvn1bmGlr5CG zdnBhJ-eyRcF-=^oo34uW8HB>--~%Sq^CZS$0PFia`Uw0xjAtKR!xGiF-&08B zM9O^HeRTUg!FXEYCQwCMYi8nM$MMjGrQdr?ADf&X#~qJt`&N7w8z|GyiEYt6d?NUG z@bMS*@fll_j_7id7!q;a;*VN%ah#y>dV)(??T_{!h>PPk8e8aZ<~=mp z`>w<;$+Sx5Z(rwM*~_h$cwIc>gAf4r6AZ}xk@V+dxK`D8LE=6hLKJAEqg66^&LsQFlf`?lP;LwS78KXIeg zHruw8c>*f_1Hrv;9Im<&a?VLq|7i!V*eW`1l@|%t_`gXq2G?uKG}CXo)MB`A_Uz8s zyrj&S2eR`GElD#rZ20l`wezKoEgL54woEM3Jg{|Z(o%j|5=Ur$uQqpxmWpT(e3RJ= zf%8ow-ibMb*(<*-+S&EY-WJ%6I}*Fy-#X^L{*+rZxu@COsZMuVv3t75ZT7j-dG|Lt zu=0$h;i9MO!St&8KbDLiN;cy(z8@?Gck1^Ye6WLer%Zn}$1+vqAWMSV@0M=pX2E@e zJ=kqzM+3p&`6(GD_ct_uLhreEDGT?G^yXgY39djbB$?b(4$Z<{Z1&*!UR)QPc*;H5 z>Auc$@SZiy=bn@oQ)Z}1~ReEPQ*D5Zh@?5pLh%Hgvj^eR(X@z$?_iUgMO~ zA6(8%wEhAcP^;!GY5gf0K|dJOfd$NNoN`s(96%AiK^22bz;|7f_5LBOZPV0;>?V>M zu;rL49zse)vICpjhpm9_l3p9Pf{T}-ioJ?@v~oRXs2<0>tK5rJQ9e%7$>J=bl*wkxO{rzJt741J1|J4zTXi@xfjQxbQIs>Y>i zs+8Bb9C{X(qNpNnbk-GY<=SIdS1J+q9d*vg?c$7W`~&!v_;a^ehb7}Mkju*Nr-@X7)%lOPZ+O{JTMg`~(BjAO3iz;CACl)P<% zFx%ovKDzT{r@rk8*0C|TV3&$0+Je}4A;<1?;NDl9L$S9xww+#aP7>6&dn_dZZ*>45 zlxgr)TpgT}ZMQdVnDuuODezwL|9-viP`$;L%7AwX)mxkz#P`ye(e+BwRmtDUf@aJ3y&+)9_lcZgj&Gz|id{Mf zbQ+`aq=uEQlGdK3XrHKqxa)IsnoovJMvgb4KACK>!}Dd{$>e6(zCm(~%Z9QzR4BgK3ba^~(N}}B6<3{@}kUbebfJZ445;{MTjAcV66XTW=T*f5?qO4`vWD}BbceAl* z2#f<|fEt9c(zan^ft-IK6e zkGW$`xnsNC8eHecx4$nLv#8NIRA2w;!FL~}>1n&s|Bw~GE%mF7_^HXPB^keL%~H;R z{TEAW4UUuH*O)#uXAMdpCg6Os%*Tl=jB3>J;@YrM+raouN)Cg(w7`$aqBR*(G@b zAPZ)Fma)wGNbFEokF+OuD6o^jdV2fXSE;I&H6d-q8th&OA6{cWO6f<|bb&|##nuEA z6kD_6mlV!h1N9Yt^Vf7g#VFqo@wF>a(U3fyh``3g=`FGNJ&-tk@N@ijXX=8%COi}` z_v1S~6JK-c@nw#STf@CKh+#SIKD{F64M<6mi^wr4^D$9DWq!1nmrrqk8o1SW%pH5m zt+lz;N8E8>FM5tj#=b#}Z$DMkzjpB5%&(c9?^8D-vvY7zo*nm>%noF@ubLeQb)#nI zj}(rcok^kDnG~9xNthkuZzWrRY5q;}1sK+gSzl(Xv3C7z@Zi1Dp1%zS56Q#7{gG~} zYvUS4A@$H22UuMNZW{hMYYvuBc*~mLRtj%jv$lxBd29Tk>A|i-`Dl6$JG$#B)0V{D zTdDG`(bJTbIQ=u4CXYNjrg|RF#q}}xHqBs|pns)tJ?uWd;`Cb0uW+%rd?DvyyMZ0H zPiC!l#@78t(aq>{UPiyRi>wK^#B;NC_ZA1b@6z4nz96l*AT3L}p*hJ6ZNPs@rQNuk zz5NK$4=v|6=|v{SYSWFMNTR4q=QKeHLq=+oSEN!Cr{!#c)>u`%z}o`rEEZkQ-@v-a zGy_=xPwBZ~4B;)W#j5{FSzbk!_7hU>McPPj57Ux3eGj;_f6_+L^E6mAMQ59C)I1kO zf>=8jm_-;ihekrKAVND&?HTh`arCsapg3P~}7 ztmgvhu^eKt#F;q2nQ*-_1YHt%1+WN!Lnc_DFi!&Yqpl2xCTb7K%Fs8{-K%G;xJ8x6 zRo*j&6x`Up;fisu!x}@x}yz9E?S*mOF0D z6i!G@%Xv~ddP>VJbHzi0n^P$XNxh{^ z^O$73aD~R@A~ksM=U4iRuMp~F`aNzn;Y~)&(jxrkW#qf@WBlMsR_mM<7`lh3=h_u! zoPc%zmN}56Ez_^im$rKUimjxa$Z8EKXIooeMsQavw4wNYx^?YlN^Z#r z(W?yWB?`}}!AJL)KMqYzqz0s<|<^k$j72?}{Dt|zKys-tz2Pr#UC;##@q zX@E2v=yu0{la6*D=9bkZ8=sKc@08X*D;al4nmeT!s9mt11*Dus*rLMIFUnhUA?752 zj~5?5KBfTF_M|Gp6wKo%c~Xp@OFg$^R#1uYqJ&F_O)@RP%J8GkbCM<>iNaJ|Z!RSD zbV`#v$FabA7D(&QNz%_6h8g%q8NW3C(3+jCyWSb-UZA^<8@yVil^CzPOP6nqm8R?F zLsghdutFrwIUyyO1l&X_&RSPJ!Su+-l6x9qz{a!?Ba*fP++{TH5#q>tK9hO}B<6Yw z`XJm#a-ahDUtDjrpIjvZ_ja2g3A^< zu+6|Y0$y1D#vP!F7|RNu7`{!+jj9WF8f3Fxk=*Y|_wuMJlZ(_O%LJ(Dq+HYA=sR4~ z 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
3}QQtMr_xLwvj;1~91hyd-V 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 Yn5*zQ1*t&xuOP&ZTy&xywW1CR<9od5s; literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user2.1024.new.2.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/512+512/user2.1024.new.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..361e69dbd8a14506560462186def90eb5c7aadf3 GIT binary patch literal 427060 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�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

M<oMC0heqqOs3&OiJ+d#9~rfR4; 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

?Sj*^r9atke$9#wXqR^PjaqAL$h* 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at/README.md b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/README.md new file mode 100644 index 0000000000..0fc6ab9096 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/bin/at/README.md @@ -0,0 +1,81 @@ +# BOOT MODE +## download +### Flash size 8Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0xfc000 (optional) + blank.bin 0x7e000 & 0xfe000 + +### Flash size 16Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0x1fc000 (optional) + blank.bin 0x7e000 & 0x1fe000 + +### Flash size 16Mbit-C1: 1024KB+1024KB + boot_v1.2+.bin 0x00000 + user1.2048.new.5.bin 0x01000 + esp_init_data_default.bin 0x1fc000 (optional) + blank.bin 0xfe000 & 0x1fe000 + +### Flash size 32Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0x3fc000 (optional) + blank.bin 0x7e000 & 0x3fe000 + +### Flash size 32Mbit-C1: 1024KB+1024KB + boot_v1.2+.bin 0x00000 + user1.2048.new.5.bin 0x01000 + esp_init_data_default.bin 0x3fc000 (optional) + blank.bin 0xfe000 & 0x3fe000 + +# NON-BOOT MODE +## download + eagle.flash.bin 0x00000 + eagle.irom0text.bin 0x10000 + blank.bin + Flash size 8Mbit: 0x7e000 & 0xfe000 + Flash size 16Mbit: 0x7e000 & 0x1fe000 + Flash size 16Mbit-C1: 0xfe000 & 0x1fe000 + Flash size 32Mbit: 0x7e000 & 0x3fe000 + Flash size 32Mbit-C1: 0xfe000 & 0x3fe000 + esp_init_data_default.bin (optional) + Flash size 8Mbit: 0xfc000 + Flash size 16Mbit: 0x1fc000 + Flash size 16Mbit-C1: 0x1fc000 + Flash size 32Mbit: 0x3fc000 + Flash size 32Mbit-C1: 0x3fc000 + +## compile + modify eagle.app.v6.ld, as + irom0_0_seg : org = 0x40210000, len = 0x6C000 + + +> NOTICE: UPDATE is not supported in non-boot mode; 4Mbit Flash is not supported in non-boot mode; + +# Update steps +1.Make sure TE(terminal equipment) is in sta or sta+ap mode + + AT+CWMODE=3 + OK + +2.Make sure TE got ip address + + AT+CWJAP="ssid","12345678" + OK + + AT+CIFSR + 192.168.1.134 + +3.Let's update + + AT+CIUPDATE + +CIPUPDATE:1 found server + +CIPUPDATE:2 connect server + +CIPUPDATE:3 got edition + +CIPUPDATE:4 start start + + OK + +> NOTICE: If there are mistakes in the updating, then break update and print ERROR. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/1024+1024/user1.2048.new.5.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/1024+1024/user1.2048.new.5.bin new file mode 100644 index 0000000000000000000000000000000000000000..67c088bda03b7ef39496d78d5d84501f0903ab1a GIT binary patch literal 428980 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%0A%RoUs8#w*7TlX7bU}@o{$hy(nk6b3&hKCn< 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%0A%Uxd$g!ypFV_|pr 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≪HM+1%yBN4tL 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

ZM?m+iEZa%w$`~P9D0Lrev!Li? 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

    `UZ^;(2W^$ByIz2Q2p*CBk{o-p^# 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≪(w0b? zq7s8AyFmYlr3TC=lI41$EEBUCanA$z?ZOZ9HRL07(6*MS$8X`DKJl{RO7ZsexoqM^ zCHxI?#SD^XMkt}Q8-!b)NGvr-GAO&Tm;Ue^`&|hh`be)&f2yosg}{N+VeFdjXIU?E z(=Arf-50#<=zafs(ytI0fA%nbxYJ9V$X4|Wib{*)=smo~nZ+K3Nq@GPjHDxA*_H|A zTlnL?A~2OzeyoY}*!*-XJ$Ma&ufWHF;(tNB|4g4{oA>8^dJk15K=;0;yG-2x5z)US zz?OJPcndOzUhaBLnfX1?#q^wLJw)THKlN$8|5M)+pO#gA3O#DU`jX0m_(#~K3G<{` z&U85{Yk|ugkfxv}JU21k?i?GRJmXlJydYlU8EM8i{eqIQP_P&lMBGKoaYVel^kd3w zz;ZgG`?fz9!cbg6$Du-mjs@(1z(`HwRJv}Vh*kpuJa{6C%~^rGyu@Ut zd5$?-%W!VDdxK0; z8GZs482N&T8)9;0i&E19(~Jvsj9AZ%Yh{Ek<^~v>Q&a2%r1OA~!@$rSv9jxyK9#d& zZuKXXjZ>GTtm5^yq6|x}`svhG>myy(C+n?`*I8F~!k2$1HGo4n2KAGtwtO!6iVA#l zSzlqf@7@yMoPA{VbyJSJ4%HsLP|TvgQ5FW_(@WqQLG%xRtEr?$X?^j@b}*ee#v;v5>QGd6AK99En+kDry2Zo8Z-iF13!1;-?7MyvQ!skR~{ z-bXh|bswQ~)l6xGAzHc6O)SaAHFh9OEi{9^T z{stUkr-I9v>CU6Y$t%k7XeNCWgMj`q%+ZSE>YDlSQnp$&eb~`J^6q-Pa##N=ZSyV5 zq}+L}xeJ>04>xyyC!~G{^Iti)(3v~8EBB{t?tR@3*kKD6kCa=~nmeB|!$|PiK0pHK z9*ET_{_8FDK$5he6c*OscWhwRgFejj7<@D}M*Eud{0<#e;zGMg_><%pZ(>rq@^QV0 zjG-IG6=4+#5v%?voV!GK4=Z}0{cLH0$MW*8rItKI_ZjmPmPhXsE{CbMZ zLk#p9pKurH!MAGn+RqH5W%TULVD5-1m+U#*s*wiW*D;Y)m_C@8&^rmvJBJxa-sXoY z{N_4#Mctk8FkY{`(?s1M?=)9^n2GHWNzKpGHHsso+2F~cB+Q_VuQDDnQXNd2V?cff zJudKRN_?;~=M27CP_w0*d8f1X06#zlYmg8;(8?~mhxE`Fq-A#(vU*h`5crUsQIQhQlqSrUYVX9YyPRMN~xT;Y{i!wPi5#mpznNlSz}ZY5Z*upS#Z3mpjz)62Th{DZ;TERa;cyt zPZB?cE$&t_38|oCrKU)w{2KPZhL@r0VL~?6KqT9(-q$hJrg8Ltm%kqW&-T*)?{;ic z2Q!9Ant ze>(J;x0J&(?>hsMkfRcHEmT_vvttGln^b#&Y^1PZw?J?rUa8*{(y+D(2a6?!IherO zOuK?IjyM=n0SARNfq~CNs-twqDDX=U0@!0w48Xii?4O)?umlfQkjE)loaR6Xk);U- zA98A$gX3k%v~_BUmMPE@*!03CnSu3xo@1hSw55KlT*)%!EU8$B{1`%IE&o)EhEIS| zFin@pB((Hp64v*af0h2@atfC)_-7~F6_`vvme4|93Sy6{tTRF0Y4xpPeUFEH6yt8Ds99-6tGK31tW*=rJx+~F zc?nz;pP-6kjQmoMoBEAhWqnst4+%-VS`*R-{X)N~M4MCvB7g*N&O;Zx59l}5X|Vl^ z6P#jgRS8Vh_{2QzMxL!&SdNpQq!kl4ZZ&N!uWF_>UUj|%S?CI_E2*^)HC=&Hb>?LS zI0JAX&HHnxo^>qz8MLq4Az1X|3(xT|sgmYO;}+_X;av(a;4m#_-XsVc2j9yrH@TPK z2O6wS9*q=O#QNBDGxw;mi9KG4jMcEnNwE+%*vC?_M=v%yRN31Z=pa3Gy#a~C{cDX@ z;wXIw{PLM-S@@k8n#9dz_V0*^geb|QM^51*F-g5wpo^$5uI*MBkb?jVy(!u+9$#>hwNN>zqaFd_P*|52|(YY25Z9b^1fmI=M&s>jVi5`EZ!Rmisib z%=3sLzrD=r>Ci~E)!_$duS=keAvCoU_kB!A)U}E+R7nFO>whbzP)3$I7vZ+X6xJcN zymRbL;kuZ@UOnw<_~n?w0=*sfC){pQSRX^L{2!3Qgcu&0vhZgyh2>CRBIW$fn8H?U z11^tudrYBIHD?TOB84?z{_x%(Nnx)>{Wd@f3)Cy`esZRsB9J%XphXiW38_y&$a;hJ z7oX5wfvYExN_yknMUoOOU|WB{sB5A)j$j`+iQhH+5_e!vz%LiS)%b13Zx?=*b#7Ic z@N}!MD&%{n%l9m1FxHm)LjgGv@6fA;i@GtGUJLZ zCW-ktF`kM>p6GHmRW3Dc-W{37(mMsa%{IyC8NYoKupS@897ny$pzXxtBpSo99zcfc_z2 z=|2@LYR_h+d4a&#E4svWRCr>7=hSLB^Fap(JCWbYFJXR=F?54s#oxAy>o#?M{guG# z{;C`evSMr!^EK_`Q$O?(IoE!`2M>I7qwzEA(0E-fCd&kaaz_T}!DjrVfVLn&_!wU2 zIdvVYlsfQcYnKw|gpu;w#r}8UJh7|5PFyKryRp!T#EL~^o;gYrpm9vGm35VZ{MkNPWF%>B zcH&JEsojfG#O25^4(6-G(c|sLwNRW&0ix0o>>~{KI$CzH&hhu_mIV2w>G*P+TH6st zS~zNJYj%oUfJTwSv=Yyq`yg*mD9TR3YwKwRXzs1XK@qkX{L=(pxdU2FrUKV){2X#v zb;ukCKaVC>th+9c@6xkX4;766Le>aLKR06Z9LRuMmbwrAK&$SQLg^)w65;ZJI?DN>lT(@B!$w*Li)P+8T{Lm$%4P( z8qA6;j`bZ=V9ui{C|&5xg6d&0dF2f}!%KK(C$e@PnWJ`xcsus{62fqwp7}ud=C|s^ zvE{tB{I0$Y?<#Bde*nip7~+&KxlXeg&!o^BV#3^nxA+A9_WIlh5VrFNPYU^MrEo$o zat*V-u}K@x7ifrdNaqY+^NuybT_wCyDXhe`Q^ClT@i67l*UC3<8R=COSMV((!CFu^#DNdCwsy}-=o{pX-5 z!@{1;Llqr9i-R@#cNnHhR6|Z#EXu`Cp2jfwb#I~$s)#${Ipr(zo@I-;2E+BDha35V z8z)3ER+s2_x~~`bSjon6lVHSirj?IhtHs=PiJqNHmYDrEW%XfU;>ISnbBf?K7(oO= zqP8u++t;sw>wFOED2meT1n~>yrY!EF?kupj_FKhC7;=TqNPG#66}d>SfgWxb7*R49ng_ z*Yr@6M@*oeL!88_u|}Km+l`;Tm7TV)54+=uPNxzRR3H2r28e48-%O`2d-}$ca zVq9Am%}c(7ew!o0x-YPJ!@v4?OXbpq8F%< z6}(ZX8)VG@2|1^G zM{yif{6`N+0aJ6PAphwrBG9MOGHs*)2>9&qKNQE`6o2F33unp5=nI_s!h37?DvrM@ z{=ufSuSf#ie?}42JF2v8IE?sO zzPuVmqDZb%R16Hjcydv_?H_;}$p!Vce*h+t9`&|=0IcK;y^S8k4T`|(+BTEORZ3B} z_K5fIwa7UVIZ8b*vxzUI4_jI3LV3dUs;Rsb)T-vlCRL79X~IA7T@|AD(8nx&48}lx z%=BPBF|ST=yYRdA=LzmW0N1-FxO4wB!94*#-|nkWH$gOL^~JD0POm$)rm)j2)iNh` z;&{0LCL{l(&23_NqvPeP#I@I|NoqAgH&M%w#(K3QnIvpHAVut|DETmb+tH<@e8?wA zxhv#c+q*Whf)=*sUYBa8!uI54AK6I@$c=lgDM>i5ZBdA{x3D}ee6o)Sd#$#lP^?p! z8=1i^R!GWTStyDm!n7^AoUJ19Q>0i#$593Lz)#Q{_0dVIgZxH)m^J9nzD-L@4>cEc>-zt+N&Vv4JFes!;|OP!aU)Q$uD zfafZlESSq4koK;_PUigdtB$*`^G0d>$gU3*)I3anxt`>!!;yWxb>T>93T+Qc-z2#z z`sM4b#iQ6MkL_aGnSv>gwU3aeJeE1EeS$RQG5O_&b|?N44}G)s!N;N)CKCrydXS7C zyly4}z1H7dRh%P`v1&Q(Cb;E+Zlc;2GDYo4$`V`Et>I&|n;DtIL=(E%4%4(rYD@X6 z?VA5MqxQsH&DK`kD=nH%btkJ^>AV-&s}`yw=~VYS?2G-@Ezp!Eb?HuAxuTCxDu&_| zCz-)AGM3I%*lpkpSPGSq2;FFs?efdlisBtTS6aP$h>lhdXD#P!NR#9ceL*~>U>Hta zA%Bm4ZI73?GvqpbG|KGGRjBz|&**MhGdA+=&Z zY9^mhf8D_a`Zm^NbYE|}qGu#VNtSS2FS(VyC9$k9otN=4v=KauXlzi2rhnG|<*TvE z9XtZPnDF;}m3^4?}O86NacUf^f^=Gt*^tb3B zd0lN0m@$wH(@DxdP<z;Z6-BZH{E^~quK@B;(bZw91&=(6BF(Rr_CqytL4P+6f&3AKq{^{l0y);rG;Ir zfd9W>8EAnRY{ia*5YI|89ti((zYmtgB>zBjaTetf2N{f*3UA9+tE>pb4YPj=-L@_q`i> zzVmFqVLqRdd^22CLY^4N79|Zrc|&T@{aw)I2^KwE;L$ogI@!b7G<;S;gDLzie{t6c za5oL9HZ5W4TyJd>y58&5!7z`O&WHgGzfkJByGF*E?#O7(2c3o zq{CE>_&H2vWG26~E|OXwxphC;VcwFzUNqof#rrS33gZx7oBxqg(oj4D3a%PI4YHlecIY)mPq(CLfJ6q_=yl zX1^UCrw0>Ovy)O_o&_!4?YuK$!b$P76bdzh&9=Y0!0mkkt;vy!#(InRUGM=8T5{U7>Rx71aOqgR2qOv{@+VNKO|}!s&N`cTVf+(!No=daG78>* z;}AGT2fy|#wL`#Py0DjY_5037ZPgE!^DryqUy3@<3T!q1lHC{^A?`*r4X5BQMSTP& zM`$^@Jz82=e~l6t9*pQqQFSXl&*fhd#s^6^m2&%69sd$mooZdm5*z*0dkHiVkoZQC zd`4e{2OP4y1$j1Acw*oLieV}?ZKgaJ)C{aoRelupV3vSOduPId%>0TvxgM7loEZxK>v8x$- zFmSL6Pd`8F#JrY}&&>Kvtds+VQXY=;G#Odsq1~u~wdJ@@SX#2r&mvO3#+eU!Hc~dDrl4byb4+6eTTrF@o%tuhCKVpzdr-z9XS3cJC6Xap!e9}V#|q+AzMsnca@o1m#+b)2lzMvq}uthj)apGqC$W&~Ns z(n7?~%ezpi(^O;;2De#)yIAm?R=A^Y>B**6=AHW3sOgZpJwjBxsx;$V=1d)f09_bO z)@Kg+5?~|`gH__VtPrjpEgkJ~sO*3JIx>2ZVY1NQJp4A}SA^dZ{8r(2 z5WjW!RpX}@7$!jfx*6sT{B6V!b9=y7BqBGQRStU?$61BAqiE%Aj;|FV_yiE0p_a@@ z%@9&kF9?S=I{t-~Om0<6pM=-1J6Ay7U*YYID0R@%6wdLvk~g1XQ3%u0n`o&`=QySm zFB6K3F9?Te=|ozZ8{_y`S+QEcFbMC^Qh}CM1}YpaN=21WQE@?Nq{U-saZN4bh$z)t zh3e`H!Vy|Lf)>{{DzI$|Aft8Qf^d`;52M9<-c}r8W%og0_wEbAyR_Iqi`lvgm^m@L zz%UntAT8F=V&|VK27CA;$J>E3Ay#^+8;nRg3Ae>Ty;V;s54EdRXMxwME3Bi6bZ5Zm zy-jxXMw-pkM8bn|Thj5aR&e3KJD8rGr)yZl&;B;gdn4 zb^_5F#_I~pHEIp<-l@7Xpv^esn5H`;(TgzZticq5gW>S0;lv@;apQGK@>OVv+vB2V zx1tG(Ea;4VyZu-pi;1IaG{vGbUQMf<&nmDd1q>jFY z9qS45qWb=m(CfkS!Fec!Z0!dS<+>RLd99*&jCwJ!Y%Y{`yMLr5uxsGJPoAY8I$?Eh zY^I0T7sxub5~IxLIwKRB;pOM21#5d0=7Ih;sUxm>xNy53$~(CmXWF1skE-9%#;uB8 zWg^T0`4zo>rsJz^?f)j@FmRw4XycFO5XO25{m3#!#a;S8aXn-X`RFs(lp(lN{b`4e z^$^;G$T1%&*H}8q{l}Cu*cWi|xpKTqo&P75=+U3|loAP1-vrpL^hc!mk-rJrYLB)R zOBgJ8$j90>O&U5RnY1|=k{RSSdZj0hskgI2qMc6-3j7T3jySzJBx@*h3>F#uvCPOa zamvtG^WeBll=Wg}0ruNiPs0DGYihtgO_Gv2G`lLJD+pYw#V++f=x@|5vyLjwZmJN@7*GM^(7DkQNp0{Go6| zD%|=1SGXlGt&wYIkqh)Q#~Ui#yT}0*?y{k9cd2lf{a@iqj#|LIpM0jmeL;o$GxD+u z*ESUHCKayje}x-KgBA%P2SO=W=}*&_2bZCW{{hy`Io>AQ?C`ZIOu*^9(>6u6-5max za?MF^Qe~UNe_Aw#TlWvxRc^S zvL#B(6IuRVcJ{q=ZVt-va%}^uq+90^^C?FYdt$m`k)RoUlzyd#HmN-XpL84f6)k9o zy(iRqwP8}O-sW27)7y8*gX%482kGq*Y^D#W1lrR0+YNf&C;kDl%a-2lkV!C@rD8i5|XGE~Z_?!O2+2P;JQdD$t$(OA13} zF-UZ`23bT17H(c#s|>;j>8hWiBm&k5{4&%wL8y;w^%+Ax94o=sN+X4SWvvZQJhQ1X z4$?i$!IFAnp}_?K>{W=mTZ6gRLLVxBPG+g{{Hirp2Q&v!0o^s+x*@&HrU`e)p_+DuysjdKRWo`{}l)F*3j0X-=oUYIJ|@cFDZ(%AMfGYRDgVnhWvqE zrDz9m{wwl4Ef|9Hk^k*`b-%XL@1OqB_a6}Fp|xb~zky&Lzl=IG>U5)g8Z|nXLbrxZ zXEv1#1GmVf#=)whKE9jR$9Iiew$;SiUXBDM+dV*bBw^ZvEK>f!@cVJDP@*#S41YCO zSP3LS`1k&TD{O@w58U96DTU7HRSj2I1B)JP{fXRNcn*^uxK?fE3Z2obKjJxz9NREVzM$w8cT@qMKfN23;tK*5DXeEWi?o09}<% z>2BzKU)RdgJzRGm@Z=v$@l>Y?KggZw1^E97KhA+-p+VeJ+;Ldo01F==Zq`7}{$Fws zLTP&!a#i(EVcdvn*AfQ*_*4UG9wGx$J`I#7>VkEal>&|aB(*jjW#>mwcD@8-AjavE z81%WYM2khnZw#;G3hSv?E+764cP)Xs=fWiTOeMVt|BgG}OCQZPhM(imENH`2gp|@| zq1<~PSJjIHX)YxW!2HQ^Jda~yYS=#}jty|^gBrSE?R>YRF-ifv{d2KDJ^+MMmHjzI z_k9{@ajpx3PojHc_-_8}5bC_HF>;7D>Fa(N+M*IXMgazkjtI`(os@^)kYbcBrkRO=7Z|j0>D3xx7uWbhil~2CiI5A+6Y>kWc>%a9nB&pU?s;JAq;C zet{8ify^K5a(^_y7y7)aZ*}L#T?7xDc0ZG5q8H2k^I6hGx7+ZP7Kjc8kP}A6<1G4E zUhbCydE}V-+}0v~qL6>m%A^34uAr=gAr%Mv2)cyx0(zvkiR}APH|hM0;_`=g_LA5B z{hi%W4X}Wd5m=PLd_7W_!dg96#0917(96^W$tpTkcE~k6-A4kn#D;Skl_A>3mNy7s zhY%_jY*Fasx>4)P!gJ%CI0K0uV{9T9Xq8)K3)nh7vHm!lGP&-jQ@I!Va7aOE{19z2 zrD^}!p3ch(84s77LQ z=KXDT*UU?blWA0;`Msn1K(=JzuB1O*>$w9-m~u;+wB_$zD_{0-$+BO;41?EKE_=9g z*{^h8t1c*@`;>y{L6G%0Yra;I^e{q3HEFNwQXdXH;^TEo^A{i{fXkRoV^>GY*X1KB zLB5VKt4}>&Gd3sksxPPGm2IEy%dfgRAe;~SNrQt$)DfJ^1p>w9pzIS{eG@{y@vKi` zB?d^t*=Prs)U3B_VA}jA?&Acqx;G?_M=oRJuVRs#9*0*_!wMJdd?=EBt|BR+@Y(B? zwaZxZaQ?$PD++mOWN~8wP&Vgp*kj7g33+o(r88pqwZ+9kN&fK7e2w+4(i>xJ`iiH7 z%KU__mnBgo-(CZ{k?FxHiilP^91-(b=`NgEWD=C)4E8g{b|a6_P^P4&D-&nv`=Q>r z{ptDei<$HI+K*J)n+|9E!FX3%y_0{h)U?c%<$psdl);O-G7*HWu#TFSF92OEWH~)= zVYc?_5eV(Ws-B605hKk8KjeF*yrXLo0hzCG3Zs+0=mSY~+HaNZ)3`U4<8@$*?8CE( zcQF^~0#mCxu6X0&J}jJkf}Yr(%4l;mirt=ssPhqxPl%}2hL#SE-r2-XG?{oD_ZTwT z&NrUu5BzLlB`GJVPTzn2a&-qfUDQ-!zeWF-a{JV(W*J%-oMEfZD9(Il-kznkk8E(- z?X3M~*>0<}r`6byb$H5>qLfl;7D79ZmZDI-ho5)mklGP1ZF;oU=(b+~fL_Vn>?n$Sr}(-IyU*vu5# zpe@@BXp7rwI*?EVv<(o7Mr|Sn(7IbH3c8>*H3iqYTMAZLtA?tmD{8HZy0W{WkXp2? zP*w#6g@OnQF4l?kPih1`n?x!XMF$#t>X4?1xQ9SYwx%#9cdAonJ+FcEE(We3IWKnG`RvvA}ECjOo? zt5rCe|4TLa9orD1iEt@Zh!w@FFgpC4Z1MbvoLx5zt0CtBYCCk3Mp)hHhx5a#R{z}? z-q2-Xh5$i-FIbV2H-%k`MHVqGM{9%&*n_P^zPFk4a<=UA9Avm2Y5o*27)z+(>CJy<{xeHS8=ZTf82tLgHe!0B75!V>wH)cfIR%+0uG8 zJ1JH?%>6Okt4|e)^^L_-~{(*D$ik=D+?WDsWFYr!rsb$ zJ@4Ja0-zl=vW6=C%in@(0=0>2t!2N6W;p&^ywkD@X>PX$_kw0w}15n2$eXW)ObvbD$i z@L9FIQ1pAtey%?Ho#jrB?8UyjDt%CCtwznEKpQ#{g)!Iwao1oI>_qr zeKI3^EBnxt>3wQb?ol2|y+!%K4ga!prHmzfE}R0_9^BTY`K|ojgZ5cJFVm%CKWK$) z4EahaJIPYluate1l)VoHk+Qcc1$FnL>?eEGvR_snwVu;|ZK*gXQM8BXp-HG79QQhV zGIB;_6i*CR{02*DgL{_mA3xm3qE0hr#I4nOUdhCbiL&6z%3FJC9b^zL+tt zBxBNVGA_>wUNxTVl>uNvZPhNU$mnV!qbh{{Q_TnUG+gIH3y3BCXJ|PYp4HKcu2VAn z$SBE=$?#68+_lRE;JFV$%UDVl0ckT}D9*%@bfFtLVgj-r~>G-hm z)PA~k_o~j_caS{sY9EewjiWMrIbFL~9iKfe+EKTsqpq`KQESJ|WLJq#UniO0(s2t; z&Q1}}lXyfuOUgs7hBzrzc{Z?%Z0tM&rQ$(bD|Uaowc(A#aT1WV!|0wX^T|E_*9 zQBjerr&|OY&y&c31J0R%d4%<1mjHJrGeG>M^m>v7)B!jjf_8zKG}6EbzaLp(oRx)x z3MIZEu?wiBuO#1rUy8FPqBkd|C`2Aw2?7u2^IBpteh5cg*|clx7wxAHIJWe1$VL&q z$4Kgq*5|YGc#Jq3$*)7=OF+9_ zq$GNw!1#O?vdARA4#DoD$f2k0$0l;Sju}=>t=-Mkc9yR4#8xIuNKvxq6c?a__9Sp)K~cLasoe+#-LZaY(}T2weC6%^erT`DQO;1o=T5)2%MU+W3~@jM zH&$?P5PRYa#Md0xe(KEO>TR>(1Z`Cw+G=I4FtK*`^I6XqfZ{7imW^WVd)dRE&&TiI zDTFX-U+pweS6U{`e%CV@{MPEsHpS&ZmBMrn2>i!84T<^-LwM-G@3= zaa22~-Cv;U4wds1akpj*m0=qPl`0OuPZFI0njwY$eDLlwa!2~&;8oF!}p~cgm4%O%K`>>950i3^WU*3nQR}hM8c_Gjmc->-wJp1&p2vDUNUC zVrNhB&R6K|N^V3E`!8}w<^*~hxx-XJ#uUya31$Pm1VeloyS}z3B&5^}mMS2n5?%>9 z>5i$`rD>>VafB|uVHb32qpZTe{h+WfTSK;ydUm&lF_mNH zb5bT?w&Ms0Bvt@dZ>=a`L68(Z!d@06B$ z76xWkP7T>_o!Dr9(9qjhpZ6GBZxG5&9o>L{oa>XCo}*`yyl^0^|A+mBH+HZ3Ml4Se z%Trs*Ekb!RQ$7Or*0)o&9%vhJ1`7ZbAWGN)#~c5tPhdyVr{LG2!6Qdi+eAcY00Qdb zlfa-u$$HUAp~D_tE!$7U?t#|{6I*8h6e0WW|J8*wgt zT9Y4gwD!@%KST-+m^=mS}FoATJJ` zrxkZ@d8E8{D%Nw|2%pZS3A^oiFHGh1FHE%VGVOZd&FtsK*8Z7H`>_fc>p@8KJ2Fdr zH@ikK7$KB^$8l3D>M(GJh?{~68+av*3*$+}*)G$O<58VJ1h~nf<`NI*5V$E4Ct}DJ zxf~4N7{muh@B$j>Yh;fyxR@UWkblCkx-iw|8wzq3? z$ENGo+n*d+mZGN<1Vci7Vo|dFl^IQ1>=@6Yxv#_Yx8SjlNrr=Qf#byf;6GWi%W+!M z-qhV{-_O1Mo6L#Hjo0U`(%060Gn1ZChxHcSPMBFlcL?_KgQ49<_=Gd&K5+oR9wk3A zpeqytyqp~VFM;pJeR&z++nvOzAl}^v^B)CY=t&QdiM54f+lUN}$S~oF6Ub1R^1m;M zPx=H64M2mMA(1A>fx?-9#-1!841k~0c2fPf$BxvOckFpUoi`sNnOf@EcJA%RKIf=| z740v+J(jbVXP6xs!X)yvoA}BBl-gd$r6hEHvn08+YN4*E&R&r--8QrC0v?f>IIZ%| za!B9=lCKfoZe=6ab`nBP_@}IO5GM+?1D5CQaR@U1Kvsbfb^D`IHv#26erljz@mlH2 z?Tx`4LxB;MJ1s+Px#}n)#!qYnQQsn8ZV^XLnbn=ZRAH)FQDsNyxle-t^v;R0>ncb{ zdvfd)J52j!ptVNv2+K`K zNAVYD(4U={gOxu2pU1-oPmqapaO*IXMt(m&c6FUls&QtJOfu&gXm|}1*iVPl4L*o~ zDZv^Un~sx(fHrCMX5hJ;oHlkdh;aR=TA;lV9`Oa?J?bH}Zl>QPWYD$h79I0jlt`GzcEo+K z4d}z~W&G8x{`)!=O*m91&ha*JyUCTRZRj+vJOT?0%L1dtW_+Z!Xp?2B!7{~wAgoRN zM9b59%Uybbzc;|=dAkxEt9rMb75J&rQ+LBz!`q||(1q1DiF}^KPo?i84<4ySI;1Yz zgj`o1(V=N{0e=W)nTTN7LeYT)Is_#dpz|w}tC-{v9}=<*)LROGr>v*BqNmAE-JcvK zM&Thx8T?P*Prpd=MQ)fB2eqC9E_i-Zw5jnavVDuqfRkfzaZ~I%MR4G~wR}{}($~u0 z*U5(kqK>at++>n=Tq)wDB^O;6US8^>2^Z{Lmv{h=zZ8$pBjZVbIr#3o8_hF?ZEr={HML0>x`pWshmEI+2KNB0n)yu>%JUcxCX z1`TM0^b7}o0CoZ0EUL8xD7c82HT}wt+`3bWQo1fY+;E!lGCIsfDT>zbuNqsI4MO@? z4b}ypjIuP1@??+L@(^~S%l)6p4>&3<%v#<3n##F|^{Wd^)6qxB+9sQOz`-q7%_7jB zFbiQ|z0kCg=)ilzdIP$=m#79~DTcNqL}5fUK@|w@gt5O=;}vywxE5lsl)d#VxpU2t zz1_sKOH#O4_Ii{%cAla)CU47R03b+$Qm8fSvn{pHkwid|uoZoPgJAz$R9H&0UJc+N z>Wgq?A8;8-EC;koIML7+C902DvBqmQ;0rD+$=*u6a_5r0or)J4xH=#nI>@Q-Y|y0y z(~FgYE-1B2jog${mP;?5vOX+oaK^2i|L-udQ#J5IL-GMJE^lA2K+>~5`Bc3KGM|jU z3E$LrFa(FC=%b}{Y?h{@Wgy9tK1=6uXiiA#RnIoPv^=38|g zJ_OGIknC&Z%tpa1wUE2>m?s-O_a|%O0;Inj*CW4<4P#>`e-Rt@s8R|6ZEYO5bA7G< z{|Xz%t}$RS1#H;81DVtJ4BW-O(EmC%EL@G)y+6Z-UGYnNx<$#5V7r!(yYqaygEstx zPtIRTf9+uU(hJh7*f0f^J7oJoWgrje@E|nmv`x=a(_`ydG;jwco}1hw-Qd`!jBEow z?j1jzr3=)r;eDFEjNB^Y?So_%r9Y0NRR$8rC3Gq#E=S*4dQ!ZcbUI7DQ}FC5X4+1E z4k31Ex`gj&+hDqJL(`?uV}2o>idn))=1BRDHml!@V=twLlUs53L})9s(-dl7x`5iD zWxn_=tx;0~l|w6qEQ;^#cT}h-pFwKR^9QTx*vSF>`KdVmJO+Gg7a0b^-EsUmVil_R z^Vs*l2y&$;DhX|6TCU*3v4g|$zT!&}TepFk$hSmui0&S2jE#uGD0~9++5AW&rGlw+Z zkWS3nq^wkYfji&~r3;&xEY#7`gqb=g_8O>Z8?I3Eo=mq8 z3Pe7K5CjDKivz^*IdnUrh@@!I>p8tiw3%vegl1ufD)_DZq)uWOxrgDiiQ-y0tf${< zLYg8@fT1T2jsQ1XN@&TVxEWjqH>#AAteZU(OrG)^7A#7bLrK2PIvwR)r?o6i4)`|D z(bX`Nvq@`t=i5sBN|1cfjGg9;@xvwS)6SQ*mRU*Mc%u%g3jF4(oatJNm^udoXAa|g zTJmjIX3h@iLh0G0&;ZW$GMHe>^`$z?L+nb#3rqHn#Pn^|uy>tosQ<5H@{dB+JZbZv z=_>L$c_AI7rJeKWCrJ$p7@>TgMK~>G&CmZ30lLcPU!-NCRa=gEsC!mCG%=AVr)3fXSNAlvlbRk;RO>Z5krn9bq)Tq?r*I&-v^C%+1T9eVd$ascd$2#do^%^K{s=Q%V#N}Hdd zi%DuBVspqpNSmLlj36-jeA+^G4x|d*hsCVAABi7|njuG>P)WKm_6t}`$;`Qb@?3A)cv$?iSaR}3gwXz_gjTzxL$q+!*W!Kj{! z0R{RS`b4}#05TauhuBgHi9A5FA-w`c<6IBwbu7e-!g>>H>sp|?!~bToe;k-FsgPJ*e2Ys|B1>%#nuuH8i^Szw7S`APc}$K05@HCfeK4K z7k-!Vb|qqFpBp>KcqL$G0oeSM@iyV;5G#qJSavCQ;aVW@FvURouXQ!xJ$&GWb9%jk z;tMZ!jPZt4UwEG*KV|I^{sQ@tbrNScyFTvshR8~ZtTSTo^?F;h13y0P^>zU;i&e*$ z_#P*(0L*S>PBr1|cWflw!kl8_U$ULO=aHhW9SpIe#31!LLq-+Xo#2y>p}21Vqqwzk zYQY8OWy(4j8#Qd#uva6YpSwDlu5nWcfORSO0B?XCbh*|F1JYf9D`m1N!G;rYO|1tG zae59Pt43LGFoYExcVl=L<84(K5bj{&tYG&Hu)=jGAj0Z0tdp=pA@_Z-j#cjVgS84v zz@A_2;93pc=?-MwH1;m!f(l$mU|Vo$+kL-EE}gGfu0f;YYj&86UtuhA2{@e^nY1#kRhtXZLw;Ei8l zKqY}0uOL*Cn|4B_iZ@1UOGL;Nyzvu+N`g0D4=M?L^Y!Rm;dw-uv}96<%>|Vyz!wO= z_Zlw$iEyYqRwPPgFZ{8_rW4-Q>%m)gdYrf6tMzSTDfS@-z99*3cd(lwH&~Vf68#+H z2Iw6<)nT(|)wUAm#@0b@G~}6g53Dp)Mkc|b1S*5q?6yIcv)hNVygtryR}BtPvXfjz zkj&VO^9-M%7b7FYpEDdf7jha%j6Fy^I|bVlDFW28E7Np+M)R%K^jy<&>+~6>J3Y}a zEf49f!NmwJX9Obu0<5R2kd#-T|0&ipc0;cU>FkbZ&_jV&e4Ai2oj)W2qlw;hx%@#3 z1F?ACo6p|07;h!1JEq%`&jLT=csc(-Obz3}_o z+D=s?H+XOj0+n;<#-kn$UBnP6N&S7?A?I`x@E4M2bM1J=w@)`Y9~%1Itrvdx^w96H zvgpnkzg{^{>_}gQw2;2sV+N1V)Nu)C2?Ux*o)GpS-~H-6uu0@=^nED56}K9UUc@0= z^c(LUL*9+y_n^kW94BV;u`dBN#8M=$0LQNI>rEai5W=s3zlX6*-f9G1z|tFc55fx0 z+eKiBk0ExK0!7Pv!G$~M%#q6MItz7#W&mmkw;gMGPj%aq^A3gUdQSzA>~yS0Cgv() zwkfpDVWc5*fxW%t&$Z~{>$$JOJEHDbN>Y_qkoF2gi3!?h|SYty)$FxT04ZV9)<0tH=gl>4L%MrL?r0Gwjl_`o zciF17{ipgse%mp50H+gorVYp1=gG0A{kelf_B26rppbtdCXF zACN6rb?i_ANIe8kpw&dlwv}lJC}7BH0>InJbcB!(9F4vx*H)6RKT3cDOWe3VO0Z_P z!R&kBoLDeNv#14KTFy2yz%cWp!ieo$RW5!zGs*AmdNyFYvUW32jp|zc0zGLK&ebp~ z4~!JF9Kq-yTFrtrrKpzS?93ed%m;<*QpD@b!tRM;$HduM`YicIPkXY`Jhv+Q^SE-A z| z=V;y{3cfT(uI-Jq**LI3J* zMNYfl+uyi|Y=IfusM_G(M6MsRg1D+rTt*K{Vjh z4UxE;7;;hxU%0LYV8`*4cAb!G>$8W)-bg@ap|FP?&c2agoulARe;tPz{tKhvFrfqh z=rW>JL6>e$S^b@*8bs0zDBT5Lwf@z>Q3lN^z*Yhnz_wt=gTLVy6Mhw837lSr^s43P z4}j`P5fl9`kr{9I_X5vw>jmsrUd@mm%BU>JHQzqN%m8bLU0gBU&~+9SBEZgLDymUi znjd@`r%FKK0kJoLv1I>rPQ_SaQ5jCB8$#cJRBRyU(Ciy(x&#$cc}I_$^tQpIu9|c1 z4#FfPbxnrjm;WNEQlbJS1+Y_1`N0`A<@&*tvCz4;e-PjFWQg$JO#t?U7k^~XVw?bM zsp8CE&vW}MhgGoRiM&F~WcbQnjZ>snH~lAt1p}A%{HIJ>s@V_IDe!T6Rn;>1e zx$)nX=iCPg#duV$K8jVGtNAeg=*jq_Kb&jpB#+?Tn|cVB)KmxkRjYp!GkpUP)B}pO+|) zI#cYNg!xS|CzJe7Kz;sbAIuPhj1;CO9Xgt0N$XfK-6ZKfWc^ zZuVr&$I7m_-|^>fkr>|C>5oWChJPH1b%FAE7$GJ82~XBlfvl^k9Gk18AH!y4R*Btg zd0Qj$Pe=zf(#~4fUwY&B8TnPW~5(|F?n9bv|w=Vlx!_4(G9JL0D%761%zHu zNUYIhVjod9Nf0^v3$heR3|>-1NyMyd#SF~pCk>ws}OC9lk1>#L}!uDZWE@_aSC z;N?uIzLhEb9CO>~=ji*Br#cq$Fq81$Jb2vJ1`jOPM!hWp0@uo?G5i?CHJ{2WCWRRE zP?vJC;$law18n& z1oRy#E4l`ws3`5+QQx=|4z|_v3W=cvMlq)$*s31(oNO^;3sm#n`9qU%uiQ{c)%G$R zy`pRwaT^m)3t$9l1^Shp1gXvcaDSB48`D*WnavQGpos9C+tP~8Ll|NpK!PVd?Dfp(o%JDxmK>r?v*xmWmv5up1#oj*@^UX}*)`rq64 z(9rgU4xzqr!=Nl!59c;>*%}=G9R3nL+AD!gfWcsV0S^c0vUudPEx$ll!qI{H{JK2c zr_?PH&0HV`-)21f^cV&X`c?H=`_MX{V(m0TfC*!;tY+LcAD89=L9bXVQN?1ci zCU|`4XxVafh+HxZ)e32#lA#e}UW!JeJqfj+S~>u}!RgaxL7OFHHogZ01pKW?jq86} z#wv|c#OJvI#C`=K=gR;K24#O}8LKFzh{KkHq=;@5!34KpOOI`%%Da8>HeIzNH}p+H zKxyj#Yrjb+Y2&i-YxncWH(Ou%UZMAY=!3tO{#TwiLJNR^Le=tM$N5jZYHuIo!T)#cQr|iv2jqIr6v>BIgG!`(gcMO zEhy)LioNQ7x}j1h@B)_-`wr&(tiTtD{N;#U+C!Xb2)qpeK0g7P0k=E?4;__zLjs?U zpgKMBsV;%PLgbwi-i#pH0{kA2&xv;noU`E@_{f4HM6n^MA`>^D0=?>ZsH&7ZdbZ3b zvM|KT*>)^~867(JJPsr@bob5bm<7v*uT=1uVxMyl*1DE@1KFW=&<%`%;b~}vDP}zu zsfbv^akWknE`3|q17?}xdJLcpRL~6K|B3B7ZZkpIzW~}mUB`18Hi~Mab|xHPz`W3` zMX1V`MSgYcUvjTx_v72m@~Ia4UVQnid`hq<)gsXQOFtOIc*N)?j?y4mgEy0J3?e+ws|*&BbjYrRTyr$RGZj{_b=G62mks2Ey? zDKxXNIAw4Pnq#>27zoWq*Hc6#1l7mO0KDLF7hLUTpej&YiwQu?bK$=d1PVF#4^1sC|B!(XbK1bvob2!)2L?tBfqR3Ciugy4Muy2PB|6ypm1%3*`=^({s zs20GXO*nX{htDO#moVA&*^{9yUnAFg8pkOb*8%RZFM>Wu`!84&p--#!R$vVr%aHbb ziEa>*uwQQF(R9%r>w)0&nvDWK0i1xBmjEf4gTt7$$TZPj!kIV?LNnR@ERMwLhuKR? z{ah-i!TvS&0Q6u6`*w&UUUlg~r*bFh?MHC;Akrt;zecWq22;T@6U5^$V5$!F;9P%H znWVDJRi`pZWtnT8+}l0Kv3j{zn1e%Q!kpL!`IJZCFM^;nfJq|1n9~Y-v9McCw#ABs z+&!>OQYA#GKZIE^7%@_0XZr*Viz+YxGR>t>8Y0r{GL+w^@PNGy65OYVAbDB|mm32z z_w&5MfBku0u5vZ63{>|IgL#pszm%6HkW7TN0ee!@g*3$$L!~&}&STVotTrW~pQOY< z9D~NgLv}q_X|y{~3htmK)^-E0I5>n@BKz;h3)z(oG~7QgRpa(-Iko z-2!?b=cJkN)m?ILr6LfwU<^~_pZdz$UOw zuI*BtnUS`3fgB>=KWzs~lZmuv2yO5a-VrcbD2ecny$7PHu!)77OGbMk2*6zv2hmOm z-vE9NvMyW&ekiPqg^+$2VO<#Apvzzf>sW}fG{8F6djY=|UBIuKF5p-20)C-U>5AX|^Ih9`v!7ruzTq7TBReDeC+ChHR4D!qU6Mm(Do8e#KSAYxvu0KH5(BChR z|3cJ_Q}_irMYngLzP|@=5*2>oE`Xj7Zp_9&ZXm*ivr)*7B3yTXS9*m*tH{_G7cO=> zh84&V>EMtD4`dNC6ql&Es5@jxl_=6!m5`jcM9r6b>xn>x-GJ&0%F}!qPNnvODmQd( ziagDLNwUJ9BJe_yqVVk(@IsZRDZj#tZWg=~jbm7%UD@^U@= z;R(D&sWoYfk)UH4+CnKIJV_}Ze0Tj`t`#A>gJ*1m0*f)2OsJhY!v6(yg9KI#Et8!H z4r>+u&y#yw3Hx1Mc;plKR1}3SR4?!&@az`(V7I{MiTqS_J^YAMkTF038~im22F5P< z1h7;xAcMUcdN*3&MVw8DIoe;O)d3Vz3Hi9wBuI5x%jr=!R}I+0Z(~ ztYk6+-vIGF6(W3#T{(nYph5@8O&cH=9R6j7sbvk)>YA?7ItH||Hw@4kyW#&ttIPRw zT3K_PRhMMAuL3`oEax1`dKJz< zR=aZ1U&+c=!xq7Rq`>Eke1XJ|^Wc@*Um+m)O$O>mR*)^EF=AG%l+aNx0}G6pJNwC=iflOMVDpW`QhNzrAL_4V zI`RkGiP-F8d{ngl6t(Cs)kiQa2ndFDOACEYj^dQey4A@`j7DUbs_}}R2O-#O%hiBv zdGxHwxgwLXI^G1_MPVFYjGrzR6CCF0#4-hj1;19u8bTNvVcSIc?H*9y5C z&QPVxDd%!{mVu>VDR7JDX0k(0i4h6y0HMPZ>6aKSqY|RTe_OEO?^ND$idqhh1H!>= zjcgW~1P`N=7#8{}O34q#WVw(1c}a3TV+b+BDw)J8HO4Wcr#2>6t)&qQ93hV@f>CeH z*>{C!>H28T#$h#xiU-Fu5g1eu6Kjv3SqdYo1AYU{?zz@InbjAKpXgv2-EIcaVG)AY zL~wnW+f2Gpq@SA{B7t~a!*$%WPKnv`Na3Eyw@ngNFX8+vX4Jhww@8}iJ>NF#Z%4q; zPKj=Qqp(F{5PX2!?{8O4fW?T`m8cVWO(|cL46n`}iONB!^vO!7bcxByD-w|eYXgVmN&kyhU_Bnl-C{ z8}HhD+#Bc@Ib+s;W~~3@%dA`QjD7kzwj&$O)I-qg^FU<$z2!|#}aMuG84uk2|xK}C`#bj)2)|1EJ4qi9cX)NG=t zD125N#^nQ!dW(XkKFs*x2A*C|IB33U0Hc8S-CJOp#Hi3Oxu{8HBv9se!@06v2D4^Qg|MCg+IQ&AfwO$e98BNM?5U4))`3Lju_S574M zyUKJz`Q!D#y4$FGb52#-!*wf&&$`Mb#HHON@@=@VgMUq?Q%J^knnch!&gx<^dw|6r z=@996mw}&7g@=kYlY-}mrN?tb6p6so&!~3<&!3aCoc@;l97M=d)bEg<=wsvKn4?!# z{oyKUAGt8C;#hb{+M($lJ44sT%S=~2;sVlwGU+uJ7B~atRsEda)oNN;TqvE0_}R2- zk@~0PUO=nk4E=|}GH+GylrnF=uuQ|x>*ya$cf*i$z6;Z_NH;~HHEP&?;K;7MhZsSa z0~>$Rg-1}TLwJZClRXDR8e_xwt$G&#IBooO^aK8h$(7qpcI!lka0r@;W3Fp~9ddjj z(^9`1ZZ~kLb6@;{ja>8ZNL6nH*1>Lg%P=Rt;=J?opEt^nPVN z=_G?OZE#HGPx^NOoddgz87JuUc=~kq4Hg6RWZ)WJXX%H!@|Oc>CK0drj0Efpeam1u zN)&)>4)#1j@~o6^j6pgk(}BS+$_DS07yy=jCcx8M8Wb5?NZ#eaz&vMi-I>Xl8Hf}r z);TKrFV~;25iS>Kt;M8lsI_gsx zYJc9YUlPL+rCh}$t}271#9UI!5ZN6wke2wO$=0Y2`46h8A%zFX-Fds8OMhk`HT9R$ zD-LlL`>I_RrgziRep0>`>9Yqdbv2~lZHv>MPXArK%YOwe`#QM?;p#ycW%_x#7YEaA ziQnx*y5}xTXZ(4(Nc`&*`tgA~q&t0KI_Br;>f>Lh({=GXB7p<$aN~52Lpt~?Vf+Tc zuW$7aBP^z~2@|q3bC^=A{oY&QxR&&aSU%|$Ju-^)Zr_lxjFQ14Q3@Va)|yD`3Cp1@`(i3DC82~->cYyq>^KDVZk## z9fGGxR6wF7N#l{2IXIT5pCuo@^Och0cbEUoUc%miRd{>y2}ic^`$FPm8~y+qU&%-r zo{>H-WAgamG%h1GlN@Sz0+JM%MrP_@>Q@WRZM||Z^|&W6vF1nI9P$J%!a18KU~fAs zQ>#^9<^vH!F59_z%2+9ZzUx01ANnvqB|Aw>pe|m3zyS>&dbROlV21kLWNBv~P^SQ2#(N8fX>y>wdF%vdAfgy$(#*ayiPYj8re-eXhl8)2 zx|=6Q5TE;N%Ka5p^97~*oN^zf+_2!8MY%tr+CHM(GpU*)s%-}4exGW4m(sOUH9M&q ziPA;Mzcp`BZLd?hS1ETh<$i(ET~6tqqiXW0w%<`Y{Qo3XGnJ}&oT_=0az8@3AEMm# zl#CQXA zw@pt{)tIRo9o5ECFyC=&iG>qZQ&<)2bd(gB;t5C_gDKOgojvT`MDBO>7zb)6t4tp1NOMwyYopKZI|N1q;S-7{$iLZITJTtQs zF^m&guk(x)$k1&gWvu_N6qw+CQw|`H55AfyA%?LOxYQHKb-#)-dc6;ymIBG{m*uR| z1$j(ci=4l7!JAB5Gd^;A0yA{a%ZX2WulZ66*xb+JS-vMwpxaCeOZ!3!{Kowxp5=G~ z4jqDs1SWX`zioS5DgVSw!QF^QS)M?)?ys^K`_ZfUTng~Ihe62qUiWb+VAX9pUU_Ou8zR)9x_?PR<_-U z3iNwd9FPKI+sZ(AzxR#(GrM%xgYJH>VZRi(Sa+>FlWALs{x5Cn!QPY%$^`gItfJui zOT%gCKX1TDsUO>({cd)&wfdbsA8yN!8l#(?GsI}Gz%kvN1{-&qY&&zN=eu+FCv`6s5m=n{!6>utjhxW$~YZI4Qq*gf!jb`2^4)*mbP|_K;4rF`;x>C z5b^dDnAXkV=#vkD#$6ApEE!n6fa+hiDKQh9l3#h3Lf+L*lVDx|#JY;7h$EP>ragEY zV>S!sl%Q!s(2PbKV%IQR`{9(+LhHmiMmk2Q=`2sveMhjvn7@?zD0UJW*hy5tPGTGR zWN;88(+D!5Z z`DiHbAb4W-Z(LuH^AfB?vM-aef5+k%qx>4neg*w1)2y3k~YrzBtyevD<0#tR(hLIkgF^33M?jM!4+ zj!=ppq(B}8o*Yu(si6gehgB2gE2z&VI8C^oh2BCTfc{Y~qE7YrBslY$J%!#tS_j)f zPBW1b1F1#S!RdUDjAi5O`{-Gu8*>bciHQX98Wc7qpIyn@Psj(LC7)<*^z1z@`+685 zwZLew(p4l&yVctQfZ=|gV0>n<*X#N?d627fwN#qetkmVDlU{{N?dE% zKhC@UH?ZoIhI5H;mb4l#W{g=DtFHT{=c_1ySRDy3&F3p*XbpqrYar~G!=+?0y`M-M z%$7alWA;D)nak#=A+1mnfR?5p9`jWRp)#vy=a>y4?q#z~MaSm|A# z0KcJq-_r|aPzKL4_M};TtwQR=agAHDhbx{e4C4!!npOn|!r4DP&I#m8Y&uYF(TPUxEj1oEc1F#wF~b zYzP&~T%Uk7t4LifDi0Ay{HigvhZA$s1l;6MAiBqUre8?n*#AKB?)tQazgKphZsE+~ zPg=IKkQdrV4CAq(Tm=JodLjA2G2y5TH}aD>4SuP3tHBijf16CF6Jo;}3cDvXwc~Bn z;4*rgT7&SLa!t3)-y%D<<8cZ-N_`9~r#3|__h%~O5aZV%Fb+eR&?{V#mvPJi$J->p zR-r+JIVz3le6HZjdWSN4oq>GXj!$qpah2gZ1D{0GFCzKuQKFFRJpP2G_ujcqg-aVX z!uIjIur!K2*j&J5n0X!%InEMqNiHMm2DCV^YlMr4l1dQJ*n_hf6r4zX4(KxZOm|jh zL(Se0#UGRD6XXfsB^N%>?}^X>p5io#!Lm!L#p$CQpUCuK@_N~QfOPE26lR!&8Og#7 zvoK?Hti5IX-TmSEm)VF+Z|T<~Qgwz&2-*@|$7yy7al{q-jOHIW49Kas>nz_Phvzn9 zagV4W*g+A0amz9Oj?a{@(BoQ(`yO0xU_5>m*F4@dzyf8{CrWv4Vwlf^X zNc;GAWcm#y<90dxmyh|kWkG;xJmtvlmzq-Oc7?zlguqNfp!XLDR7_*}tNZEADqXJT z7B+`+iBy=UT>EJNy>uy5FnuQfvdl!7e;7DDH>SyD3b~R)E_2f?Ei;RyA67`Xyq|tZ zx!EMs>*JX{-{QKM3TIO>D;4{McI~5MH8QX57ckYBjp6YSH@;D(uO%{p{u9?6QB)n; zNL>T`&}T314G2_nhS`tRDQ2sbB>n-^-_9ho(AntH%Pmz2TZ=0)%9ikOvQk8{8bk^Q z&F_d*vP7AKDcdtry&h^bKeFEv))Mvwn6V-=E@*jyzC(sLVfcDG0dMDKk<3w9Tc*+F zcxpH4smx~Dh_}ld(esAEF}*kN9VhBOmpP#gO>eF_Mm((_l_@?`R@Q^fq`zU#0R3@K z1Xyad^6)3iE7fE$m%%A4cP1g9HgX6yFbyL{yy|;MTD9(K+VFqlY0dGpTB@-&!)nRM zO5qWO)TlCUFg^WA-!4jbPBwjx{*TLv>y5$n)c!s_bucH3LFu!X(@r8Bj(vR-$>fTa z6#e5mBF^vi2?FI6Y5r^3@im-z&!KzBb1bg@FrZYyS8aW$9&rxd$RLcg?>}@l$*nNj zhe2uZ^oyb@P<|aQwJqQ1)0++!BW{OdKQa!|zfmZ7rEg-28x(vi(+3m^Uh1=(G17O- z2pug&%IW{8<(rai?BeqzP*LQ2crfoxeR`Xk_jV+@gVrl~H}*|TkLTU0 zJ3d=Q|6?$3mw!m!{GXNjL4DU~cD#Tu*U;Y*Ru`@%6-*rzRQ^8YJ3;vl+wn*p{iX8V z-Q>IRgWpv~YC{o%%r(F}VItzrFJA-uB~~KmW0W=r(na|T)8-c!FHb1bSLnzCEM$$k zVEA~=H}d(I=(QNXOefH`xa_!caGijxIq|m)R|T#rTx)UF;o3G~f^*cJ6xB?gA?*fS z+#<{ZC+|J5ESugtuWy$>&uA!V)tJN`$yFV6wB14fk<_5nc;qwL!;X}axP^tm)QjQP zuuGEtcgVXO^el3F%eFW9JO^2kYFOG$o)kGs`LyXX9Sb%b=iid) zLh>w-#04#hBB$kFN6=vMWc%UXb`EQx#{6trSr|1ELM&neSr={TH>_)4*OA|DY~@Dr zY#;60gqLIu>S@_q-Vfz0y?{KyjpHe@BA8Ep!9iIQeqizLAwN4&=GbB2;o~xGBSj)g zG$-gOMmi;d0_C!c~mxFxr#CUlXo9xJQe2`Ssm? z19ahr!tGmn5BS@;Lk#G5xm&*es5fu8k?GP{fkVg~hXKc0G+ffA1yfNT$F z+HEm7h<}iQc4!ny?YH$Sj%x4yejU+rW8xRbj`s>V|P7PSv>R6K%zf&bv=tQ<%QvTJ)7Dm1Ef3~i z=~+jK>u6yebIs(7Caa%jq;so|%}7bexKX?6=>_XECFK+6dCN4*PD>hvUYC)>=suNo^C?i%0}h9MdckKX(7NB17e~hUSNDddnI6$qZq(MTsH=QfTRC&& z5?!go;~sTy5{wGC;HaDVH8R~;2MOQ|8<#nj^%gD5)9}^umGJeOOgE4hMa$CW6+4&D zTo#=73BOvV*O7<(Dw+PXl5F$RWqHf^JLSs?L=8vZucqL>O+baAO;!Bb3IDOIUUs(f3vJToGs zGkS|g2ocIzEq|clLFVh-w*lV zz(T#kMcgEUkwkK8w#bf4kdw3?Mm4~lIGqk@u2!%n=1i}v5~7KMFi*>@*KW4`!?Ru| zt!Im;N4>8O6LutXix9xzHPU|^6M92NRHkYPU8ymZEpb#Okgb$OIG9;D!P}%9aO%r}pgW5!xCpm7Ew^z2X(7=C{<@4;dUN1gr@UU&`n%rqbNbnNjbeM2}S$ zu(BbmHssR;d|Ho>t@kBV`g9dlJ)ACjM_uJejj5roVr8^)A&D1VQQT<*FArXJxwwuJ*3tFrn9C~vxOifgFza|GFi`uY~ zwrT=a?F#e0#UuBGtn8YR?}%1i?#P|jp%NOT)9se|`_9=JPd$}3pMp}b*x~WOL!Hhx zzpiJhM$N7b_D!$}Pkx$^g_$-mWg?uLQ z2_7CjntXVaFTvzbp8EIo1$3Bkjd|PoIrtcJK6%WG=ji*Nz>UCN9X|9jzp=tTMGq5NpoMC6O~4hSb^o5Su81I@4xK-8=){U=-s*-dGZ-DolCOSO_rBE z)rTfQ?1Ka@IMT@5WZI$7u0ylKMbC8l?my$hHoNS2qK_=A;tPJE)ugrqymxV~8d*`Y zhIc~eIj|tiL4PjB1sxJ`mbZ(qH;>w_vD}~3q|tJ^mdK*c$lA(?T;>J#DJ=+r3XK>e zju>5aUtwf&RGq|zxg_nSX;cNq#+`{|6fZjk{n_hv2@E$Xk@8j;B!>HN!*4uXYH-A8 zZiK{)XRL`tUZ|+VOrY5HPRiyrB^=-P`-WF^jMcQJIgnPo;E~x<+C*Ut$=HaR#%J7m zSdY^M^o+M&lV_8VMi;~iP0tC z%j)zQ+MwX~C5gVQwD&P+C9baY8T{FO45ZRz;vbVmYZCnyX-F=`Z|~bYc7$LZ4&MbP zCsqX0Hj)128~$P4R~~#nB9X7h_eT09<@*fGr9RVAP6yl=wFm8a23G~H2(D&aRk-SK z_56`wMGyb5%-}fbKTxu(aPPDqcWd?=yUe3Hvr{dfB!$rKRDEPoQ)F!*B2&c?E-{Tl zyH_ghUa`EeYM|Z!{%!a0OVi#elcU}nI5I5WatbVZ_))#Yjmk)6a7653xMv>vO$!=6 zO>OvYwc%yb@MpeV@04xc8xoEmt=zot4=q;HinoGY){DEX7o}a>Vx73);hCsXi_hNe zo7m;MNc3Hd_C14eBhyVjcEN@WG%*~2J6D*3AC9SvoH<b#2aWrnlB?29GqML9WB0PBcOPrh<;Zhcg+X3o}TPH_WdZ8c_%wA~n8{LGaGPG_V# zt%iGF?^PC8RydJ=RF=@T(@9(L8fSvGfl9xA z3@`Fv))MvJHVnT{li#+S<#5enlO;~bOeKCP@ZxjwVh%$BQPCkXoLDLoaC=03%ps0A zz2reW#-|5|d^&=BioSiY8GvOH3F|iU;9z&jAA3D4mob7Yw6Vkvnv(1QuHd~gCR>^k zOKu|{1V;?xuaU8QqDTb--1M|yVD@wfpZD}PA~${6(q3hdOXNK={T(SD54kH6tG&;D z;jw0>O|aFa&H^;{m12fJI2GNkOYL0&Us9LPa41QK1C42EhYug_N&EzT44qEJJE7mf zSClUcq2MUSH{8 zbSHVI`(8GEiTy9GI$Sxp%5W9qs>0>O)r_kGR|FT=r7Z{kSoMuLk^q1p)#CkPmL1#e}lWaM%O2VQfFaeO8E-&@JeE21sN z2^E#=n^)MpBh45F-9^;d15BHns>JY{%eW;fEz@R?dVyQ@nFOo9(t1OaHPB+cUa~In zSQjr`Hq-H@zr}ambA@-7gnUcteF4e0xXI_Q^j%+X4Th{`A>R#xugv2MR=`KU^`;i< zq88tc^}d^$e2dP0&giC7MfaBaXJj%pg;a5I&)Lry_Z8IEZyCTu@=5~M;W;^rD2=nM z?B%6=z-lPs7f)u|E~BO%aXPh@=|-^-u5!7#A?ppHLb}pgR$0gdto}fu#$ye53bnDX z`)!d$^oQr_t=GZXPhH)jXGSkbjClWU;MdFajim9~(kYc}(&Mgc@m=5IyP?Hb*5X5@ zZfx;^*qd5>!4}kMESV^t`6r`$Om5$_|K$_gzu!y1UrythN=z0{;*@0=e~+AZgr1`a z422Q9=m?i`cwRD<>ZB%bTGiu(k_E2&eZ#TS8FtBK`GWa|G)kCu4VfvOUr5&B9pkzA z3pq46+8>RNB6UY)J)cnaC1XvpRD7T4w2U9-K^)3(axmw^DynBq*3B`#|FE3MbrsuopLEUH=&wLF}0 z@4e?RuqCebzVQ`bDAP#_M_-q#^jb^BHxXM;9q4d6u|Tiy4n_N$i+if(N4@WVP0FtG zE=_8(8Y4}G&s@s1T|&whtv85;2$5XI%@qm}3x=`!nL&*!;) zp6loGd_F>ZP6H#O?K$OdPljTwJ=nMYxAt`1+@1?Txp$AYr;n$6^d~}l%6w7EXiU+m zK$+7FI)vah<)F6)eQ7AHsw!-#_kfjTi2OY!x;g$=+$3iocZAFNK`(uPlmM<&WJvvS zc6@)nike`e*6-XfT(w?T>QLJM^E}FX>EC1`b*@6~@u)qaw5qVij3s@a(@fhV3+!e_ z;_+fpV0B)6 zp=t9K?FUK@8B=)RK$C<@N5894Z6NfNfU0C*R}K8BkoPWVYr*DmOPDDb65$&=nT%m zzX~zTH7qGE!WnMBN`Eul0*|v7!mXaG5qFL|O*?X0aZnCKDjX4!y) z1Ao{@-$uHKa&~NC6_DY41!n3pdJ>65W_2F`(~?f`ANuHVB+iaFM?v?6lYgHC=B6Jw zm?Q|0M_xQF0MKvy1eozCSEyE(`8_^*m~?{0)QDysAFp@HmN~OGm9QPb`*_`DI&udRYZP2W@o7li z)fD}}75!F7O5oH4gXV_&8yL$r_&Q(k|H|>DJ}>-A+2q59A*9y%;5kFkiSf%gAkkwW z3)j$`Rv+!wNBwn1)VH|wO-P)YmM~S*rPQZg!3fSGh^BX6B6_q&WlF!Vj;O8}xsLyH z16?(Yxk8;0=0$*wo_Ph5??Y>&l&e@KiSAJC>p1#`!+M{Vj%b#!PW?NVEiXH1FX=V} z?TiFc&m>x-2?du%L%&O+VOyh3Svz^3I!=EY3~GaDt|5y;6x}M|>c?TQOUr5tk3ksx zR}}ULeTKvzTuWFixYz1mMC1ngqyYStkKRcT3yVc481on8VlI0HqDMv|Hn=B8DN`AZ z)IxoxPBxj!ET+%W-n^6V9Tt=cOrP0Pr1U??ufNRyiosO_acCB@V7 zE35^hK;+LOM5YpWkfWZfko`_bpKdBkBY1(GZ0KX0yL?Cm+#F_tsEGam-g-&S7^o>0 z$Q#2V9pMx6L-QrY8b^_`Sn6;D@vu;}jx-&b%Nn;*UxHrk={fC-lYuzS`mFLW{TgXP z%vnj-vGlY0?|d=g+Our(CmOn##225q)nO!J~wEUg!TXxC>!uVjR7ZeBPj&^#7L}g#&JK5Dr2%R)xQA1c7{S3%&$bK`cM) z`&zlY9Wr$b?lk2>_t;Ln9Rg*qBdCA{wmc_|G0PbYFVvs( zMKTumTG}Dxj%39d1}Gj73HfaV7>|zfN@@PMPyc^VLIpi(w1oZFAo>Z28)FurUBokF z+o_90hpDFr7W0!77WY$hE-4t=6)fJD#O=@+4How^v*TbRe?Cdj#*L~qi8JCdBFEI4 zs6q6#+uvVIKDzg!`GLy}C&FHz*UxBn=Ih@@dtRoEq!9fl7dQM8lW?YnNaOws@vqT? zPYJcAynYS%Ag3p0$B!g#WZGFRIdy^!G5-CFXu8%Q$i`kmUJpHulxcqZB4lGTM_C~h zcNX_}1S5h8p#Y%@p#fn#f*ZkuKzJo);%)Bu%NGyn4^9c-4<^?B?2EVxJR6i`po?!Qk+8sqrI$*iIiAaxq+4D-wigcC1sNKZt!XuYw*FuysWE0HY++Gdl}j} zj_?@%YY5bZ9k?%1f*Oxx}4HAJJpQYHy_InfochG+$F~+;;1s8kg$+dSM z617{#AEdyN9TO?ZNY^8rAw;OM*UPWFNPqksVjxGVeXYeZL)7!xrS{|rM4I#=iHH11 zbs6iS-Tz@;HEj6nDGMxdkAols@qZ`rRy27Wkt)6Eqn{Gm1ml7Azjj9CV;LY>FO?Z-=!D6;dlFpKUMls64!QmSl@9`dpBG7tHytj8Ccd4 zra<1mfNv+KodimLce?V-BL3{Kftp}2P1OH5EN55^5-b1?C&14Nzzza@P(S7^u${f9 zv(49yaXgA(ItN)6LJmScLIFZCLIZ*uVK+hxLN~%7g7PQOdaOKk>^k@X7_bSjRIh`X?{4Gh_4vhm|0?|3W59 zHdCxWAAGT(v`icF^@j#VU7FyD_<5Y&q9y{fNkPeZ)5gJD#Svef3|yAT_2U@3C2~jH zh}i7Uq=+$Y``V*BPwg9SBS%4wV$cP#*{fa_k2Tm}{>9-3lV<0}nEMyFyOSH#=RiI( z;S-y~CxN5qe#tERF374-*0>90AkZ*7C$t{i5fP-&G*`)5nNHl6o0DV-gx_8hsd~l8 z)WuQibklsW0X5c0Wldy=D>B%%93*70b$Lkhauu^&N$D=Ia*w=$Q7V+$21?{%tP}-K z8>K&CTDqZK*1X6sS5rbLNLb{vlA9Z;R)N#LC+N8m&?t`G05kcrr~>hZm(m(|cTf)% z(Bm(L&`FCEZ-@D%M2qK2#7n<>FehU1@BBhKV{KhIXn!SCSeA#lmXo#t8)(?Je=v3b z@O8fBi(t<}{Fq9U1rw14C)C?%clie(PRdfJd9cRR6o~SHaTA-zO|nV^ zgnb`Wqfp9DNq{o}VIau}&Tdx$XD3?;VGW#}OkkuY;4A_-lO|Dk6zfOZ%y1@hoHa7M zCNivMd8l=H*ue5}%<}NY>BG&-VFrtJOf*y;FFDUX@M@2-hrdUVwJGV>pG51@d;G$n z9>+`HCI#~ucy&pli_cdaABY?`g7Q#;^5EYDxz>6 zP#!wZ0F=LJdC(M5XcjMFwhsz%7~~-R*1q^pb$pmAn@u z0Kpd<_-apjk1>S*)$131E+Mh`J?f%@oU)}oj>X6Mi(cAFBKZqmI!DO!N+lVNA+KNb znMvZ(dqzc{Jw)_*#!IJ==txE{hQ8K&^hUBL!DYq3Jg0)Kao2C!7RIVuE%Ii?G?!v} z)gG0*iE~*c@xey;!G=BrZ6q03@$L{dpgB<4yg*tX($wSJF3z~S$}iGgAS=EjKjidX zr|+;V7Ps;Wh)J1GXwUB&Gz%3}OWC_Uj^CX!Z@GlCb-<=_geMt-rTjbt`q4`@@?fZ$ z%J0&KxR{Ai6DRL{_!6sREE7+K?ANz0n9v-^Iwr~ayC&H82enW0AKiSi8G^<@4ir&t)gN=1;1aTcem}1^!`a z03608!TjGYFn3U`ZmKnhqNyen1A$G-?^+CZi10%*ZvrpBNM9ijqIu~>ecB})hr_}b zbJ5&<@#b^#XOfU>xFm2ugZR~WVSf+(Ptr90K`;Gx^5a-F{H!+?&&{tkHd-YS58Q7} z4M?BM7YcJRfPRa>ROA*{*Egyi>iQ=eORCpz?dDf_>DNbc2Q-c4R+8Ky$h}0!9YVkS z+qrYR^ot~=k@c?yg>f#Q(b>m2VhU%Cj13*?YQOcuz`_R>#~6m5tguj<`|->LatZAgs^IusO8 zUZtn_q zV0lK&b6)xZe=SHP0?(B`yGv?yNmhS@>_s;bxf zC-bIP!bidGC1ATlTnfrHU%Bsti>*Oy(1E;1Kj39vI+s+#2A}rt7vhoqB9p{k-!F=e z8$*a#{@S&Xl{Sy0r(W}#TLk2YN04*z8lB{CHbD-EzNZL!FdKR*de{KraJ21d31o0k2J!OKX-OdBStER(=>9+B;s5;!mdHIr1# zq!5F95W3jhw3+Nwj^g5pno58kf)w-~T~F7e^AM<{#!wcTw!4edz)X*#)*3H@j}$eY z#2aAZ`l+<{$n@i%^U)uWk@aUr)>NJ}7hLFN%GPBety3nTHE>CknyHJTG=YnwLYdTQlp%0Y6x4<_lqJx5@fk*14s4VF8=X$N zH83|z_Rc$uw3Kd{>4|gAYGzVb)AkQ9t-PI)K1e%1xWrDVnZFR1k4ir8jm+IiuE5N$ z3?|SDaWxZ|`#eb1Uzqu@fy_EWr=%zGnLdNqY7ytsrKAhSBt9J%{Y-k*tsSCi;NDF& zSg1-3RT1&hkF#7d^-P1QvaZGV_B2NN2Izc?sj?!;PUG}wu%uR`?!n{Y5DiUf=I6?j za3q@+*ZtGym=^Ep4fmbc`b0I2l?E`hoRiklxph9xuN0|{Eb zpxQ;=UOOv{L6hyIx$tvIBuJd#(HMzM47gKpLMg?iArDA_lOG`s@CYA_5gw^nl?(4c( zA8-8ylKW+$!c@B35*YRV6X)Oa0_&d+x|cVwbrwm5RZ{uUT`alz(?>}ysqmhKM=JCe z{wmd7_P{6%#>&LQAlCPK!E1$hbc#Rm_^Vz`U@n%*u27zRCd-v(m}Kbo{ZQy$)L@lV zsFSU!D-9w%3om;8V(^F_#ecYkb9WG3DFIAYCfGo7m^m7amI(R_owuF$rRQ` zZ&4?a^Y$xR)1FIjCv8ekGKe$P35H~>Q52H*#;+*#{Da;drTi){8*cat?ih0|mPMNO z#W-aDNV4!Nz5114|JRY<4lm@^HRPvx@Pcsk#qf47{WytXS-!yg0~iDQ=ts!+7@Ol> zFa0oyz>QY&#vA-=KhrOg#`3TJOz$8+n&U-y4iFGHpqLi%r@caR=hup8`ox8#kP&XM zbg#EPFjo_3eV#mVi+-Q!1l`f%(>Bskqy)&uwT&I^UU?EjMRSxVj|)c9Z6wK9 zh&49S?~&d_)UdmgEP>;r!sifF)&3KxvI14(vItJ^c`H6dzio(}Nxv=tySzYcOe3uz zB^C24L&^3C&(_b!viEl!KvpNRZc~wxB;*seKDl~NL`5)}6BNmm&1}a))EtVX>uT|d zR$X~kh~AxKY$Q+yQW2D_@G?tyNSjN~AThS>7e-W_l6clj=G62$MCT`2B$?`DEbP?J zeAbW|dF2<#=04sLG2waAp+dTfPMt+r!1|cUz<$Dh`1)&E;kG`jRQFMfJrUE{?(VXcFZ{?V*ua(- z+%-+g4IfrjdHfgL6X`{pUb0)7RO&r{%!Ni_&aws&GRkEQHH#_7oD6FtUDL?88b!JZ+XMX-r4B&(2|7-64H+0#CU3Np8&u(@t&<|o4$}+IvjKAI2BaTpIuFl0 zY=Wjy=4_PqWS+M-O7aztIBLelKA<7Yg$p%{V=E$aKrB?4sr4S`5w9~p)-o8S)$==y;L@Xtn#r*jwM=IY#Z11Po!A}Ipb3qYg$7v^Qw)m9L?==d z?m9$c$Q`qf*KYOlP8fcmdpdpw3HWY&Gv015B#q}`@HM>Nu%F48UJHx zl&%LicYcCeq!YbK(L9qM)vS(ff&S#A*yjA`-I4BpNZb_?_l|M>O)B?#RZA1+epk|R zK;{0MqHc@NPFcWJRzQN1R)4wNcqwN7a za;EPkKOwT%{WECKrT!1I=;xbB&qXBOssM{Nnx6~pLs~<6VMjy+UcC-@ zNG4jxMbnc=BE9Wr;Z?xapYg$;foo;x8G`m&L>E4Rn4Xh^NAYxm?PUYHUv=Y>Ev%F1 zrt_VpK3ry3#CARe*^=@+_@D?n1QS95LKQ*_LN`J`0yP8}1Ra72AqOEJLH{CL6?7k4 zd$}M%x(1@K!DJfwdUOFME*;y>x9qfO=fHwlU z{x!wM&un29!Ym=hDn?e#!l0aZ=qfX= zJ1njl7Hb@1jmH{vJa)>ug*ovHQwOP1Qbl5aysGpuw{u%8Yua^*!8RPD3fP&S*x#Va z;oLQ@xF-FH;gn|gpy64ATm`)dcB;k|w~S&MV!4)?ZZ{!Bpq$9<;h>)wPh$(A4sfkz z>Q!?`o;Ter-x(bqs?N!QYDwuUL1Yiedu>?yo{tXyS-AY&h6^!n_-sv@A&B4ZqyIt% zlgNU$Liv~cuGi-$7OR}kCcr_~GRLy|n(guSt+zjt{FLK?dA^G+inyN{$RwNFkEy_T1F40EUfw9 z5*}JS$w$1tqW51jAOW96-q`NuUvbUF$4v4;blemvsowpGtwGVz&qpJE28qvRWNs5btvG<^dGiwu5^Z#t9Fr;U#Ve@=G&!v_LP-|R8YeQiDH8L_Mr1-+YJXY9 zq%53N!d8$JtW6v{dha2n=O=1{@3BiJMn`D(TAh*!XJjc8-q@a4{nn7{7(JA+L{JF~ z;-NJhd=EXB;54?d7otP+mI(LSKWy2uyUiZ<_07&%kUO5 zmI9eXK%v+m$z>!~z~TbOcrMA}|1F(Ny{%#DuHb>M##EV}XrQ6?-k_OR(b)|uPvN8~ zXG(5y;!x^hX)b6yg^Q+KDbe+bL+N>)S-xgacwhDQ(o}DXc7Nhf=911dALi|jA)&3P zKS$BPP!*#MK$39gMkn=aBvrI=2oP9u9B8j|A%yDs&`W@WdKe6TSgz6&eDoVh{tfa5&p7T1C za|a|*@4t8)Z><#r|5E0xXke@Sq}CCgf`8l#N%3Q(uY}fu=V|P0E1|W5=@0y^z~tyz@arz+6hEOg{;RT_LhwF7W!ckKB9Ty8x>?h{b7G=h8c){o z?ORX3B&+q@IcVEHG9x z>6rv8WUo4RMW|y(4qM0v|0+1v%pDS_E_w#(6d&i+2mVTH2|OR`)r)?mr<332E$4;J z;LiL+t0eQx7yL9YeH%$&gU@Tc-FH{Px>J9^rZ_Z0pygt>kt6Z|V2Iod^A2=Nx~%!x(A4 zchJSu!sU_l=49b7a0>4BTAJ}QQw9-p%fIg{;oiy zu3pr25Q-!k@0gmz^9h=+2+&gTWGrAxSHI&Nbcc)y?95*i{JU~q=r#SebH)U@C`yS( z6(6$GGQu)Mox}!+5nDEb8g@+f&Kn@m4Pe)ETaf*|y*+9^kH)m(_uAE!Sj@z?c> z79g^U{!{?|!bd+z)~KLgWP}Zbufb!+7!Vzgp+R&0ISnPYPZLFjmfF9htXe-!OnmWD_A ztEQXS)!=(SNN^1Mv-H71;5dc`jyriGwTnRacH1ua;v_Yl4fRG=R&$hgrY~69NjH)@ z;5jembjK4%^gsI2zl{lJleOO(X=oi~3Jrh!C)@WvDB%>JfT6^t(vDe2_{yK4oK!pK z2*3WP4)GDb{3p6Z=z{Ynv=ujbhw!!Lr%~;r`^opH%Rh?R0y{8X`kL=2pYKcP4N3NT z=T1d{v5L9ZXzx|rys^*04j~0LiY9g@#CdrOVG>|9!%Emt%%TG8#zVG%wRq&M^IXXL zuRxD=W8UIGXc=qVAs-pw!wM|y{BS6*NF&8?$p?f&GcH0SO{a6GK4CJJS52e2sa(!X zWtHGRPJeu>4nDTi%_a+%L8tSkVgVuwdb>)P(Lq{)hVv(D^%*>eWDA{RRq6~%Qz}PR z+9D2?v31kA7`>6^5BZ|ONdCsB<-w_eyf$6WGC|2~m}%-p+$1&($k!h9YqhOr_!U0_ zPUUnLE z7?P`+OT+PB49}PQsvI=u;6R*15b3k#iel(UMw822=JO{f(It9f{1|h9_yCzYWF^D` zwc%Sbvo^fR@L}ZVpLnHQL@bZBYNl6=uMe|_ z1?5k8#8JA~vvh)eVUR&HElyhS5~n**-I_uz|5^7tWdS5FDYQ#7tvN;HN?~d=)0~>= zN|UK-eYG=1Y}ZV);4|G+kX&s^kr*`74JlHTO$@Q8$eK0N5Tl;|%3Cyel=kT`ph%2; z!zMNMAgW5x^Q;K7aZl8b58$5?TPacT!#Rt^5sTS^2PAnHgX|PDTW_T(mz-*LZ+15+ zo89%VG^twUbW2Nk>nGRp9u0KKr@#az9_<7*Q&IyZuAyXHQwwHr!D6mS#YR-stMDc+ zCxLUg|)> zbKoUO(MeGdv?kYr`j>B6oM1>+M4jZtML>>w@Mt+qrn;o@?IC2QYv!5hbp)eUk z%7Q}x`&F1|g*85~6OKVg@Tsv|1Iigs&NDeZVr=&ib6tng;{FRcGWZx6Kw{hVu!6%9 zSOJnj7Ncr5GdnauGcqvL@=B%Y1qNB-MTdCu;<8WFM8nDAVP-R2LBO*6uz)Ans6MJc z=pRfE`g^7&5_XqHT9|}?`^Z=#7C@z4W)uN9V!KPn~YR7<<=K4J3 zEgFn+RJG@PhZS;I|2t|vh@ypd<4u;u7HG8v*==lPPk{cA z`B*M#JpDdt6Gns0k7VmyZCKh(bP2yqlat_C9k3#xg0Fr3^*&~+3obS)SnwX#8|1`w zxTMD?j|_bJ$;hL*2hHR~p^5ly=pM4kVII2ICOwpUdhKD!S=fh$f#*%%6QAs`dpMqg z@o_p*OwT2Q;t`tz8h0tp?RXv#9IsH&28Oag_|Xp9RcA0!FqH6->jy}rXgD0N|2|%k zM6&8g*7h!?`dsf}WqxD4V#$ji#)s5y`W|y0cA-zL9g`!Y&rm{yUCv%x;GxFT`^MT6 zL5;L$(rA0sqwVS0rOX!E1B;*VbZ&u5^>C7gRw%L+DfwWIjJ8uvk!IrgnC2tbnRpsk zOSCS40Ha}OAXFpHEqU?n_>h!5++7bgj;JP93%H_sgnJ@9RN$(}wR5$Pf4{XgsNbO4 z6*@DU^@!Z8%<#e0%=P)=V&Gx0M7%#|scCokyW!glUd^eW)-$PJWp?!EF>(Ep}HOa91_Cw+HMG%9rSjWjTwht4InCrj`TMIR|vuBy|bZ zx+Yyqldg%%q|zFmSFr0{e;Qk2R15aItisiz$H>}0q}RAF=zsME@Rh0(n(iXk#KX*v znsjUz-N`DLTKX~+7RO;IJnJp`GTFmewhohERbo6V=gIuV9#2u!7X)9PLwu_^sFmJ zu**GI?;hOa9weCF9at|v$nFm+mL64{3O1R_2b10X=c-TJfb;IY>eBu)3?Z_g3QiXz z9(5Ers{P}E1Wy-*SV8* z4aqu9JD1Z?CiJ4aUWd9H5_AO#x`+ZLX_J5nKN_kE%Fz#CB4Dj9r@WLZA6zV;14tRe z$QU~O$T$^zRFN+kq}*}}IKeywTKpJ6gMf#0@o!>+qN=G;Oq9w;F+mYb$SK_jCJHE> z&`0#1I-sivt&*1mFK9}!6ovZhOs)n7(0%kB)uwBJj2wy}BcGxAbUKGlzSd~)qoIGX zu4)twi?5?W`lzpJxU7mQ)14~Ub(3jfLf;$8QEOY450m4)_a9jG+>T|-_w2<=3}nCh z`pVTG&YZSg?m4zEpp9sbQ>A#W+g(;VTwc{*{==CoSHJo?kgcjO$Ia`h&8CX7M>aTR z6t1a6d5F?EF0L!s>9Ef=a7?DcxS~GRbR90gzoeO@YG(yOcu5h|SRi zU9rt7p%6hWR$(P#k>+4t`gB94kU<@!HRZ7PYrx4eY#uTN59i8N!rr+;jC~~=TJ;7^ zV(mY!8xR9S(G82!BMcDw!eiJ>^nLImZ*ji@PYDC$q#UJ+0VcQ%rUH1@nj)r*bc%#x z!}C=v6(ixqTgI-J*m^W>_*eosm7xmYYiYt)Q)%fA1vPTfA^VfA-a9wf=QB#8w}^<{ zWI_q#ZyGh7 z9`wPCJNhh~<$(dVLu*er9;?PV&Kwp;yd;iriX-NUwaF-dImp0>8WDsAouvGj+@q5T z$CCVJ{B?bDkMWNDDY}^(vl(sfZ0yl+?E8D_OBW8)+Co?iK^F-Zju&@0eE31Sc&c%D z=ZG*CO?LNJsXQ8+&S29I*y0#lOuH?%*LHhO2UqYV$Mn#Q=RT4& zSvyV}+6vUuti09&kYvd?YP8DSo2#Tqm09q}vAomL#>I2z+4|DBZ{pxcD{z5`s~CQQzmqlY2FwSmEt0WK?zP?4ZksY-;|`0@Vp+x0wQ6d| z-QDNh@w8Eq&Pt|GUt9c6w$I{f#z%HU`{@+W@^7M-b|^zGubH; z)rc6E2wDLuvJ0-~YD83K0xlJP$8FAnO_|inh9mjrED_V=b@uo&*Vja?SI#rFN7cHb zsyts;E6pa)`_-P0&D{rdN{h*JK-V5s@m>>Bs5FyjZ?)$GbN3#dXOC_V(Ux#*%5<#X zdLWZ(>-FvDcdNG3_4=c0D{RHNK?%wXQ$d<8=lg2d4xv&_IlokwChMq7Q_l2i&ZncY zVf6puq}9C@zSugEhh~-O$?tdpq|oyx7R$dH@APU?VG)8`}S7< zdvD{hy*rQWh2iGrcSGN0Uez=ip0re2OYBRX88x$AWWs}1x|~Z4=@R#4WP6e~9~Qse z%}A$G5l_f0?Qt2j{IzTB8PnS^!mdaP1{Y~-s7yY2;9sVEMSGV=^98e{l~z*$lVcPR zt7l=i^?cMyUt^MjvqQe(H0|(VM&{y`bH>*OyF6DCX20h6Y;ruP*4jRJ9$@5?)3N7j zK4;QKOIi9_-uuJ2=flL#DYO5q0_6od8}3g0?S-x1QL0hf+$Vaw7u-i!on(XMkwaZ^ zMz-6c(ivLP-XzV6oXvi0x4u!Oc2@4SrpC$lCO#p1OMS6h@o|;9p=s|xI-=h0J`YkX zr1o>)>AftK=#&{0AG_5p@9rI#k5pOfdE8Y_Mao$w>%oDnmHp}F{+wU>i_7gEd?Bxp$X0XH(nb8XA6aWz+R> znO#JKCYz~&Z%S}dAI^EGoZ*2voWz?thl1BPVJGEgjzy<}a z{u!JxH{IOvXQbm?2T2Cs5VhOkUKz%=(tF}VBu~*XHe&t>UgRYBUvOZI6*iKS$9f`y^1cwc6rENR&BgVwK{dWy_5pU)TanCNNj zp8c22hg7Ha0&hb6q)p4nMU`u#-SXGuXPLuzIZvGhUGthq?Uhe{HCHwx1hX!r!%0=F z-JM%+%d^VrjbNRp&ypuqC@w2@MZzQ<%cwQQ^8Mn>`po3_91kQkEL1L~bcuIjbJ_7- zJlhFU2nMfCM&5R^IkJC&s$Zk3pA(y(FUi!*xwGK|BSP1a9zoQRZ&^yaMiC?gL)C_3U+#EZdJSP82n73MsbRC{-Q zLi()j!N-Ev{?oTBayr^esi|V|Zh2;MX1&|tfu+b&w3yM&MT=xR1{6Yz!IC=S9!CH( zlW&H2;j}!M6>W3NXESOXm$Igd@xizcjJ9!%#X@xxofsd?p+7QqnTuoSq$(`Om_+aq z2I_EC10~1S1{yL%nUuqGF@w#BW0|FRa659r8_TIR9OL&k%UM>jOQ~D|MIJS^%yLX@ zWHT4f;)Y;G*Rpd5eJ?qmk0l;sk3}BC8{nh-=rxh-GlaGragqpY2WQ2@8u`=!TJ{&& zLA@!B(d4SmuGaG8ZnMAwkM#>3<3XsrzodT z-eJ*6rR?;ylw-cm0IFjWB{xSg3ZVq*G*|nb53IgyVxouXpSm%IBkZY^Zv}4-r}WqH z#*Rm?1612Z`Aq%PLwvF3u(-q_*_6wG0(wj;A|*@M)oPBP<;)-t2%QbD3N)Yp%u9 zkO*jVVIv6TWI)t%s5&P1FivC~|6hlWl+*D$ko7pEPe9CfuzF+(5^t}pcmX~)x}_xTOI@HmC^ z)eIms+NnV%S!e(owqeLLbqjFkPzJ<{lBBreL(M*3+94jzN2P1>nW*sa6Vnx1gO-U- zkj^s5$laarb%|>(q0U-6NCP?jr~wG$3~%ZZc#fOKP1`a@L$(NNJ5wx5PuLbUV`a=8 zMuREFt!clio9zbwX4k|BR$4ErU^dNCtv7}u9+7It%BCM~se`OWVK#`*isYe(nG>9p zo!T*jA|5|59pV*1ebBRpkF<^1Y=@Ehx*fvfV5(RGHk6M%v^LZ zgzwCFF~XntQbkk}t2Ni|_2Khl9}cbDgEnw4*Pa4Hi`*~;njv6qjP3N!V~vNZ`y^zo zoCpg|5~nD!Gj2}8jvNfOY#l~`mbCjew~~$d)XtH~uw#YRh6O{XEC4A%CPT*um{o8Y zgXrKCP-XrZ(vBG-J@1Qb`N*w=xaI>omoVJWsbJJ1MAV!?#QW{W;PktLM5Y8X3|spd zR!oJO*zu7Ep>+%sGePUYtC?Uz8dbP6J&a;Zrkuu72=5kiOT!%0aU2}s)aDgfXtV_7 z(vkz9SEQf$$Q+yv&xHXhDAWFzugeOY&?yWxwwm${#!yyPsi|akg|Vw;YDc9cJv4K1 zTGWM+xirc(o)wyE#4Tc$TMk~ZlDg_Lvc-woq+MZQWQ#INGaa)TY*Lz8++ZpW0xDgR z=EnA^re=eB%hW94E*RO_isHDEc>e}^ecub9cZJQXXNnD*rb;B2e02({V4YjH-9siL zicXhhuFsIxGno#=ZR5@grEhYFurf7ODa3E$E+DCC%=cj==RC4e0pZQ))=ZUp3B2SKbjEi?}E{kZRI zXC1`w)aC|tk~VQR%f-6`;QS=zC(I)Mi9E7vAI0knOya+gvrWOonDZlJvzJT@QqROf z{t5DjyrHX+Z=c*1fUS_~2&3|ts{;I?9|0fHe&r}@Ox!hj>)J1`;WQLx_=LzqToW{~ zcLvo{0jB*Tb#jZl5mTQ!u(PFwbIX;b2bAxMjtLKFhSZI*ogCp;}`yoAb(u z#{$wGzXc`CniF9G@#2*CF*#DDlpK7A!G205n<`5Zcf3z5?qEv2@7wGewcd$69qaA` zI-Se{h_F8Z4<>}nAU5nVELtr~iJQGp>JuYBs5;`N zA3BIE+ZAMAoP=xto}EE^AP8uON@?&p7{&YX*d~J|t-d}6jtd1r2)G*7HXSRKeC69~Wy83sTiW??y?n#~Kc3;k zL)!{)z$z?!*yfpVwvH1;fkPh?iVf?vg-Q1aq(y#`glt6PUK=VUTX0<6LA0j%> z%EHlAn=<7C@=+6H;8mJ7Wj2%Yk?>+o6ea3dlj>{p~AR1F_?YR17h zc4B{*$8%`Q4sE>L(56F|G<=wmVJV$w;~|ZO58V-t%QcG zI*$5!ZBOm0A$Askn4A-e@_So<-4XdwR&$*lufJl|k_un~Q7*+)j<{ z#j^}G*#v()*^&jvHLCpA3`Oz$KywFU|ZaDo}xU_sP}N>2!h zu#4^d(}P_qN^0`t?2{Go2ENgs1t?kq6rHi$oa1YYm48xw?&PyC8~A7akSWjkScU&* zN3st;Qt*GiQIhPl@bw1%#k9YMdoHLvAE+jEO(Gg%79!lbwBtg&qMd)Pmw$c$>cIR9 zhGsB{ng}x?&J@jMvq^P-_n}Ydx2Ij@8B|U3P3mg5{VAU9V^ik9bDR1cM0}T^s)qVz zlfi8sHt<{W)=3e8CU@LPy2o5P|AJ3Ckutb9M^BArv+Ljtl7CTS+kEmRRF1+rW|PJo z0b39ao{eU2hG!h>&i3f(Vs-^=DB52h9~~uTSEoMbTl+^J`&cwgK*D3v)3C#302=uQ zNffE4X7GG1GCxCb#W!Na5NG)bWe)JJNCh>;MD^|bsx66?Y!F&{mf@e?#Z8C6lttV` zVIa;}dazhfz{tS-Xysi5&;Mrl7wvq#np){j^xUQL^kbn6PWo5uxj7n*?T=6m) zClSZ|+s^+b^*9#V(`t$;_fX?aRLRbQE^bM~@?GO%*54xMts6^o(OhS|{D=qU6l76kY7e zfdBy2%SuwV3&iah6%I8B+z0S5pS;mOy|xcj(qU$p+(g-qRCqY-W9nqUV$fVkj*q_J zyVRl~H}`D1BN(H$*Mi>qyyQB1YHhq?xcaC~pjiAMD?&OJkcr>|a@GGQNpY;PBNIE# z;M~E;4~H8;KLEqE!o2?#)dgcTLOO(*Q*&hm|00swe3>|~mZ)(cav-F_YVU>JVqmm_ zB=%k!0sYmBuc3?h3dV>#81hnvd|J}hQ- z`j&7LLa_sQEpCfbx7~8ksmEPxY_u5%y(3R z$K!F!U+VtMt)o2AZaUyQq^5so?~(5c*RhhNQgoc9-K4K`{v7)v(<7HtC*P&j_3d3( zGyAT|&jzR|RH6MgKqPbZqR-XeUa|JbT`1(;{4a_RRsBi%q_qF1YW3o!#|E$7ndvAw zv?QE?@pIHb3R4!pT~C!za^2Ru81-FL%9imU|?6oOROkv;!oMrpH5af2xP~o1wFQzd7)~L@veT7w|x1HK&JTKQX zHkC0U@En<;r-I`}w2_PsP|xtHkC)F`9sBrTn$mclTI@C^sM!q3QGI&b!F>ceedkwQ zC*Psfj?Avo6V++%MT{+U_VNC1mG->WU_AbnM$6FCNnxwu@g<#QC9&eP7N}_cP_^VA zG&}y0buyxMnA!J;6tz8Nujm=9Q$C659sM?@cR_#k`WOC-;Y0WDJKFfi1MlwZKH%B$ zA}ig_0{Dl@!B>>80(9FuG#i1+^A>ndwH>B1&z)||``u74uLS2Vz(+Q<4l&kn#~Zh- z;hd2@-F>Y3bmQfnOM8fLH|F?Z@$B>IA|p-&yyi>*S252bEZa21&7P+}T7tTbW z@LqT&?j;;ar0SpD)Vao^FsBneDRuuyN+J={DXX@WRH zZ@rTE9et3%jd2x(v#$04T;2MatvHX5>4_}-5PurGI>aCEV&mVuSI$PaNMl%ti$u^B zgp}z+Zyw{@%pN1EoPtP+uxm%pW$;03-}k~#^dKkRh=bK%xWBG9Zm0`z9s6$icKwHZ zTmM7+bN?ZJ$A5@_`MGRx$sGKIYz@>ckw(wR=z)5(P~(1;ntLuj>MxyFL_zTc3tXy}$ZPluqB5x={dqYNR zQQ7^)DNg4a=XGdp)*4&k!m>5aqFWM1%Ft#NJzTU(pYc#xk<(dTT6R6BA3$qfwQ9}% z*JDv%S<%WOXL8BIC51(n%4J2)HP=(Y+{Z!Ro!{%`qz14hWdD9e&vvTogPbzm&Ld{tRVddba=M=yo+ zR5B1_h`6bk8`IYmm)J|nZbsDg{{40%ZchL2jkuovAL=LbA;yva9({;v*I1V3%8$S}Re^lK6uni+J7EuV;k&l~-bUNb>OwQyUE+SR0lQZb_ zvpD@-b9BZzciu@dl@?cyfEV63y)cd|Egk)wfwl)y>nhik6|Lq6(#MhQ56xa} ztKdj^+{3n2bs z)ECkpjE(cY60%!5FvmtuDU#y6rbneS&n(w#r##E3Cv!Teq&La3rU{#m*vOvW;XH zpl{4h-CBQHWoglk1>BS$Me0$hVI+{>qu-aj-F8qn( zRuw%ox)nLs6awNur`y-9 z%etWzLVD>MOse0`e=lbLiUrud9$fR#dM+*5aA$6UVIGG`T2{V}D=DlX6>_8||G)oR z_*Al6lRk~k>D-KaM)yuqB0jl{1sRLDdoqRSv2V1CT;|r5miTx4`^b{GZ=_x5)kq)5 zT5MkBBuge2NXlMQII^2jlr@=4HZL;I(dADUcH}Ymd21eWl&lDxj2$V#R(7A=wytR2 z>O%kC=CnPuvS^NewodnW0#vRQw}9VN_vi;#%9+akg15J$5%_CF9QiEU;hifcKW_L} zg|rR75ieiMnVvwr_WT@f6LBsu#L{aUZ_9*bHqc1K!|rE zZZy9ChIj%mAAvuE_|bk<40EP~SN-K&K>R4~H(b6RPrYzGp1?nG#ShOSezY9YzJ^~o z)8Hk}6pnbXV#fZRx#)-IM&M74)F%L3<4oEc%2|%@Qi?Z`G#%nc+Y|1+9-nwaJb|By zGyLfnUdiu4yxK1X5hjNR7rpBXi(iLwM6D9v6;@8bfHR=X(oe%(mqCf z__#=(XmYHZU~*hUJoV#cpMuBhR*DWohv*QV7{UKWw6#jF)O#J`$5Da!%R-zQpB5HR z`LiOG{F#VX>ER*dFOF8?vkd~V?MEN-uZ>mW>k+TEw-#|~ zd|OyN<#81|4SK^Q2zWI64aSHJS zryAe#w37aDupFxMa;NCXTCK!iM!br*;ul26v$!Y^`}dLdQt+jhm3RU1Dj%!gi}v86 z^y?6>mh;#?(b12K;zh)(?JfOHux!Lz5U-9G%9nXibT|%(j#-FT@j&q#4=L~Dj>-SG zV0v<*r&N1@%zH!+Yn!TOo=}jR!-6zqT|UvCB7f= zDn31Lj>Nwk7Ek%RkVbHxL3}uVHvUS9zl?aby_E0GW+h$=KCkxU-oGnxlrA7%#RG*) zKTy(=#>DUYhZ1i=e0cfwXO#F%#E18b@2nD^JEojnA1d*sh*#n1|450W`qe+k3w2BD zTFPjVN)iKwJt66Vu|-R(+dNpTV`-An426$LeKB}1srD|%s<8pW3<)%(0$b*-o)gNY zO6ri;W!XbrnPCyUyro*C<#a=eH}zztk#z<1tg=gGf#E1 zhZ4jTkDM^~&IJpy=N5-D6+-~3Te?K_RwEZ;tLmCZm9sE=0oHQPy!_xBSqm15B)X{u zd{wxnaoJKV>B5>eG9s2XiggMk3JUVFL`bH07OCasqkSSRvPMUT@bzu!c?F|i%wAAj zv^XrvTiwtIypom^3n8`EQ1J}QVyIt6k}GRTK$Ic+%KW59Qm9?Z@K&qU#vc3^26iOm;81>HB{+yeC z=fZFxM*0^T4YbH2|Bn|YBizGGdd&ak2+UPW)uj| zA&2EfL3r#4ec=6;F!E=vMLAG-K--b8jF7@b*^9DAf{fauj8|%vv$%}VSC*Bx@M{P} zZhx&Cx;L5d#x|b?hjSV5&~hzzU~FvvfnPyexU?Dki}#^jRhSx? z765y5OY@le7ZTe8*AwT0;e<051w1yE-p1nR+uld%V)lYLp@xqgzhlc=QVm^HrDv|p zl4p(q7BB_h4<&$}l%5X86jyo{Dyv`OvY0ADIh6(hUl?+t8y)s-sFPnHRYWsj0&fxT zC#@64)B|CKj%^Pym8JBKs&N}r|9^G7{&(|_CAhKWjSb(Gmy`Fk%oiAu(?^EinATxU zkqbl>=grT)bCEnr%K7KrSuEx$yt&aMGoOaK<_0&6AYyB6^-{5+YN<+>;5T(kWyW<) zlH4CeAGJ^)EpxRQaL&fVZ`-rYN*_^X%P9Gu4r3U5TY?QGv2!L29L0AonwuN! zfNRp7c|~{REnFB(X4j-IT5!jLJMUVcrYrcRUZZXXY1cHWNpgpTzfZUyi}Ubw75Cvd z|B7@hMW`;N8aZ8Tb*t0960WJk{6X{1(&~^TFN4EcJ)UZHSG z53m0#`5`i?jimh56*9{Re@&?jzjA$Ox0)!2Ws8m)6Ur(-gwlg!@&9%G3OtP-wE=2a zWfc^L8MT2XY?&dehzT}p8OSfhtPn?G2zM}Gw3SsXs|kvZ3smuvAx^A;5t2MJXr1f9 zvNC9wluK5ae#Y1Sjj5i=`Dcor`g*cU%Z?n?Rn4Nkp;__$Ae%0M8h%%w)%b4k zhJ&bE0vDT^qPM06*yFT(isUkl-vS|4mBLLMw9NLwJkV6$LwfgNF%Y_0YZ2%@J8~$s;5JZH5@HZle@_!Qo#t;_IXygS_Ux)r4nH)W)WsjwM`0?&+n{tk?nsVityR?z5Tw=3H8hWhfUc{quFkaD zZMI;HY(s`&OkP#a6d92QiX}Mc#?rn~Ku%}k&7z#Ixv{3jS@7-o3Fh#>5IkkH@`PIr zU=IHy^pVTieajj=R$4HP!5GrR(Z!(8kVTY6FIb?wil~9-*GPYk)K|CEvuu>;BUd|; z-ca3KTh_F!uJZnHn7%4q*3d(1AvVC%Y)k`3@`ICqMTKGTdc2Jl)fTZ1&S_ZF2irOF zK0Mt3NVp9%98c{N7(97@!u^%~SdPAY6T+IuxwqLeIebP#w+=Rwn<;mBKa37q?jern zw#n)LFMq=AF5z$l+r*D)ljc9uCTgT-B7R~7?JPD+_BuXw3&PRY;Zr|WIUFDto+zu{ z!Yp#w_Zq_b@=*BP5rl>MP&jQe!sFvYD=zvQ>0iw3RgK}U*>d_a4c9zRpot7B4GcaDK$nLY>8@qZBQGi)6)85t?T4y`Jw#qEQ)}Qhh05;jRp-u+X8z8p-Cb+WpI)H#^?Ng(%q{Y=l~a`q`k4jA)^ZmfVEXQ}9^tdL0x8eI8>pnWA&rD|`1PG62ILKAWu zX({T0mN1xVQS>PoD`gGMio#5#)BkFIq9=ewld(#d(C4J3GzUj<7(8W={ox~tE~Uj; zutGI`S(O5BbxW<=8#b%gEoqQL_wu5LJ|BvMU<+Afg|H(&YEn_m)C!(eIJpMRj>$LT zdkL$otM>R-n(S{3cTZq9FS;rHgUJ`pWg780D{x)`Uv|MsY0TwhMMmt^G~ARTIxdRV zOSjK;I4<2jb*9Y`vcbt-^^WlBCCN^2^` z5e=EnKEQ)=XiJi~vBl>#`hH_vtLfj_;w!(j>lr#>&*Qo1_g_5q&U&AC@r><0v#--w ztGy`$-|9bZdZZOwipqVL%F8c4QuAQVeP+>fQ7pf7Q|f~?<>i;|Gq- zgEs?bS}Zo6ZIZtQ6NztxjLV2f=jbSRv?y`DmQT_}{s!M4NK0bpa3(3f4CPJIeR%rZ z$pGL#MGZT3>SFY#kxM4}utU#q>P*YIPsPiRBJvyyuyZX}9*y_}pFN?yr9i=Uqrkif@Wf{*j;rtqh<6^0izF=*{kv7=idv}(# z;1b@sdn)yb(nU8-z8%hvmu8yVKeMVW3+`XUr@ZuB`)BCSP>Q^tO8sKrz6wIL+) z{?B(*SO>LV@Xa^&%gs6U$Ms@{^^EPf2`y1JhJi-#tvUMahWrP=P{oxOBn|_gI;_-W zM)ro#U_~s2%V6)s+8yJ^vz(Ndm_C+Pg92p16brj*b+D-Ul?e%Ew>lUFzWFU!6Uydi z&ku>2;4C7>TA4h-lr_+Xl_l6`B(FI}&jbp{ke4Yt@%yjLP4EW|JmFrxDhmZK2%lZB zZvUpjsC~_lj%ymjmbKxnSMUXo3}sPoiWU_pM}CPBmC2?i%$u1072X;iGm@8{RD670 z1HY~P)E+qCE9U60KwuK;NXE4*cu&Bc<_)?Vf_D}H*)zE4@_+!s>4U=ZCJjg=L`?FO zlmb~2G{0TfuYhl3u)hGq*oqbW>gkl$A`p$z2(Qq#Z-WO+R{AJKbM7+#f2P)OG6 zZk56CfKbSHLsoG&FKq#()Oo?{)n3IsgAN;kSeo2QQ)G*&xUcvl3#06OJsx=U8f*j?G;;6jv zMMiW`_{6}5BwdR!291|un2`}L`@;tvykw$*877%VsjI|bR%waq zb5}QK$lH0KN6DyOTB+iZ(&%rQX9@iL;elUQAt$L}xm;AFhDjya4BaSXKR{erp-=^u zbI$yH=s+<_Xu}#Q4vD-Q?^j_^!b&RTYrH=kdeEDke99PjiAJ(EgAW8Av1&X!bmX+KNYJmMU8k}h`I0~gEph3wvmL@R$vz# zab9*Y;+mV?OG2y1@cRGnz!&U)a4BpxtisYjW^oE7QY)0j2yL079MLSu-xRWJsjZeb zV<}054kl}~NxwqiqJXb1AM$ivb8YqLty=Q?iZZs+TS)~h3r)jv8vUsB8XQ(-LGk|U z(p54Jr3d>1CN;9Tsrwhp)MDj^kMthaAKuYJD(JsS0Jemzo?&DWmi|@Z$e8^(%CsB~ zR5n4hMkG*2Oc z1fHGM=$%m4%&qpez}Q?#N|LY26J%ZBXjRR%Q0yx+-v|r4CVk8>x+Z;uwa5)n(x)_w z@}N~+Z=h#rX{>C7=C(kYZ)K{bc?4ro0k(1k@bLZ&&kwz)-1e`@D%T&Rmy!03f$y61 zG3`^*zaIW;-X9ryO8w3CPzZs8dlk-3Lrxy6=qtBa07;cXBlt!?m$lS4tLkUW>q_gh zX`dVP&uUnq4)}*G%pXN$!Er_IAyu%5z#ghNJB1LSz8Ji#>1vOt98ArorbBHnN2y^b zg5-%>4L5`F(Zmh?RArr~R+-%KMi@NMi?!hE9B^zH>Dmx{nEvJRRnCG%whXumhkB>- zM_xx8Wnx!TQJ>;#4QI;gC5z18pMzXUzmCqu4ZH~}*65;c?9F7nf80}&2 ztF-B?2UO@E#dw9{>T2W$srXUxHMafBM*P!*b4OU=c%=N0fg8OLcBuUSH_NP{coO3A&VefKJ(8U&E;CB@6#=Oql)J`BFP1QuDRHcXKQSqV1 z5k0rvYMr6VHEzt6^)<39K18bUu7o0_MRt|IJd5dy2FhF~*bzP*5msnLH7sb*sVu`X z-~r;A@}r{ur0vr6jg9w{_ZS8jocW>EQYs0RKzrMRMTb{TZ_xGts54PII!oc1py<$> zN{dD&&XMflG847e-Mln3ej$&wU`ew~o-RdNs9`Ph!<6QGE%NV}(#d~88Lw4!OTgAa zP-Ff`jY^T~i&S4l-4ck93Wg~x_h=(osFk^I_YqEr6!2*>d}ig4F_ssE9vACzaScL+ z10UU-R8#Z$rC7d*@spmKxdDgdtPmdQeB@!DujQuN?g+ly!58Hq+q`GE716JD9SeOj zhIR1F%X2#>OuhY=lh#u9y+twn-K`!^%S{_9qWFqC_@X@Cu4VTv!l|Zr7ZvGvoSI|L zVw19-dhD$Z7xTI}S?3hqM1tQNT3yKgM=I&a+3qS>C>G=`2qBO3@ao_t$3pZshzGfX z2qOO;StdrGhF%J*5IJdc`x0f|gI&;r{sAEnk&(8$9t&c8XauuTO&x7_&YQR3&Z6v4 z(){qbn2M$PR31hk$mN5%QJ06pl!<_*ohxN%7w0bOU zzM{ly(#Mq8Tv^tix$qENj1syy}UKMrE!!JZsAWPo-0v6+=UKX>vM^N;qASX9W3Mr84PHw#(tJmS5bSONha8m_AW6dTdbs;`ZQhr43P)wbzWW z;&#>Zk#a+RK}&#Vd`hOF+JeT_%3dT&8vUy6Q)9$n(^YutTyg=Sd}=%`&cfeUSvIqR&!UJ7&OMi@$>0I~Qb!P^jWhg+E$FFnwhMk!rd+ZvQ{v zSAA8kqPX2#EgQyYJ@pkmRNPMHyOG3EFQWwXA9V<=@a5huZdZDU`iF3MZFu3rye#4! zN=e1-3+Lh!F>{ONiot}@G*aBIcwmwW7JK=~&2tnL6}QtzURp_>1q^Znt zUMG)xlkx?nkr{DJ`nMJLpXaZ#6Mvb^(?<%umc@P>KLmbd4ySGl2*)jT!ngCQ|1LjV zxELQ&qPcs~LR7BuGj-xGZihCOY{0>YvHU2=A4#`J98#27q|7-8`u}z`nKUpxQhw2$teV0%LSql8DAl+&I=)>IcY zAjl%Zpd>{&r;ZB0oF2*LqSMtSQAo{(#~3x{HX* z_og^t4^vHz$T7xV1?ADG#W~Vpr)r_?G_VNPQvS0VR-k3{-3)`Hs-0pC4wEE_|A_BR zp%C-3oZ*l+0m6Tb?^M6{Ag4RWq|1?EKLhcdWLN&WKgYMc-~a6J9OlC}ba;b2jAn*4&td&kGo!#Upvfy=++TNU`MHjALwC7xTY22> z^7x+egd^n>PM0TMD4%HjND`REE`AVi5ZNh><}5dGMhe8T%iK9l{H$Pn?*7t&+V|Sd z<5S_?CgV0!+-_5Rk164ZX~Jn!;sw*hG+U-qd@iJ;IOk9ZrhL~p3zwCI7U0K$*+--bL#b^JDB5e zGIQW89ZOc!er^zlmPDJmFQov^jpw*4bl2~X+wXu@Mhl#@!n#S6oQ z=aiB)U59^N%+yp(nh@dTaR_0-T~=tP3Ywgg z;7imJS*`cU5jl+A8(FjZgPe;J9h1z&pQktqZ~<02Rf{{IK)V4o_lS?<*CqZNetGe+ zFFw|rE=o9CFG7+IcO7mqU663J9s({Gj&EM(sC8DjGEUh{>u_;i z7cazx4s0rN@dfNs0nV^>alDHOQ;VEzH_z>Ma@%;e&55sIXMZLIa+l4EJ0$R{&tm}b ztehMyq<_LU=bR+De<3*srNXDA56sz3=wXp%CVQq5T4yBV$DH~|_ck`M!ieXN6d%ri zrH5)?j+X7-%J94`#RtDEdZ_l9K9u?15#B z>}M{2Qr8&`h;=p>HQ;+uv#IIfm7d+2<&T!{(bR1%_*Ap_MHbLR?a%%b6DGJDGH_v{e#3^9!*3H_#T$Z{Hr+zf4Lqvf5eRwZnRel)A7M<-5cyG zKk$XL{|kxtuXqm!n`xNAD0c2=2%a+sru-lg?X_Fh^iMV5H1+A$_YlnGT=hQn3)-Or z7+KKgtEO8Jj$~hvgl#x|qK{)je`Fk=eOWzGJdGEv2{rK%Qz~$nbnLk)6*%4%C}dV0 z@m=EbA}$AeX3;Z?@c+!LXlc%_ZQ%Q|M~>{F!7=7z7Vw6o)68-727F_RuIrfN)I>O} z-6lHBPo5Hu0oQ=Gr)t{is@wRgsYj}A9jG9r_hjS*0x8)mc+=k`?w^DygGtPOODggc z{kSqB;q-WSGMxSaUA2|a-?5`~1tiQDF~&fiOEu?OvGakB-kmmrBJOJJameAFQ`$?VLHw_2fpYxnnlRJx}T80qt?_G@u^P z@qwME$L;Jtp2a@(>;HwXu%Gz>zH0wLuuXtDwIDjRJTld%71mGhO8k62pOeg9d5iBe zGv|(BVS<>l-kimk;mvmj<)GhI5TWc5JcOy$>?HK~M zk+OgRr!sxOB65#Wu*1ZrpW%CLoN0|@u!(?}`&Wure$j*cfEF+xK_}whGVMslt*39f zjTfiVvDK#kC1wAd*whOBy^(!;q{22SXE*)!?LyRQ#+n|GmM8W-FQxt-2O4s1a{Z^J zCa;9E@n(<9;85(53_G`s5{`BAeSgM@A>2|5;S2~?j`<(}n(M~}9?H8Jrk@@+hj~Tp z5!aPtz~P952FCrbVbF?Mj1nz@58{&WY&$RYh*5S8>p5JIxSg5)iHx21G0sC74+Tcd z5iAOG)+wd@({2r_IO66H;Q+*e8p?Wn%RT(*UozY05_eKUaj4mPdOd3Xj0&t~A7+R` z-~&Tq|E$0V@w(1SQlEx>XfgLVbeE(EoCPU#UJN_Q6la^U8TLF^`z1J)#?_e@W5k_9 z-G=Qc4iT3X*Qv*b=X{I{JOaSj-8w*Z!gR%X{x{Mg%y?3)Byi;xZ0PpDTX0?TfB2FZ( z`Xi;YTp|IB+z*qmn03Y}5 z$7zm3z0_X3R-dz>5pd=x-@IC3kt^DfS znCX<%o5dn541eywNThP5huig?+J-NW2WCpfmx#N2RL+`t=ENSVgY?=!s-QS7jfUVWWj&7R3{h=zcp>y*(?XBV9* zyzJJSF-f4WK8ka+a{efFVJtUEQf6H4yoSiqh$$~eth=>A zhl6bw^S4i(F)uv=W5a-cI%gFfz8giy;aiBFcJ;W8`_JRNGXtL#jq~$f*|mfdsbJH0 zhcVaQNROB&drPHEVPN^y#K~G3>ReJ5_bJgyreNMLW=`flroe2z6lVbC-dZ|=%O?sp zKh@8DKnXzJLBZ>9t`)ouy(N8v+a8HO0!aZezhR)DM zgZQ+0c@b7~Abp-Pg)(=qLtg zo?(iz9de#1e2YJ+<<1gd@4YPPe{|TveL-M6n}n07zQifPn>*5ervLereQ{0ylrjyu z?7$w&vyZJ{v09w#Da3LjWj^CRyk)jvIwNuMRFK}55qr>iJa|y)k4_jP6Y`?CX{pkpfQ#D^am(sY>hce^to;u?pT@2&SQBQ^>S;p9tkRw(=kdsTEt@W5Y=IheA-j9Ka zbsd5xms8M#6HAN-LA=CT*}Yo%jVNw5KR;54(+#P@4$1?rPuQZ2Gq@{-hfI0yv(EXt zPjonE%Z;;>$7lZoCs}Q_Z%&#mpx{3c-1Eobh$|ucf<)z?apGvL!s9l1kYJ4et0Yr! zgRWFJ<<`q>iT6#P-W{16ml5$`R$gLT+)ZoN{M-1IbEUOyYbF>rPAJtqxM@?|Vtz>+ zM`V7lK4*xAis_+D3@bALeh&}G_9&z7z+AW&h$#!>& z%bi-}o>JjX^SaY{_YE9GdB#$4z|)P)<<|~;BAGst?51RX03rr=`uAOYpo@1WO?e~R zI$7kfmV~t5Bi-D?0(%5UpvS}x`vZZClPqTUcXV%~_1t@ug?m>zw%c`*%hw8VX7{86 z({KixBXF?~#{|coc32B5rb#6~xsnlUdkGUzyY7Uv`ZQtC2LbimJmxS>x++f&;0WKLf*~c~ zx4y-8{}9HudGf;!Gp!pi<(MlUMoMU92QjxFQvsbJy)vqaiUjPSvm*EZkkTqF>wGl^PmM^=_3JS03L57bNzf^%PjYdG ziNfWjueR{C#GR(1ahRGW=}j)1o`uDDRatIy*XM8IIwRQD6k_b#>Rq8z#qn*^KS1{o zePNDmSTYS`eTxicvrjp!yWlBVPKx4Qu?wcFk}x&<&p71@qVdgUe6oPcAP7WjOUe3S zAufc2ajd+^|N4|$6E?>S)2-zRhj*OnHg;@hU26mLc4~;D&5Mi{vK=lb&U?i^6i0`1 z^O>d#lAyi4!dmS2)c65HsSZCyHGxT44oAzHX@8?71->i(UoZDvD!0g5<@YS2a*I*| z_+1<^x?D-RDpfo$*$RdVFAO5xm9k1%&%3HuA!wfbgLPiqy_0`XvP60mf`-V}PVQPu zH1P0b0t|8-<|5nsgYG%hd8MhIMbvSNQ(apb?&is>9A=6zSFVz?W0IlmD~beCNxfzI z(GaNQ$HdOi$G1=^Mdb!3bQ+`Sq?VODAgw%4(O%Jj<*wJw={_Acn>gNt@?^Hf4$hTj zC$pPj`UcA}Eg8z>P`td9OgCj;qC?|xLK5XRykm0A!rGJJ0zAq)!A0k%lBsmaY-ZeI zg3GjsK$NvC>+C`t&TKXn4nc6B3{ZnGR?;zS%9r!cr~DB21YWI%;m>EqCxNBc8;1{g zu=fJAg*XrJ@CB~F;(8rC^@uy-v^%oLt-~>XeCG#}DU&LlLFEmc8GP?C>Yk2Ud=J}j zZ);d?!mT!=j@J04D;9H3%)b~?E3lmmcT@V%j1_qMAOYu<*ZdW?sEUB4zQT7YbM6Xd zWtg|3eGh_ZE3ER^PG7;jP04#R*lX0!zslHpgu+iZ2vN9gy5aCFp`!Lf z!UtD44paJ}6NW3W=>~`W1z9S3rG*d)|tkrx@k?DSmdwDjJffV-Z*zJEbiW z_r0-G2EV|)C&Lg3wBVs=sSm&D8TgsefS=)S#{YBksu4ZoS>DJ>-spc+q=UGW8DvzXMdzz{_0Il5 zxp&-O(>qwheN*pXQ8%i0{z&2Q-kBKeor%HTnTXyo{Z_L3neJaDub*MOq!~+1wYIIl z7~Fra^x|I!0|#XEZ+Wzb%38ZZQAjj=6!yb5TPCe$6*AbkP4IydHEP zZ#uJ5_iG#|E+52s(2>XvI<8~w4#rl!uIOfr*{`8pTSV4^)8V=4hI@!xl)dv1@ee)cGaE%FM(Wc|pGu-=Nau6`2`D4A$v&yX%;`D1 zzdceDE%0{#Dy!Ad`&WoAGS5I3z*BNz7$}_eW~BBXl;sU%={zard`=VT?J6&cGWJ4B z`v*-Fy-!0#Q*^fJCf##kEQkdZ-UDXU`IKb({vdG_dCE=aOqoPsGYAuM0U>^puhbD` zOy>@nPT1bkp41$kD#S$yvYrd9$9jN8l4Rn9WWx2y5NwqoD?mg595TZKhj|jDA9hqY z_K3YmYh~!0>CDx$Hk_Wy;|TAmLK04DZ@MCRacbxiPPavxABz(}$8q^z0BX7i>PfEc- z<7WEs%gpu}O+ekl)N*}O8g{_C|NiB+=cPxJ2TPsE(vjg)_)ABFuW1u0Con0$J${6kUnOnDDiYZ?ue>N{YxlJhsV{H0ou}~L zcB{fc+qbT!@Y?nuTWfDxMPaH{9#`!zen8=0t;0`#^tO76Tq^_zp@2Y}Fr`&yZ-T1%Nq46d0ksR} zGryF*08^CO{h~ZIThS*zTm`twahd&4+mosYT`-%USdnDuSs1xflv<1mBVDASkD7aX(G4L7>{J@X9L zbAwk4^%CO^cNy|bkdZ zkS@bzkDx@>`dNJY!nDJY??UrbVDo~-_5 zUEhOE2y!*pf|QJU5|2dK2Bln$!|~FTC%Fu5sm6KfiuhfMnir6}78;}L>NBIU^524NLaQRSYJucIibhPvd8lT5`oN0~K z;uTxs>(K*k7FP6re`D}9$3YXR1-#CL~?cw7^u+^}=7(_L%la zx%}p715m-lrrltj^-=&9t61Epcbj|PmQ2tl6OICJP-Ta%sZ8I58ME+=^D^k1Ms$*% zm5aENai!t1;IiVv$6m^}Y#N?(5AKk;*)H5)!i58e*}@IOb0GJedI){T$dHABf>j{% zBpDn6<$oxeZG?VuEv}uip7NAnrhYw9NIk1ea<=y*^Yeco#ApOTR73-f?W81-0G6u> z#k@o92@4+^6UK^oRQfoUqQ2K{d+_yqb*eNwM9j9*)y{3`!mDTcSw zRZ#4;e}=bb@V5QnS8`3~UzbGLSc2hZlgx9O$tE4*bI4flx`o+(C7t`8Sn?9nofv+L zPahWnLkScHOm}>^=Uu(Io)ddS5SE}h#LtL}Ia%`DkZHE`=+Nauyy@!j%IQOyeADUS zF7T4UVc%5I{pAq2e<34IQx5vxCdt%pn89a`J7Jy?XZzFePR)tQT~8Q%4~tvB81l3k z{H+Fz?}8EoI6$7pxj}Mokn-Z4XKC&z)s``rz+ssR=Mj!62060oL-UEMWc6vHcbI#VGDKXF6uoI5 z$&Nb%!*hIQ6Y!uMGCU;h|A>|qMV6r{FLU?u1=foQr7?T`V4_P~6c_D^V?z90k4FSrdoFk1v`P`iyYE{CMfeOCqRp1U&`HI3 z;SW@!**r+SgrV>Lnb{}ApjOGjiC1Z>^ytoOStVgjWVSvmx9O*LYB zb6NHcZ1s4Gt*~@Vtod&HaXfl0s}woRTfYiHf#>TV%D#=Q)=|E0OUJyrSlAD;$5AjT zW_SHVBgQEeCT|!_N2Sgf$~p?Bc*r!p4zhpS{aQiW`Pboy>nRg}TT@Mmx;df5-jl<9 zMoN@noYMUQ>6kh!s}!-MqkffKicZjG|CxrUaMQN>hZJCU1K9gxO)p8=8W~vL90sg= zo79whS*#g&FqJAcuW|WT5Voi35Da2FNF&f?^LC!C+k?f;kYpFQNry`&!%P-ZNn!Gh zGM;swupKg;)V{@kqIvenvwNO>EHjReV`=7@Ok|*vi&5M>>*U$vxXQ~2*pk;ESS(Q-@l z+BF;YMOpej0a>&D*Hav8{ljyPLJtjiV62DO4|_e_IOa;H{Zg)Vzi>IR#SoL6C@UZ` z#UqwA_W0=j{+8*p?=_v1I=2ryXGpozir%{F!g<#TF(ng(&G!myK6kqnD47Hr_JLVr z_jKfzkHIQze}isQ!~Km$K*{N--u=U{y>RISqc9a;-EqtpL3usHt3`HtD;9rpvWb$h zL{`$NqXWY=ao;ce4n|OE%CkSsO_@YBpuP%=53VW|S*&(KZi;sT_EY7h+}GOrm}Y)N zT}tGZW9A9b{pNsqQ8eY3;s+g1*hZ)gZn2>KBe@27dj_?npLi zUY;HA?!M30X3veAw6;5rVZ+$%n>K9F5$B;>z?keW_}J6{ zNX%+&DPV!fJqh?|5$bo{vMM0Yudb!5Fc3E5OLr~3vQn`KDT_p8DO$QJZGK{$_Px_m zPBhTOGsndWi>7XV_8%dXx&$Un_GNL7T$^skFwEY9Yx}*O^}}iN-{KQ1v}v*WBvc>y za$n9k_z={(Y7*@oanas5wq`?m`#UJU`<7LHS$EOBbQSkYS|EZyl4fEz0C%8k0nta1)=6B`}!FfIh$ThQ%ow`M|-7Hi2O)`}i4Rx-U$=LG+wJAj9i0%7OBLA01<>XpQ_FXV? z)x(Lu(WZ%l&|&5SKk|7aVc+LqD+u_iGUIB^K-r|4I`hod*2lRS=6BZ$8uJTqpz(>4 zLExDr&L6M)*)X?oI88jTW#3z|IUF;Kd=CgWE;_)f`lkl$MbU}kXCP%k<9dNP?ld?Y zV(%lvs}D%99?IOfrW-{Gf9&0aeigQ7Z=&@cdDdtJzH_5$Zkh(40tlf$u072hmsbtX znf1rX4m9A$n9wsdH%)f&oDlDDB!DdlykoMWVh&&){W#s^5Xk0rFAwt>%zAN)gNl_9 zYa~|$*$qyH27-j1=?#QDC@(sTWv>PccYTaGHaUSYDJ6&494!bI+O z($g#TP$?Yc#VKZgJt3lX>%iywm2#!W{IU|SyZ#u09hRfMwaeB-#^8Ck<>;=xDJ9>R zqMEKedUk7KL9`Hi!7sfh>utALj<)|W@N*TufY-`}s|gfzJqh2zqTY`RviDe@ z>?n1!83zAOQ^CDmlfYXqKJ`8Br_nPr@ole3Q>`{r`43jrHrW@kV~Kpuap}y~%a0!C z&`?4Fw@wlk>6uW1whNKe^f+!60dqu#`a(T*)aiQaA{W4GcEIybL#+>i_oA%e-DWwa zw)R;2S)_MZj;q3eBETFMWepKc2A2!H^~Z&XgQf}xybELvC(gtKy?1RgIZ8W0zX?f~ z1bz3`OgAl}16X42BKPGA@Ojb6@B zyI+WYdY~gh=WFGV(bH!09=Or#H27))tj1VgZaepYvE#s%hhOv_xD0~vcx=nJ+BrkU zc;8gcnrVyH@J>T?pAU;ay)E*4Tm~~c4RzYpF7D5Nnpcy@6G!jCkScp1-`eQ zJ3?utFN!MyEYb+6`z}#u_wPKmy>Q*9xdWwJBa`)rsX)w*Irr$-m}hQ$ul9W47wf;c z-a6@1HpM91G^y)mU)RHXVx#d{J>Tj;%v#@C&bQXKBaMsISM@qnFxhJTGR{@LSL?+%}zBmJ1Mq@Ivm3sup6_yUsXYc~HY zPJREp<0g8x_#!JNiD@mus!mF_`|r1!2gKAMESO)x!dFAW#u9)C=T#=pch0j?QT?ky z3EW&vIve%`E3f@!*9TMjU;2=2kJlBRrdh|Eazs%tdaIALe}D*A$`Po5=%M+qk z_Q{V6Pg-Y9gPNpfeaxe>W~#g5BD#?{`Pk~Z)!##FoQfv63X+AMTKI4ZXBMxQuSMd!$hv(Axfh)fmdSZM8$v^`)pa&KM&(vO>-jngM>-sRdVP1&Vm z_5iRXS_9Lk2_obmu?t`2o9s+a3Q4s|t8$>#!=I0_H1x|5c<@!?!+$_)q;t}&Uz!|F z8ZzgiOce=S9ajiN{A(8hnO%Gw{M94& z8e3$f%91-gQw;_365C$Y;d?2;@fyWg}#^=~xBEUM9cS#v$9*>;<6-?b~@@PFXZ zZob`WO-P(dJ+44Q4^D_X$8`UdfQPmnD4e3SZ+kJ}+MUDsnt1+%hv)4Z^n0 z8#N)Dh%$%2hj+K|c=sd8_7UE_%q54t8)e9ztTFqeJ4KB;!kPSDHdtJ6$V-w2ge4l* zeG2}o+wJ#(@kY51HJw-qry>pPn}?_B1(2`4+bbAr9d<*^+AgypdZQjhDqhUIu4{*L z*RKuM>7B>wv|!i3FBQl}@RPBD@a>VV|hI)RfuQ<@`0E;gn+g@nAqB@Y^exV2sO z5^kqni1+Vs_9Zg25Odh&5@HjNre$bc*Xg=9$L!u5z4d8{Ei~?Yrl7#K^NFt40z1F6 z`=03T&C&j+I-kk1P7AQ9Myu6kzbD2zBQQNhZ!Y1y`2vO$ieB3#Xiz+l;uGU|yF1G3 zj;?z#YX6%163lvi_HjN6ijCcR9JsjG*`3IVVzST7xnGpnCgZMMFO`=YxM#jdoS(SiJ`U!iSkynj zUtS{zq7m5o^kw_z=nvwBTq9f@4rle~^{?#H3K}HYUb*Ohi_~F(9?^POoJ}j~93wOQ9yy*}`aIBy##G?(uYeXnsrH~aEm+hZuDn^qlwDAe z>|1NZ;8z?fipoDb*mQiQ-YrjO{>OBQi~k|mSHo2q=BnBvLF+V2^*_x`C^$KQO&rlD z{fh#^-350$3yK4aZFf!McG~>@mmJR!1KQSbsZ?LE!}&!ucX;kV=|$?FxsuX9Is^)x zO8<;k`ln@^UjO;8`G~!e5WV_U$($r4x*|bP9byzlWOo{y!9`xVsrBrX;$GA467H}alRS@+$s2S+ z+^-p50+Mdqy0&ZeS+W70O6O)6>s0?#9Xtfzqk*U|Oyg|Fheh))tJ#0V6`5(o-Vi$< z(c{ujpQSyvNBdT6k1K+lJNY7kyPoE&pob@O_YD{Id`^Zb;v&X^X{(ANSS)YVt%siA z6`#@c+hN;phh5vg&+)+_@9ncP$1YEnze8(Gz3#TpJ1qs-!CgwOrvEaxThQyZ4+{s*olWPug&2^>;a_dr9KGW^ z5yGV1`LTL!;suReh;a$RI?dr}MMCVemza5)E}nClm@7GoPiC7>vl3_IxecwS9xH4b z7UI+Y4c>w~V4b%6k9PiC>U&>0R=)1QsfY1e?|3c|j)qHy?S9T&69w1%-t9_8-DYX^ z3CUbfsuM(KZ<8=G$=A8}c^*Eq)PC}()?_~}CEBB5(F7VQhHVvS=}zv6U`ySF!}=ZO z2!*`tkm%8lGK7}(>|CiPMT|fVZ6gJEs$lj z-b(ha83rM~)67Eh4q8#{av3{KEaywf&PT2}qqn;vQ1WWHDasG1V)Yrc@l+H?`USGz z!vh<-g{!*EpQUY{G@~)n$_l z%+t!JO}iOiWNzua%yPNh$1HrVR;YBirg3-B{N5)p+xu6`ON+gl*lvx`dTWf3EKHb9 zZdef!to&!i8!}^rX>!ab5}GX}Anh~Nr-QlpSV6Zg%kGLPa>b%;pp_ms2T*uE28ejJ z+>B2)v2_>HgtYE7UIc>v!P133m;i9we1y=cdyvoxv_jLs3+v%Pk{=gzeLz_2%8%*0 zqS7Erh2w2GSy*FoIHK3yFC^2Rt7dal_8A0)QE$f+Z-GY!_smszRdhx1+09JY6P|?$ z(~A6$LGN(3Dav`M@XE>)ZejeuFOZ!Vj2RjXqK|hA-!%umEV&S+f9^uQG55JNp(Ob` z>+Gdl5<4?Y{;M|sRoC{#+==rF&q);%QVmAa6IX3dApW=9AA|Aw=i0Ws>!9Wew^igD zd+%eP@InEfAJ=ySOFY11KIllpJ`LZ)I^V79duyb$E!lrY7};m+eC}zXJKxy3gkCAn zxghPuLM+m>@~W)^Rh-~{9jv0J;CcY4f3D<|-t^#A+k;4anA;OfG(B+D_5fnuH6lXrh$e<4cnf>Y%i*G;^TA48CL-a`O;BKo9`jHtw1O}7}e z5#y(8ldkL5_4fIe+2eHY5~JC<HZ)I2I0Fo$E4jBR`QX~ zEJlHN(sha6_zdo5+a1oI6n1Xq_0N@>^j*2eT4;K>auE9cx{{J{LPYOxS>H^SyCuq& zn5<1a9dDX`)ixb%`4_G+*cSTs`I)B6EA>uUb&w&<9tRaEL4fLo?4ta*%;$RhBy93x zIj>0XdXZs#_JC9&#H>q1>wvnay!mmfwT!f=*kp%{$A#{ah% zP&`w|Ux4M>!pGnJG_$RS=DD`GTQCaO2|90VY**>3*4tt-Z2%^@^A)M@FVgNdb$UBd2A*Ow781Y0ImWeV@90Ecdzaau-p#)C0Oc=`<)TlHre2(1Zy}2PF_C zqM_LkPR8}UDaplWWxpWx?U&L~fA$;FC;aN)No`#jLR;h~%(GnQxplp6wv_hsH2zqH zaNsn0GaFbMm(v5>=?)=#-|OJJY zB=D*2(~!X~o-a(h^!O@X&nFgWbGy>CVuVvHFD~$ieyD3|#5yhZ{#+u?8C<=*_%gZ0 zY!lB1l~Cp9g}SwTx67EAdo_EfwE8oN+cc#2CzcQCyX?F+*O0~>St;|@zdE0x=$tcX zH|<^x%_F1}Fuh96?J@7dzTrUNWjyl`l^CfV_=;W6ZWg}VE*|YeuH3s){zS3bd zRSwxIhg?tofcy7zKp<9^?z@ICzn7c+nf$(H^h0Wb(X@ETb~iH3HO4oPC$CT>4 z+gU-0v$b<#M|`xmuirZ{@`<%;o{H+lZa`%nDJ1ALECPEIoVA2LSF*3P+ctBkv^q1s zAS+;hW3YUxao!%;7_Qh(B~V+C)6>ZhCpGVCOf!e@itEWrt~ppcmpqs%OJcI1>- zqbE(b=SN{qM0oF(t>>gEdkkhFqDatBs<>-+OhtYKCKs;|>CKNwo74fX)@=qct#}fa zsm0{~_>B1Uq;5gGVPk6AmbN(0v}x-e^Xx5tb^Gq2c)q&FJoXZYc|LtNath9zP{cc$@}_(nAKFHMjpRHyr8v%eQL5}upJz9ohQ(A;6ZVa z89F_f-9tNT61#Qfw~1ykvMsSFLcf^vw02@qqqA^nLT&d(t|LOf;kpRjaaJqTKAs_X zH^*#D>`2sgZRo^yfJa)9H9Lo)j*p0EYdTw{G{FvgvmN#aSn?pk+Wjp10m*J*Y0a7I zJ5y0CrCTZeFW^k)h+c~LXvJM~VEZ8E`&c1E7x{AZq!e?0GyF=^`j8bPd|Nfc=lSga1^Dh`RV7kT?%g{e}J*E&tbC4MB4JQT=jW-syyBpJ<+t|G^>cACY zuWMTjC;YVk8FAYkG8yPRQr`uMV1dZeFlbvk==vqc?Fa%QxL~--H)4YOs}zA{AQSDo zfHvnngHfDgvY!XLHGC(N$6zZPw3Xr2iQESD)db9*L81)ujm{&(aJ_Y z<<-eyLAwn z#MpDzH-r04WZ50#zxQ{;iQb6L-%(wegSJf6mBV?0b#YS$q5F=!!DzA#+H6Rg$K4l9 zN=?d0opn=E+yOKH!9Kg)ADEtGF`c39hA#}6QU-0Q$bC2WFTvdC&y3j4Ps4F8RM{pB zGEtt5To?(uyQS4%NCgUf%AQo1&J%eZ%<6#6IA}AX$ObMi1i;kPS=J=O0TBR9GyC@+ zFvAECnEq^1sn$4#b>zO;SxrEAA6T(Sz5V?w&{@ix=n zzqI`w3Ab@K1QRj^acUs3IokA>FKvH8ijA8XOzGIlD&k^bPi}f&DqrNQFhjil(w@p( z36a(a=Uq>lTi?IYS0Gv)#eN(ngOg>f#f}^&b}IO@jI@l4K&}Jj^B@=1%y5<_7Cbp^ z$IKZ{qh$3L`*w*18;iwFM*nL@D4^ia)s-dsUvWPAqhX9e&ufOf#N2Kr?dgcU30FOr0h(8q zH1PZ0Jq*^U6);(7`F!I+WADCDPMOYUz^gn8+qSb)SmtKEW<31)0-!2Xh>1Nr8I!!Ovqha28N3?SCaq5TyO-zeJj16z zd{Ye`PlETrRZq$KdF#3V)84zsHFaeT!}}a^g##uC0R`E8KhPnby{oH+SWQq1usLVYH!-wsaor$VnwvxCEwcT zB#7-iedl@J@ArNGJki71*R}Uv`?A(vd+l|m8qPrM*bv1@ z(!j5N*Nr&(bI~?8-Ft58pWPHaZcPTFL26MJz$cPqB${a`@t#i21e)u-|5b$Vf33eu zl;BR47GDOva1(YWZ@NP;chazyK^H!bg|li^QAXgtnM4B7{N`QIB$AWO6$I6*0nNqn zU^kar1{!V5PMB#QFexsa67w)fSY=j@40I6fmxehUssQl1r=z676!;XlC;GOWyJ-A9j62Zdr$6BOl?3F!PSq~o2F?#a-=0~ z)r%J(}|ZlJMug7xn)f&ei2(tlwe?nb)SEO?b)UjIO-zXta#O2(ZGt}(eIYL;yEe#rh=w{ z7;7)xU<)%rBF(EVK&m7V4WPzX9Ia_vJH)TGs`AAJ2dn}*{n+Dm)-)W4<@*C5-v`xE zJT8O;EE}M1eFs}eA!hvy%?0*Lx!gha(s79}j)UeFG=*`<;J~Gm0@E#)7YQ;)^u{-Waot`TX@eQP?FhdV*>l=1}!cxFMN%$3w8Zaz3{FIdD za~$lPsL^L@JqCLAiF(c`P982gIfk`f^#%d#H}|q5ubZ=U7&FD=*3!U(|11J!qF=G$ zt1h`=R(;ShFwFALm)D}76(MjwYzDo8tN6~m#FJJ{OsiStDqwE`OY1HM?h)g*qrsGBEWdQ&o$PkC%C z*_I-|`&xrIorv2RrX0Ll@4NIS@=?RORstNW;=?J(UxiXDddXu;_ zk}nphsR{16`Mz6Tfegs9*1kmHQBq_U6}_eCg5x@M5iG%Qxl*kz((Zd`)pq1=)u#G5 z&-sefMF4R$_A8%}e&%vM6+j8ro*99LU;?~xj*#f8?GpGMbI%iTHoejz^g%-P;hvTJ z!6;85nxNiVAYQmon>i#>@-hm8t-_GlRb0BRM{90Qk zl{nmt3qN~cx*hevJnEsz9;uG|9wKazVyg~XV@#GqYoJYIS_3<0__kZFLidoN8P>-$2A^4_C(x-6+DcYQNS_T2_?w+jl36M!`a3hzUQ9ohOnWamiF!FMklxpnIJ zUg27}Dvj{;-`hNLAmacs7)L|nK8@Zy%{cdFc$ z$hrBxw3MS$N9%Hexu@_o?GRiXXiE&xB`^4DOe6VM(vm>MYf7rH?I3s9l-hsZ(e%zI zWu1qsqw{$u>)*j#)5eWY9CTkJZ10HP z`YJ4ix9SN`T!xcGf)JlVEuhBcec;_=d(R)ac}lRBIn9Ap>NX&UV(oIobx`W`L^5$4 z+!UjN4-^fUuJ79egA>#=2fgWi-sz7&j zYV$%6NMGaffVXMwJRp|kb6IW+p`H5iJDY^zN!PdW1CxOCXuFCcIB<`@tH*Q5et(EX6Tyh(|rZ?|{-f_?7n@5Ur54%e-N40CZ(0kuGL%NOEsG!ZdNP_37gx zfhJB&t(zLOvyBMk98k{DEtD~5Q*aXPq>nfc0rn-fAabh=ap5|969LC@zc|9gaw6Of z3W2llII%z)KkI;!Il^`};&7rk>r01PaZU5^O`U#gK6hsmn2wS_ixn|V@Nq=dmphwy zOZPn-1*#?r=eH{r#-3P}TLjo;@Cd=>Kdlp~uWyUjz@fjYeNI%D8%mL&79Z5_jrs+M zCqOM?)ISdOb5V*XYVkn*LL8Xlh84Q|L3~02(RQ#*31x)079JTqR(SOAsNjLy1XL3| z9q@ERpAAz2NUgi%H`ecvv?(~lI z(^{=WtM$YCHKPPltrI$CiyA?9;X0$2FC?%`>^nE$j_*3)vWtwWBhhn+R3o&KUo=TZ zJ*uJ_*ed}fRR^Y%5ZSIk?LbUhK(~$}1KZ)CoR%v?X|alOV->ApX)a0Ob61k8mxcRl zN%yR8E`O7hN(UVFY^RI5jOG3?2?c~c*j}*vnACZ!fKaDI|}-69gSxH~?Wc2yEJEhHMA9y zhdW3_YLQ(?bR2AiMZ=wk2x&Wi8N>tMkCXWM+EcL(FWkhKlX5aie21gvyoWeaQcI}Z zIErWu@IfG`2niO3#PFQ8RKX0r;=o#5MmJ!srDZg)V74KY)HE_%y+2sJ9QyqXJV-!; zKzC%e;VGAhj<^A~QzG0XgB(@3zhoIFj#MnstSHVGT4e?@?=X@MIg)qXkx5BIwIhyf z>r8u8QNSrRk$JvCE3ZY-$Uy>ib@fVq>12|(;((ac3Y?9M1H?D;i~Yfb2&5cz2&}NQ z_g{C^6$g^x6X5u-#OJlTA6DPE`f^)_KHN{zca!+q(Q?WWCS6?|4D#zpWXOi=#bmfY zTxC3Qk=>EP*3`KpCHpTpvIZP=T#+^0uWbWy$kFm6$WHhmPy+DS5{M1-bT;Di?5;e` z{@W(_ZV9h|STnx0rv2q;`_6W)2N6*6gbkFT>cVJHf-gzAusGJywUT4yw*ZI4v?)az z1*_KznBr|sY5IHu+8z62f+51uwU}ds5y%G?Y$dK zmbHVpt>v0yXNNQX4(wWP$a-&%#`8cw_>0i(Y;^xsh`uW8y*3)1a@i4>}E?&`4S?3k@a35 zjqE?{2;_|B{S=~yWW85Lqj?7%f$Ln+{e2L9R@QrNG&%*Y&z*5a^Y%dWu&np$Xmra5 zqb2w6{B_A-;*J^x&3gx;ugiLG+|RoS_xWF12xLD9^H7+8_gKf3x3ch^7Oc;3s{LnJ z8;?fX=XwtF50b+&k_>v)uu+Rf|0M zXWX+^Ir6zWoloA5YZ!3|!Ev3D^24}mv{@0HU3l1GU+?Xq^>$Zo08py&+=WT0 zL4H`^Lisj%dsw~Qjopi%tE&qEQ(;&JM)_{@_JE5x9dDlhaMOmc(NK^`0uWXA?#Chj zXlRGG2fpXBt_aSdLPtYY-X7b$-MiOKjQ{BUsm@TCPZ@BJBFh0CrS(PKz66Y9Z7wqU z0@u4UL{JuF2@VV5jYB1pajh{R`B)S5Dg-phK~5&iCAxD_S?;dn4}!yzEiqxa@X7F! zi5zX8e|kt*(Bd7}%7OuP#?qz^U!utuNzY$9fweuaX5b9RA-$Bq z!q|U0tWr<}X$UEh9M$vErlfmckfr&gYn9=6QILCq%5j1hxWeGO=MkRdqg3+{jDX~w zBiNAJc>^{FfW=d2=u=j=Tg+I~0Lz82tBP9L!<+pQ&(&UQm@ctwoMZ!8nn6U`?aW9=>~JcrKRB5yR*LY*ZO1tD`h ztx&%W?oCiXs0>>_V3_&Tgl?HMU{kkI%KO@(_*ztQDX{I^a}6G8i{S*2udZ3v|4&Ez zV_Zqh)%Gf`pGdFd$ukfqu=;~VSXX=(s#y}=hev}Zj4;Ej$3p;53 z<5Yl0UGBaa0x<@ZC{kAn-Um3mFwlo1x-e1&V#5~Z zs#C~IkV7BR0e`I_FV%VTBlv8CHkZm-p2T`((IQkO? z<~(%(V=wodcP5B?un+2zqc-mz(9ax=N5~DW0e;irxZ_Z;^WmW8g5lO;p>k&9@vI|F z!%%>9^HAB85$n6<*Z^aJv(o92D_5PDfky@LF`EjZ9vQBroEY5rjjz;wo&6RY5BxNBtl~v;6AtlxA>b zmEO_^{~a9KDJ_y`=(6dOyddz^k2?$^#;1Kt{EFoCZq+3c!dl70AliG;ci{Z_Nbs)l zI{d1r{m;IVTO-XcAmaQ;H(daISyXWDA&xvUulw%1y^j4J?s6#|9*qrd&K`-qOY){5 z$a-bYt(y<6c*bvN=ocOrNw1D5ua0Qf83^lncFGTTJ#$)0o*azc`68EuYcL{zW%UK= zI}XJx5g5psNu01M%P+)I-Vt8hyn9)j9GbEVx&e_oLzGSkq+kkJqMP7BOHNNvf&J!X z6SZKo`HPAAo;!KJjO$a5EdGn5`suE+{Q_X|E&E~nMHE~BbV?A|SA#hnz0*#Xw5LX( zX5GE7my+Bw_fnT~asAKSTV3w1d}l-!WDbzYip@Q-TuI`YtW6`@;F5qOt+}M-1&6d} zMA-vPd4y0qnC&Z>g&cvog%!_#3!qI zU|MsFvX_B%vc}~jR(U}{owcmsKUqRO$0R{Bu>Ht$6r9+Ja*TG>7y<#t+!I3q^q0@K8agC){ zKs6MLp-}nqtdB1;S6s7taaz@sE3PZ9S8#me$Jfi3E4Sk$@mTrY8uY%MF*t8EUBRG( zcHzG!JY)4iAK<^HtMFG9^dbIh8kI+39bA%o%OT}}W!o;0DjX08fE?G~wJJzEFG2>H zY%5J~$K`4w&MQ|lK|x#9%^5&H-v@PETyte1 zuBLIy1*i3U(}k=_m@QCEx!}5za{=I#@5_3|+3v|$*2zR;4O-%}pHr+w=Lk$cSxB+-{W5p0t#9s-lBSSnl6veJFdQ<>(vn;!aLM-JnVv^Nr$$Hh;9)g zOv4{;T0b>h`SisjQl?)cHUT8(^`VMQr#`~EalH|nL4)ihV-v8qVl%78MZ`0-iX|T^ z5pjIVp-(`3!N`|q5<;=d#sS8lhi217L-)nSSB4rlUR>GCVvxZYNOGY724is~oIY=5 z?q@NUdp45lO(LgFK^DV0#vl`YP z1`L+<#2p^!KiDI^gl9^xaT(zKV9)`n7IE^4g2Ue=9aC!69D-yiu~YtPIE@o`gnZZD z84Vw(0C!W!cXs>srflrChJ4e&fwwW_xP_U%NCdV_4LgUjzQEbE!Hq7}!bVWr!&- zgmL)sz_SUSPv8Nm9@?(Nc03LXr56lD#ob$r&!gj-^N|OY2PR8>hyGCxZH)7xCc$1$ z@rdt!eziL%dT5Pmo(m{kOg)V=@*mqvM3 zk+k`)viYuNyMy4Kg;?0BB~Y{W5fo0^)OE6>>#m?t`x%J;RfYcPSptz})=z*Md1D+Y z_r|9wvo!ItPzBi^2BIFJ^&$V*Sh7C^!J2LGzT4Iv8V6fF6#4<#LZdR?#t_IVBsRL| zi_1dveg0(*Yw`&f2*e&GmIWzS9bY`loXJse zhl0H%L=tOp*4M+G*Ro-KR6czxJeQh5`N4OBj9NmkMOwF2TKJHV+bb$9=MQkO1ZGT{Rx*7%Z`KG) z=v=%IO*>|{e;KUScM&ki0TO7oXP1NfjWPsRE7?FwEss+*e+pis)bv!z3 z7E4*WdSIiI%)3o_!Y#J8feOe8w&Q*nNybDU_X)0Km?e3gJdV0yV^;=Zq{i^e86|FXVvA8--6CVqlvr+2>n#x6G z8au-h*cT8+?Ks$e*x?#PE{&N4tw5co(Q1XvUw7uO$IJnK5ohHo$E$jfA-j|0qmv}% z9=oWygOWS$s&J7!Gq0EfxAKf6&kja6b7>>VbvZb!!*JN4OVbq9ihvb?vg~F;mtPAT z4JZ*#(Lk({&()WUwB_OiD$}ce5@qi2;~M=qt$tyC_NE?tNss;2o{k0FqM~c4RbyPh zA+@3=tvG^De2h^HpGBbbl)DimKBXHo=`|YJ98t#{v3wHoK8}81Etoq926wmNU{Fg_ zjqLLNfJ*r%?)9Rd5IR#OQnziFsnZV2)SL=uUxEx1QnP=-SgR7wo;d7^Gdf3oszvH! zkPlWC;Q5#jwaM0A133|-WWM>~OgRhEO%b}_vgx`^Y&yoqmNT6R(uux&5Z;^T*>qs) zam*4j<=R&GK7)>j)S}Oky83I(PnW9f8(&+V0ZNqRnNOk6T|_|jV_1%(4WFk@>q*^3cq}LYO$i8*h0mwlPRc~YIR
    F2p`nj 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 J_PW&T{{beUoCN>? literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/512+512/user1.1024.new.2.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/512+512/user1.1024.new.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..e0c6850e69fe0098303d409dfc9f84a7cea6eda6 GIT binary patch literal 428980 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%0A%RoUs8#w*7TlX7bU}@o{$hy(nk6b3&hKCn< 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%0A%Uxd$g!ypFV_|pr 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

    N{r^8D4lA+3JkN7^huLVn;6 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≠rf>fUnzWz@J+(E3G;iA zZs$+JTZOj^b3DcMKM>}J6kYzUFuyzK@`l3Ag!6>k3l|9UdxdU?<2B9$g$E1s6Nauc zMwp*3booqSe$US3i-ea5FB85<_)_8Pgl`buD14Xj1Hz98^TT(Zo)?8*7k*3lec=y< z`N2H5^OG>gtz4cZj8C4`$(sxFJ9)0(Rk&EVukgXbhYIrpdv0f(@DyQ=f4L4nz~_9b z@R`DA3*(VDO5i@58-|kV#TQ`^Ht^oyO;YzcKy;_($Wrz<5Ps2>T?M{n)hg47ic;3*hF)uY5cqf>B*VO0u4A+&A zzXGo{{ua#jBb0v+X5TgWC-B|I5&RDrb4}J`#$12IzH92|Vt>w<>#ANb<{HpfjkyMj zeb>})i~U{WeDH_HUBRCkbIgZ**VONY{d?m9;N8Z9z-d$%>I}xtzH9PO>|B>Z=GrBG zLYd6oR z2R_=Eb)D;LC@%nWO%0jrh^HEN1y46-y`O8$^;|W^toMtIxfX1(G1qOKYs@*D7a6mz zbBzt-ngU*Jd?NS{#%u$wH=YT;-I!~~?lorpe#n^h_)o^Hug@6Y4*rYrU0|-wVZ8T( zxt@p2F{rnVp9Q~fybb&>W7gfTjahepFy>ej`_gIWJ#b@Vt`Tc(%=x7I7;{ZoCu7#* zZpN&a{31H-FcLX11ydRirlBwSXe4KF+c${%D_#|VlC!1wF8a&r{EV#y) zYt0rJvo0<+o(4YGcm|mL?Toh^ywaF;bhR z0Q{5jKfxL3`=$INaJDhWvYHrkjawUIu9eF-=2+JL#u?zg#%b`O#;o`J-WBcVgO4`e z7d*a}PHFJ*}Ukc{BC)#BFe%YAgU~d?&1;1mw9{dkuj*0!- z_(t#-#;A zxWDmdV6L~K{0lJq;mK?Rjx^@_)8mXeZ<77+)M)@d!I*8pOym8)6~H)DS=YB1 zv#xJ5J`en|F~`l`FuorAjxpB;{==B>L*SY$+GO4R#+Y^VN8=q}u3w?f```w~{{%NO zW_@jL{3*D#G1m*SU!7rDk2@KE1?D_q$~m^y-}ndc5M!8IFEb0aZ51g4^z&u zwduxOOUOQR%6o&WjQfG-8xH`p&zw43UwF1L>-TxaTqk(3G1nblWqbnodSi~i-D1pj zh<6%uy&?O?X@3=XlkpnxpN-doUopN8{Ejil+}H=su(yG~GQJ)By)nn%b{pRV=9)3; zvwr6o-w)>d8Yq7l+|rnJo&DaFb1aU1-Q?}yKE@npJJ6VG8xJ+!4Q5|A^;xHnHs;*+ zQO3F83C4}VQ;qimPdDbA*mC0z;40&M@OWy=%-hkslg!Jnd8C2f<$%b8PK<<43`}jXAGBjs8-e?+ajlWS#sfcrWAE!7YtH z1h+S4o#wo2>PIL$U5zuq{GL1I+2DT0{P^C%#vC6TV%#2lgz>)MV~jagHpZCmCz)j2 z7tH=}+8+d-WjqJW{&31Uu2o}P172jj2)x+%GVr;^obP{;G3Q0EG~NJae>iP&zW;h- zj!oTcyajxZG3(-^#+>{Al<{`(bH*H}dcl}=^i5-~>11Cw(>~Xza=tpbJ9v^Y z*Icvjn)3eO*~Y`bRmLO1^Nl$l`*dU0*Rzc)z~>py1G68SHu+_|%Z)jH#lCCGxrX%y z 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libcrypto.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libcrypto.a new file mode 100755 index 0000000000000000000000000000000000000000..1c3feaba433511a6c2b7269a4ffa52274a914955 GIT binary patch literal 135458 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%0DQ6Mpe}+JpMMQa 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 U;Ij&jMEgje@e0}v7TLe&nZ4G@BtfCy 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

    jBK=QmJ_EVwCT=;&FKc)7TtXQIGy1B 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 Ldq$K3?g{w6MXtP&`3Ol+I;Jfm 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 X%eB~6gSQ*J%i!I_X9sQgh{69KnX;PA literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libgcc.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libgcc.a new file mode 100644 index 0000000000000000000000000000000000000000..121b28d4ab42134390fe140c5aaeeb4602e83b3e GIT binary patch literal 603000 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 TCleEy# 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�h1d^ZG&%J}<6(}u7EC_I@rjP3we9~GrJ~J3 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≪D;5= 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 z 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 KD#*l%z5fdXSfS3YB_VxE}*wQoZqdMEV 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

  1. ?LAU~@kd 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 z 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�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%0Dw6p``KX6}}kC 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libpp.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libpp.a new file mode 100755 index 0000000000000000000000000000000000000000..f67aa22ef6c9486b7124770717406f5b0443a4e8 GIT binary patch literal 237994 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 JbNGKU{}pO+ihTe8 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libssl.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libssl.a new file mode 100755 index 0000000000000000000000000000000000000000..6ff625bf6a023f43ac03f5e162fab9ba2778ed79 GIT binary patch literal 275704 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 a#@)^*yyMdJ@QzF4@QzF4&CY+DB#<$Xm;}Ko z(;_mCz1NxXhq1InZzDrnXD+=%tz+#|+a~xk;KV6XIz>jOXsJIf+Gwf8k?WrKUHkja zSvdjC+&jI`Gjr#Avi5q{yT1Lc|Fzd%d+(EIb!+eHwb$fb5g9FsE8|yRT~QIAm54;* zCdxiWB9-y0mTO>b*kd-Lkv z)y=Edwy(a)>Dbu3s&l=G?7OwEzkOY^=r|Hw)85|OU)SB=u7;c2dt3Y3n>)H%`_^WkH!7;Xx4E~yr>k{!dph6DOiyq3>h`|A=HAx+ z_U!XbNq@Ixa!_|OyRBxmTlC6!1zOKPCgSm{uBt?6c2$+%q%C=$o12>Fx-J^l7uWf; zlLS~X4w03s2x3Q-hvEo;4=*W(BoW7n; zzv0oct!BiN4CaVCL(~{5we8EnqM?J&wZ3!P z(boe*&wJ5-@@m5FYiy?%0?$7bea>@VVW1`){fU=)xHRA%mo~iAd9Co+ z>62f(>@%C+3x}i6dNuj6qCo9I?;~Z&SfTqo)gtl!+4tP=t-SJcYVvEJ_S~P4d_8c< z@NaiMb4Q^=x*_5I$Y<*YI))zis-n>$@3mlQ0NMBlM%0AM^XmrIxPQ+;IIw^5k=9pl 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 O4PTbU*&Fyk;Qt4h^2?h5 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libwps.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libwps.a new file mode 100755 index 0000000000000000000000000000000000000000..9a7815faec19873143fed157aa0eadab5bcd4032 GIT binary patch literal 322676 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 Lnq{wV1rCZ9}@E7yRxptlVtUY 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%0Do(|6sQ4_Hvitg-9_T|%{GRNpW7nULAAkt%?dy;I zt}>44KO~mq^beMphK;`s`q8bI4Lf>+xf!gN2mdpj(3u$X?F_GRIlAnOui;-)^M7D` zaZ%iJ0s6%S&-(HU^7_TC?hUJlRPtUB#Lm_dEM-ID-*;npaBy&&2tp_^xN9*kf zA{Y8wUFKlYg}$5Yy(K}gf0iXjYTY#0OuT<}c^N_}{wZd9wgyr2H_UXQkmq{$y@Y-Ll@WIv7;9rZ;TO4QepT8-qc8o|o(0-GGCS-80E{@vmz8dRg8J{4!$ZL2KQ}xf7b!&a^#`3aDm~->-$PPY#PX-`_Jv=2z|+deEMz$KP*`{qf_DeQo<&aZo=z z)ki1dnQWG8qI@U~Bpt-rkrwyt*@fAD%xu0AglKg)Uc3}>3qsJ% z^R7hC#4xV-$^&kc?g?;g#GH<{CCi&LQPTU|Xab8RM*_rIZenR&s9t(m(Qb}T^oRX1ldSKU5_pHPWy!2f;tub70CY4X0GX||0T~2bww41b`amM7g-#lwlc1)F%=ao#m2_>W536tkU zonTAkgjrLkPo0b^-86Z|)Jf&DuD^;sI4WB{Pz%CJ1wEWA2rA>+SCws^Umc!-da;%R zr`$YC{VqZWjV~WKd)m~-DfLsQ+<5D4GaAvI`2_kgpUC>e7!q|iHqM+pyM9u6IX+$G zOhfiej}_keBPB2I_H1re%nKmK~K%();bT$%sd@3c>;GOBtRQvz4AAa`-|c(<=Jo=ePeqGlA*S%SylNbAc#-ZAL>;~hhx{|qp% zOFvg4(RePg`lNrF`s8u7mnWxf)HwXF(iaj}tP|Uacg=_O)Hv6A7UG97O+V~QZ7=(i zb|!vU5BlMpQ$HDC+L`#d0DAhtyWv7VWx%vE@xz#-ANte!TnJ42Uq8W|{A2V_A?qaj zd$s9z=9zR{{P{(mdLC7yW2Wco93N~n9BZ0t3-MD({r{ML;*~+0Sbw(hPqj9lsefGu zP`z-Syb73hCjI$eIWDZ%nZ(tZ>i?MIuJO!0(MBY$mo(OiIDtf-_d$($uF14B>3_Y4 zW^kVRsh|^>^%JiQ%JHdl*N40>YaKYJbR2CRh;f>$XDyC;Kb232<@sNYa$aBSpx5S+ z37>Xxel9hd5x_Ln^4#CIo|oZV_UCm-TF*LQn)QFWda{4$2cOIf+rqlj)DMsJWAnt? zc7J{QpQdL&oUWgf(6FD`-`a1CNt*4~|Lx~o|M+oLNI&!W4Ewpib>>eUpM})Zt`EAV zO+dXhHr@(M)7U7)XCe3c3iymy25(1N56pP`5)z*~v)^_i(Rf{AU0Yru3A6Q~AJ&U; zOg~&h5=ivJy^8Kp%YkV;msp=4T?wrF>Pf(Qty*B3UTY*Uuf-$lx*F+qBwf3H2~4A& zSpB>~5~hBp1Je(W{Miipxf{m>jvJBg0oHT*Rn;_}OU$-W^Mt|tiaeV7uLq`o9?MWh z|NM$Nk48PQUW?bIk*DziOJ(#xml!A+c_Mjzo@l9ukdt+MmK_ zEBwYQgRf|AK^s`lmrc7~HF&paBeCui4ghPN`SqJLt#cDF{qr~rW%R!lN9~6%7|gFF zr14y0_0O;PR{#8pLYn%Y4NU($UXC*QzZXaK|A4`3%(=wse;u&;?=~8^ie-@KpU1n9 z=$~^==h_Bf8qeQ=lt9`jNqzn;@-*gY6-e~SxxbD@Zi; znFgj$9;=Y(b0U)ZydIcFJ+b<%7mhw>BGJ?*pC{8Nk9Q!^C+n*|p8%#&Ppm$l5{^DU zibPYN|C8&PK|ioRdAtXS{rO=e?aya`Y3wUv?a#j!j{W%=B%1c8jin9X>2oKN`urv^ zje27Bxf@tDuL0B4=bvKSGw>g;4BGyFVAiwHm`_2=w(mfqX+61~(kGAaM550-k+fa! z1*TC?oIs+V`;f>HKa50EpSJC7;OX;0B=yO<)2Js_pMN17eSQdurau4F^}HX~Vm&{C zr1#}d0Ml3pVy!3RO7~Zv1E#rpj#_@t;*RE)*r??l?ZI(@qD2ck+S;2Jjk5oCX}l}= zCrxZrf2G-o;`X*XSF|nfXzaLWSzDxJ`Ld-;mbZBt_mQB+c}thfUwC`t;i<{f;X>4t~%WF$sf40wWY-wH+*_h_#%a_h; zT;73CLq%Lin%maizBH;Ttim#Qx_fDRYvaP!2uF*Xm#moIJg;L#ds~#F#YOhIO$Kr3iorBFpQQqwk>I2x@b{Ei=aDQ_j4@z>s`dj^0tl@ z%NiFgop(oDRM#zUThunMqph{Ez3ujem_E%>9S9*cg~eX;3WRz4!h7L&ar3;Wa9_Oq z_Wt4vXErvswnkMb=)bnM#wAOa%!?Y;uvPu4maS-6v~XVI9c}mIh6AJA*s`z#ecaZO zWAi2eTj?6mIDb*|?NO}^RS{m=mdtBEy_ZlG;RSPP$?3f;#U~W|T?JX$wj~`4=QVdk z&dIjM1ZSVKopfu`S*991jj)hAiJ6nq}c@{O_)7Y^va=y1WE_Ztj%f8ZJD7Jz#JMb8(tmO5(j`$*yJFcAceli1f9mb9qirSb z0QgjQb8J-0axC-hSX)Msjo4rIUydk=5QLipx5tbWm ze_t9QJ7s4Yp|g9_oFspDn&a~(dARe`{psm+k@GX$eV)cssEhP;%04xsPIjjnA@TOA z5vp*v+HZM3i?Z%mBhC-^tP$njt~El{=e{*Ut2~SNDWG5I^j(u)q(P>V_UN`Dg-R(w|W4{|&begMT z&l`2B?s_B2!+mc*<-yLkA3?D9jS%#^`^8(;7bD7JqgJ~2ypLMQ_oD}G!3G#FrRFjS z(q+Nxvjsg~3{@P7|3IdV4G!UBk)UgEEJQb_KpkILFT~%+3)KBXfx3eQ>iApth1Bng z0(Er->h35|_jrN2%?0YdRiN(I1?q<3KL?PWKCTMX%`H&ZS)lIY1?s+5pzh}d>INnY z>lgRCZw2(`>gE-wd$2&=#|zZ`LxH;Q7pOZ~pzccC01Jt~X$9&Q7N~n)fx1r> zsQX5Ny2AzPit(S}Li#0Jpl)`7y3PW1A1zSle!H%KdGyZ(`r~i97Sb=$FqH=JAjB`(1&$H{o5~g^b6z0(CbPsB^!uS3v(gT%f;a3e>$= zpzgH-btekcy$SDVDWspr7pQZ;)7MY`@mjPc;t$&iXa4gP)$zCf5HkFl)_!&O_fbFn z5F}5;?b+Eq&?zP{7w?*>!0|tk_~t>D@y%%;^ZeC=>&xGVJ%63XUxV@Y70=(?2!CJl z{B1J+_*_iucgXX{=ZJmP??;}$UB=(LjK6_+ca@EUH7Kh>QsZ@LXF;c!`6KYR5=ZtQ z+obh-v*&Lc%Eln6sgKJ%f2|J$<3NA!MpA#bc>WHfY?L|^9kcumMfJ`63&vj)^6Kxs zp1)yeJjY#4eca{wOLqouG-Lf*kksEtJbx7t{yyaSt1$jrjlVB?{;DGUZS(w1H2&rr ze+NB(6X9JKk)p`?hM{Q%Jwcm()K3NS#S|PADoTMCCIC(zu$TO)^_IR+j}5Z ze^+?^_@?TNIujkU<i^Rz=Jt|oTKXR!=Asr5&qVB{;G|?cH{3w&)?Aqe_!zYEinE%jK3dy z{?d3p+*f<|d;Xp_{`f{|ZSOhw1OciP#tVNBzAt|X=(H~(kL@!4xX!4*O3z;%{Pnf| zjqv=PfWHd(;rQNb{LS+G@%QJ^w9vFpGdzF8SLfD)RmR`lp1)T3;|D3!)L*;jZ!G+A z-DUl-w1(~du;*_T{Poq|b)LUg_|x`w8hubILspoGqobbNO_O3zVwb<_$uWq3J%4NAuL9?>evcb}4}0|+3x9pZ zU#I798~kw{r@t=a&;8aZ@>;)|2!DU$`Rg(MK4ARq_3Aer{`zX~w>*D`;7{AT*7*C4 z=dTI=E<(AQj_EPa-+(nae@{Y89sB8gd~(Ug%PRQeb=B10KQKC+&_x$wtzisQi#h^W7Jdj1Z>-w1UkI%fIXuj-rmz3`{;_cZeA??KOB z8U=McL5w=uD$ifh!@2tLjpFL>8PDHL6zGRX=|}y2%=5Pj{xl68Gtb{n<8OoU=YFFWd7U4f5&q6E&b1x#*nZ=0qwzNuIvamo z5&o|B{2e#`HW`1jJ%3L}_`BKjm&T%}{r5@Zufy}VDZ<}U&tHY{_pI@^&hxhg{?PTI zA?xgep1+CkSAi1FkH1Btj&boN&);?w^c649dH$MA{WcqauY3M_BK-Z>^S9FY`>gRd zU~vBU^7Y=n>X(F$ZBkon{A~frGM@Kl&)=a4f0udwo;Ciq8h`G$gONWQiN+ri>8pM> zc>cBv zD#H5hK+^gx@%+ufK-a1>(J{Nw^Vj{pTzhwlj^p@*=dT<7-k<|9tzVbtuNVHtVz0>h zy^N&w+v53KcTOy}i5)7Y{yy#btLloyw&Pw+f4h*>-)o+~YP{a2AO59F_4i%R-_Z}^ z{ww~zZv465l13iQbhd3^?t{N1)ZcGBe+%#_%Y7(k{dz>l{<~yIe!L9B^YD4#)zsgG z&?#nF4K_jQ@0-Z8jQ%Ej{#L=Ce#jTap^u54zhU?k++H|g{dS9v{@ia{4{V{i<;@>h8l|yXS8$HW{VjZ?Ez9l;>|R?i0LUscHQ_ z;Q8BxO#$PI?fo8-*6*{PzfR11{qQb*s=rTp{^~ac{X%~n7xnjw=dT8FF_VtO)Zb3e z-|$c3H4|v)?=>X#_cPBQe@FeJ;)@6McgXX%8~*rO4gKvG9mm)GCOD2dz9Vs7U-dib z`K!YwL+kfL*ql;^lRS)!#=v zf5+jkum1ax=kIB3g0%k*8-LGv{?-o7eK41G)cS4l{H3?#+WT|k@4KGA*?98tFdd1h zKmI?`{2f7F+xu(JAAidlOHpX*?F3ps-mh84c>aLzZ#eoHF{7rg z-{<+;{6e7Pd^>@p{;+(;a2pM6%$Qj0FLAD#`r{GXfzW0z!xuiFLcL(HG&q07IO6u5 z=dX1Y_8aO1WdgDHq`2}A7 zJzjp1mtW%L(Rs#_v38SV{X4w;U0!~rm%rD`qtlHg-7BCuA{pz0Uv! z`A2dYr+>`LKkntby!;2e{8}&nq?cdk<=1=pr@j0~ynMHp$L7RXGPc3w*nVs_j3r~6 zOpfKB^zw}OoF(&iG}Ld-6#^w=Sp1D8V_Qs)lke!rLJ z4k%~I*nwOIDCu?}IVu@Dl*_pC*S-8Oj zKf7WxU*w&SC!xlY;oUYMlX-V8o=HI`rG zmGdT^vt;=7)d81uUqNNdFUe(qlCev@e8$U{dHHfLKf=pbc=^k`{N-N$3NK&j<*)Se zZ}#$U@$w_Ry!{Uo+dIlDzuL=JdHK;^KI`SNNiml6-kqO}jWeaZ{&+7x!OK^B`D?uV zwO;9HgotK~L<*)bhH+cDaFF(!8zun8<=;fz- z`59jRCNF=pm!Ik7Z}IZ8y!@?R{Xx%b&>GhjR6?D;o1$0T|W1vz6c#Fh(?6 zIR{H~30}b>X0MHQ`LDazgm@lnR)SZM?!_^e|7Pq-!y^vR&`*2zwo%=*upEN#(mdE3>XZiW8pKtYupdDe&@tq0z4#ozb z$;v0kd7^QBiN<>(`CwSSrwN`&zVskpRPBl6!(MqJ{e;&kr2AOcDXjY}S03Bn2e>f! zuu{YVcOVJD=i$itNWKV1S}6)c4RELd4mC-m0S-05p#~uI0~~6AsX3e1lI;`o#FaR5 zE)kdDh?hhi9*HCKumzPbA%=B~x{1MnzdS{y!U z?p#(@a0)!@`xYdgJ4i8Jq{sl%;-Y6+DR>%j3Ovspf<&IX6<(W|I|1%?6a&Ue(Sczf z3U)jy9`b@6KhW@k9goI^dSLdSYp-CAO{rk+2#HxwS}6u3JQtWdG&csop$3f$HNaf| zxUQE1hZz&`=K? z>IFMJaHt0n>VZSOV5i4JsK+3Odf-qm*y({oJq9Jz1EVW~F#--Xa1v?+Ll!GV5QRK2 zsvVpwn7*h9{h;GRJ#cs};825`NT>l0HNezV(I*BOLlDd(U|b@&F7PN|THZWjP{25+ z^5zkE&W|@El_C&ApTMC{;7XM9-bM{EE&gn9Iody6PUi=A{zQ1WiVhYp1}ib z3=;j&h_#;A0F$SmiGss=B3QzD0%Ljx{R3PCjO8O%Di||a|Jsdfe`Y79ghVd zq7Het+^AF58 zbg>7FD!KPtmkLIR#1y014zoTk{-Fu`6Ar`r0CSGA-%Ek1d6~F6`0{Xcx5GPeq{TlK z9NpZ3hDMwcz6O}*QcquTw2M}cM4lXRO8A?Er=E3+qYr8CM53M?aZ30`;i*p}#bsXK zE<8En6nI{1vGCM$F2pPF09%1X|Kx~M;HiJF@YI(g#o2kVhmfczN1PJ=eZo^e3@MI& zrmaV!o*Z#X_-^5;=Qzgs0DA_BdS;1J!n0e+Q=dVKGZjzviEI38f{Mj}s+I3;|m@Vu6bnV|r%MM%_>BTfn5EOa&JB6p-#mq1O*kef4lOs+E{{i8tcQL~W1zV3qJvri(@ZG{wPZ#kE@c{cI z67}SWQ{dV5&B9a9u!ysPu+Jk=PmVYx{1=6%K7$nJVHO0k$8BdUC`m@T~tq;i-Qw#<29Q!4Cs8kq6fI^k~eq36DdJ zSYzf6;i0R7G?2)RL5f12v3eUCH!?p zUyZW(5UOLbX~L5uP6>ar(N9EK{2Z!dv3CehjyMILL-2o$z6N=nv-5-}N33&}Ka|0K zWB=4qpTGlbsqo~8b zN}A5!24M0uVx7NpfmP2o>zrL6JUL>WvrB}h{{g`9BpzUQA<+*x;*{{Kgs0xk*|R~w z9!8>`9I?Kp@qXc{XV_`Xe^_{O#2WJ-7oK`IXU_!z`wSBOlOs+E&ox=w>*lP)(wBrM zN31cnU3mH*4y-ZoHQ~t-YYe!#kLyyO0Uu`rVSABy-HhOr@UIC^eFboQ5FTJZMxve^ zaZ31~3Qv6{a9r+R|0X;+VqK$tEj;xjfi)(3g(pX>F`0l)`^U{$St|w!PmWmEkRe9T z`KfEjCBl;<)-|NU=-r%^wc={w$r0-sGS2AH9pM~za~}jbVx8ktjlPC@1^{fj@HK){ z!t+O2w7qpGi*sWJYZRUwaZ30$qrV7crP#3jIgUdG^SLrj=iQ~i)X<1^-dzSvp7B%6NMo_dCwj{8jE$r0iaF7RQygm>){{VDAN-)Fl-&;MbRUKfiU!0|n}2Jx%FG##&{ zz~pJfI$kS)RnMyEc&!nh9I=kq$t2acEF0rpQw)RQAl3I7A(sm}n%N8kZ=2#NZP;FRz`7oPeG;5a7`?3YN?lOs+E z{~O_{uLRcD(m8I_I}TXyJLd>b{YdILp<(9>PmWmkq8Au_70Pt4l@XpCv96Ps8$IW> zu9N(KBzzhlL;XNJ zz?y`w5v=#Y`9@!dGTm$4DLgr1U5DL%M(R^fy*#hsUWfH0N38cv{-0IrKb`tC9$@bm zo*c2>H=i*2nJCly;M2mBBi8%i$Bce9^>RPmBs@7{z0dxw(a)j&ay-C3Cpz zg{EtodyZD)DEC8Fx~AO;O7%t5%Xyu`lOxtO?GfSm17-t&3|QB+ ze-xe^v94*a3QzrT;CLAxVD7ngO~4WBnzj#^^`t%ntZUkjgeOO=YudjEPkjZju4zYv zCr7Mn+A-m&uLRaLtyg$*#JZ-ryfNFzN33g9tMK$+N4>03cL-08Sl1}7Z#us9)Ti+Pb8B5qu%;2~8g-x1Plry| zoQH%bN33hk`;2}j^|H5LD?B-3UDMVZ{cP%GE&40r$r0-s^^DQapWhGNjp`7d9I>uZ_X^J+LF9U*Yt)0nlOxtO>QUjT=Wyy8^#S3@5$hVYPI&4$ zJ#>xwsPN>7b&dLj@YI(A>l*c}@Z^Yfjry$c)DHvJHRn0u$r0zd=%w8;VI*0i&Oy}eu0z*ApI{rPx+9Yx|e zk|WlA(Hp{3KN48i9F8;fjsw;;$L-U=Q(r~B?2Af}r=A?K?u&*APyJZxWz88OJUL=r zbFMV{YU*WQR3$t)VqJ5_8~sG;<+Y~C!jmJ`HRlGSuc2Pn9Ji)T#`*`&t!cu$H4QxL z&-F;x9JhZ1PmWmE9QV9c^!3!sKF2+81y7Dx*BrOjiGDiuvWB!n!~P^ktZT?h;n(2k z);DOL1fI!rWj%5075S|>dt_imaPkkCm=eS$DP#(!USs&_)k>Ztj zfZdKno*Z#X_{G9g@74tV;|A7&L_Im;l<;m%6aQ{aNT3k*AQJWDh_#>HnkIU;CR~9+ zm|N4plXGjD@avGLAFf;ObvED)z+1^r!G03QHw)(4L(?(38kiayv5wI=VDi-4F=D)u zCr7Mf^mgGtjiVi-TZAV^tYh>J;i-3HB+pylEj&45UAJ3>r{0Yb8w6W~#QKmUP6^*G zJoOxp_*?J*y9bGSa>Oa&9}u2;H%21?VDCeso*Z#X_zwzCy&Izh0L;Y%^yG+jOuK>U zhx!bX-hZDFo*c2>e?KMs798C@1?O@saEO(n>?U}|W@I;NKblc&B2 zDLx7hFoqF%a>Oa&uM&PDj&4k|0I;!0)RQAl34g8dlX1LGFt5c}Eu9*R@%co#;3sgT zX`NjiprN@sumfPO4&bSGb&fmQ?I-Dz9P6iXh|qV}dK5=j=ZgVg(~zhqN33ypv+&fX zk#w!NO?Yy|x>o$T@YK6Flz3y7$?HJI04^hoPZyI^Ts0Otta5aI00teHXxN^68|-hmkZ|F zNz*#N1(+Hdv95umfyq;ETlx@OspL7)RDGZ|?z~+zcdLPu$)^^e#^1wGOxU z08j3ey@%*+oV*7*UY8uPt|!ZcXMJ3puv1}oBT-L|I3@gj!c*_!MAn}*!jmJ`^~bFt zQlH`A^*+T|p?`A3y8is7@E^mmTQK|fRpPe?-<>f=@HcU!=@?Z5Q$r)xF?t&?dFtI5 zanN9HEWnc^P6{!qdMS zqwxT+zeA#)9I?JX>N(-5&mhI+e*L2GDppPajo z+w~bd^=?c@0>IjkSRZo4I`8ffo_aT?2>_V8k3&!Hl>4~&cVl{mlLz;4@Z?UpkAv?5 z|2Pusz`or|JU!UMj}pxBq-meK`2`J)So{1MV4h38>vNeGb;6S))_H-@ar#f===xmZ ze3tO!h&9gV2v2<)DPDmGSQ8SjOO9CMe7^A1yFQmVUm`p?VvX|-;i-3hJ{$n{UL^V_ zN38SoLE)))ea;Smxji}b%91s@LO>FtYG%-N@Cmu zxYlyHCuY59Iz}Ua$a>TkHZV{e(H%2lq779;}Snn@Og})2O4#DiJ$B1tV z{{O(RBYr=QH0?u9A@Ve0?Zc~pRd4%nqVVL1wGV5BXS~=xtQVdfvGyS^N&nQ_KAbH) zIb!WYcdr+{?ZYO~lOxtXbn`;=>@R)IXAv;3OO9Ay^Wi$9^o)fYPmWmo+&y=I zAKsVNh=zT;k{AnT7`MQE#w{0D*eP)S#w{@W>SIWysK_%oRto+E zjx>#17oV&wj9BB=t=r(KcQFafcH92MusQ$ah_ydw3;z)u*?0QC2G?HrA?MnA9ssNb ziS?x3_2-3T<$V<3$-M_j-|M&xSoOug8e?ofd2+-WW2=Oxf7hQE0l?f|2zqkF;rri! z)j#7^Usr!pcyh%0y86??cjM@;0iR(%p9K=;`r+&Vvwrb&0_^-tdo$#vZXB<8d7!Bx zt_W~7F&|(xNbzfkf;Az2ZGdt4Sp2O4oh zJ~_aT5i<~AYmwqp9E?3p%*g@UfE1rf6#U;Ietm$q;1Itdz%LNj2Y5U2v;glSW`MzV zBgJoY(0xB!e0qQnkjMRkb{Hwnpo1MniX-M}Cy?SZ9dr+R&vJ1U5BOo!2xhk`t}>Wi zraY^wF~-l74el{`A8`>LV26+tyM7S9*YN!O zw`xia&Jas{^1ZT(s|~I*c&5Q~i6x#F7|izqD&J`^-&3kQ-#ejrlfnF-pz{2`pw5w9 z2JbcafWb!$K4EZCBIl==cmR71`zM3>z4^-XdoC5%5T6_9ryI=gu~(koL9cij@xVaO z?~+&in8E7|-awoR^qUQS!Qh<+?>2b9!H0<%;IQKc#}I4ErwtxvaD~C{_w)t@ekPI^ zTyOAfgPROqWH7&rQ`h`82Cp@^+u&yn-e&N2;`4+0^ccL);6nxC1(#6yDqIb!e$gNrb~Ra0#6aDyv}c@u<emAi3ZmjJlo(VgBKaR zl34EPYYbj%Fu!|OHP0Hn&EV|@_ZYm7SoR5r3_fabufYSb*HAq_yRSH7@JNHJiDj=_ zXYfpe=Ni1g;0}X3iH8UM*=6w425&NWi^1-<=;Yj8jRz4em8~0Pe~0%L4zU24@T&X>hf{bq3EQzC7?V*I@ViY{K)m)l}0- zd_|z|GWcnOHyONzxH8bcXz(tB_ZobF_{uD(sOqiyq9=F;PZgN?zfVJKVkSHyvCsVVuObhR|kG74IXQ7jlt6mo?~z; zu{;M~X7DP5A2WEJ!5a*AzbzzwUNHPlgLf0lbNu}VA2#^7!Tb=o>eB`fBbL_(Dh#eN zc%s4e2J^Rc^xP(c7a6>gcw*4EYYbj%aJRwF8obTm?ZonWMUTPz3_fJ=QGhf{bq3Egc&@<~gNGYjNjy35Ki1$HgWYeTh-QxATMb@j@G65JBd!hnyWcDkyutAN zO%c_+VDL_ZcN@H)cuL^&u))U-<`;6QCT;LAgDVWKBCZR3PBggQ;MoQ@8NA5gl?JaN zo*MY%_x~&IHuzbCw;8WiW8m{KgV!0n!QjmXzhLlAgZVxE`da9I zgAW^g++eRDy*M1$)Mo^5cG!HW!DNqke_bB)1k4emDhS%bG3 zyxrg);+q4X`wTv0@KJ+%4IY5k81!6z$C%;_@yx*INQ0{lt}}S1!E+5>VDSF~(gCaw literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/readme.md b/Sming/third-party/ESP8266_NONOS_SDK/lib/readme.md new file mode 100644 index 0000000000..8447d99ea7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/lib/readme.md @@ -0,0 +1,59 @@ +# About libc.a and libgcc.a + +In order to reduce the size of **.text**, we remove the functions which already in rom code. + +The removed functions in libgcc.a: + +``` +__addsubdf3 +__addsubsf3 +__divdf3 +__divdi3 +__divsi3 +__extendsfdf2 +__fixdfsi +__fixunsdfsi +__fixunssfsi +__floatsidf +__floatsisf +__floatunsidf +__floatunsisf +__muldf3 +__muldi3 +__mulsf3 +__truncdfsf2 +__udivdi3 +__udivsi3 +__umoddi3 +__umodsi3 +__umulsidi3 +``` + +The removed functions in libc.a: + +``` +bzero +memcmp +memcpy +memmove +memset +strcmp +strcpy +strlen +strncmp +strncpy +strstr +``` + +## How to remove the functions in those two lib. + +The libc.a in SDK is compiled from newlib v2.0.0, libgcc.a is compiled from gcc v4.8.5. +If you use other version gcc and newlib, you can follow those commands to strip the functions. + +``` +cp $(TOOLCHAIN)/lib/gcc/xtensa-lx106-elf//libgcc.a . +xtensa-lx106-elf-ar -M < strip_libgcc_funcs.txt + +cp $(TOOLCHAIN)/xtensa-lx106-elf/lib/libc.a . +xtensa-lx106-elf-ar -M < strip_libc_funcs.txt +``` \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libc_funcs.txt b/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libc_funcs.txt new file mode 100644 index 0000000000..db4e6b27bb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libc_funcs.txt @@ -0,0 +1,15 @@ +OPEN libc.a +DELETE lib_a-bzero.o +DELETE lib_a-memcmp.o +DELETE lib_a-memcpy.o +DELETE lib_a-memmove.o +DELETE lib_a-memset.o +DELETE lib_a-rand.o +DELETE lib_a-strcmp.o +DELETE lib_a-strcpy.o +DELETE lib_a-strlen.o +DELETE lib_a-strncmp.o +DELETE lib_a-strncpy.o +DELETE lib_a-strstr.o +SAVE +END \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libgcc_funcs.txt b/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libgcc_funcs.txt new file mode 100644 index 0000000000..ab9b50635a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/lib/strip_libgcc_funcs.txt @@ -0,0 +1,25 @@ +OPEN libgcc.a +DELETE _addsubdf3.o +DELETE _addsubsf3.o +DELETE _divdf3.o +DELETE _divdi3.o +DELETE _divsi3.o +DELETE _extendsfdf2.o +DELETE _fixdfsi.o +DELETE _fixunsdfsi.o +DELETE _fixunssfsi.o +DELETE _floatsidf.o +DELETE _floatsisf.o +DELETE _floatunsidf.o +DELETE _floatunsisf.o +DELETE _muldf3.o +DELETE _muldi3.o +DELETE _mulsf3.o +DELETE _truncdfsf2.o +DELETE _udivdi3.o +DELETE _udivsi3.o +DELETE _umoddi3.o +DELETE _umodsi3.o +DELETE _umulsidi3.o +SAVE +END \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/Makefile new file mode 100644 index 0000000000..bb3718b494 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/Makefile @@ -0,0 +1,127 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lssl \ + -lupgrade \ + -lsmartconfig \ + -lairkiss\ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DLWIP_OPEN_SRC \ + -DPBUF_RSV_FOR_WLAN \ + -DEBUF_LWIP \ + -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/cc.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/cc.h new file mode 100644 index 0000000000..3633f6740b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/cc.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __ARCH_CC_H__ +#define __ARCH_CC_H__ + +//#include +#include "c_types.h" +#include "ets_sys.h" +#include "osapi.h" +#define EFAULT 14 + +//#define LWIP_PROVIDE_ERRNO + +#if (1) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif + + +typedef unsigned char u8_t; +typedef signed char s8_t; +typedef unsigned short u16_t; +typedef signed short s16_t; +typedef unsigned long u32_t; +typedef signed long s32_t; +typedef unsigned long mem_ptr_t; + +#define S16_F "d" +#define U16_F "d" +#define X16_F "x" + +#define S32_F "d" +#define U32_F "d" +#define X32_F "x" + +#define LWIP_ERR_T s32_t + +//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +//#define LWIP_DEBUG + +#ifdef LWIP_DEBUG +#define LWIP_PLATFORM_DIAG(x) os_printf x +#define LWIP_PLATFORM_ASSERT(x) ETS_ASSERT(x) +#else +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) +#endif + +#define SYS_ARCH_DECL_PROTECT(x) +#define SYS_ARCH_PROTECT(x) +#define SYS_ARCH_UNPROTECT(x) + +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff))) +#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) + +#if LWIP_RAW +extern u8_t memp_memory_RAW_PCB_base[]; +#endif /* LWIP_RAW */ + +#if LWIP_UDP +extern u8_t memp_memory_UDP_PCB_base[]; +#endif /* LWIP_UDP */ + +#if LWIP_TCP +extern u8_t memp_memory_TCP_PCB_base[]; +extern u8_t memp_memory_TCP_PCB_LISTEN_base[]; +extern u8_t memp_memory_TCP_SEG_base[] SHMEM_ATTR; +#endif /* LWIP_TCP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +extern u8_t memp_memory_SYS_TIMEOUT_base[]; +#endif /* LWIP_TIMERS */ + +extern u8_t memp_memory_PBUF_base[]; +extern u8_t memp_memory_PBUF_POOL_base[]; + + + +#endif /* __ARCH_CC_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/perf.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/perf.h new file mode 100644 index 0000000000..089facac1d --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/sys_arch.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/arch/sys_arch.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api.h new file mode 100644 index 0000000000..91b9e5d243 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores whether to wake up the original application task + if data couldn't be sent in the first try. */ +#define NETCONN_FLAG_WRITE_DELAYED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If this is set, a TCP netconn must call netconn_recved() to update + the TCP receive window (done automatically if not set). */ +#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) (t&0xF0) +#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) + +/** Protocol family and type of the netconn */ +enum netconn_type { + NETCONN_INVALID = 0, + /* NETCONN_TCP Group */ + NETCONN_TCP = 0x10, + /* NETCONN_UDP Group */ + NETCONN_UDP = 0x20, + NETCONN_UDPLITE = 0x21, + NETCONN_UDPNOCHKSUM= 0x22, + /* NETCONN_RAW Group */ + NETCONN_RAW = 0x40 +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Use to inform the callback function about changes */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last error this netconn had */ + err_t last_err; + /** sem that is used to synchroneously execute functions in the core context */ + sys_sem_t op_completed; + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_RCVTIMEO + /** timeout to wait for new data to be received + (or connections to arrive for listening netconns) */ + int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores how much is already sent. */ + size_t write_offset; + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(lev); \ +} while(0); + +/* Network connection functions: */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +void netconn_recved(struct netconn *conn, u32_t length); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags); +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP +err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#endif /* LWIP_DNS */ + +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_set_noautorecved(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) +/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) + +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api_msg.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api_msg.h new file mode 100644 index 0000000000..f99d8c3b71 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/api_msg.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for do_send */ + struct netbuf *b; + /** used for do_newconn */ + struct { + u8_t proto; + } n; + /** used for do_bind and do_connect */ + struct { + ip_addr_t *ipaddr; + u16_t port; + } bc; + /** used for do_getaddr */ + struct { + ip_addr_t *ipaddr; + u16_t *port; + u8_t local; + } ad; + /** used for do_write */ + struct { + const void *dataptr; + size_t len; + u8_t apiflags; + } w; + /** used for do_recv */ + struct { + u32_t len; + } r; + /** used for do_close (/shutdown) */ + struct { + u8_t shut; + } sd; +#if LWIP_IGMP + /** used for do_join_leave_group */ + struct { + ip_addr_t *multiaddr; + ip_addr_t *netif_addr; + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +}; + +/** This struct contains a function to execute in another thread context and + a struct api_msg_msg that serves as an argument for this function. + This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ +struct api_msg { + /** function to execute in tcpip_thread context */ + void (* function)(struct api_msg_msg *msg); + /** arguments for this function */ + struct api_msg_msg msg; +}; + +#if LWIP_DNS +/** As do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ + const char *name; + /** Rhe resolved address is stored here */ + ip_addr_t *addr; + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t *sem; + /** Errors are given back here */ + err_t *err; +}; +#endif /* LWIP_DNS */ + +void do_newconn ( struct api_msg_msg *msg); +void do_delconn ( struct api_msg_msg *msg); +void do_bind ( struct api_msg_msg *msg); +void do_connect ( struct api_msg_msg *msg); +void do_disconnect ( struct api_msg_msg *msg); +void do_listen ( struct api_msg_msg *msg); +void do_send ( struct api_msg_msg *msg); +void do_recv ( struct api_msg_msg *msg); +void do_write ( struct api_msg_msg *msg); +void do_getaddr ( struct api_msg_msg *msg); +void do_close ( struct api_msg_msg *msg); +void do_shutdown ( struct api_msg_msg *msg); +#if LWIP_IGMP +void do_join_leave_group( struct api_msg_msg *msg); +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +void do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/dhcpserver.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/dhcpserver.h new file mode 100644 index 0000000000..df21178d55 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/dhcpserver.h @@ -0,0 +1,115 @@ +#ifndef __DHCPS_H__ +#define __DHCPS_H__ + +#define USE_DNS + +typedef struct dhcps_state{ + sint16_t state; +} dhcps_state; + +// ����dhcpclient�Զ����һ��DHCP msg�ṹ�� +typedef struct dhcps_msg { + uint8_t op, htype, hlen, hops; + uint8_t xid[4]; + uint16_t secs, flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[312]; +}dhcps_msg; + +#ifndef LWIP_OPEN_SRC +struct dhcps_lease { + bool enable; + struct ip_addr start_ip; + struct ip_addr end_ip; +}; + +enum dhcps_offer_option{ + OFFER_START = 0x00, + OFFER_ROUTER = 0x01, + OFFER_END +}; +#endif + +typedef enum { + DHCPS_TYPE_DYNAMIC, + DHCPS_TYPE_STATIC +} dhcps_type_t; + +typedef enum { + DHCPS_STATE_ONLINE, + DHCPS_STATE_OFFLINE +} dhcps_state_t; + +struct dhcps_pool{ + struct ip_addr ip; + uint8 mac[6]; + uint32 lease_timer; + dhcps_type_t type; + dhcps_state_t state; + +}; + +typedef struct _list_node{ + void *pnode; + struct _list_node *pnext; +}list_node; + +extern uint32 dhcps_lease_time; +#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0 +#define DHCPS_MAX_LEASE 0x64 +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPS_SERVER_PORT 67 +#define DHCPS_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_INTERFACE_MTU 26 +#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP_OPTION_BROADCAST_ADDRESS 28 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +//#define USE_CLASS_B_NET 1 +#define DHCPS_DEBUG 0 +#define MAX_STATION_NUM 8 + +#define DHCPS_STATE_OFFER 1 +#define DHCPS_STATE_DECLINE 2 +#define DHCPS_STATE_ACK 3 +#define DHCPS_STATE_NAK 4 +#define DHCPS_STATE_IDLE 5 +#define DHCPS_STATE_RELEASE 6 + +#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0) + +void dhcps_start(struct ip_info *info); +void dhcps_stop(void); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn.h new file mode 100644 index 0000000000..d54795e270 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn.h @@ -0,0 +1,687 @@ +#ifndef __ESPCONN_H__ +#define __ESPCONN_H__ + +#include "lwip/dns.h" +#include "os_type.h" +#include "lwip/app/espconn_buf.h" + +#if 0 +#define espconn_printf(fmt, args...) os_printf(fmt,## args) +#else +#define espconn_printf(fmt, args...) +#endif + + +typedef void *espconn_handle; +typedef void (* espconn_connect_callback)(void *arg); +typedef void (* espconn_reconnect_callback)(void *arg, sint8 err); + +/* Definitions for error constants. */ + +#define ESPCONN_OK 0 /* No error, everything OK. */ +#define ESPCONN_MEM -1 /* Out of memory error. */ +#define ESPCONN_TIMEOUT -3 /* Timeout. */ +#define ESPCONN_RTE -4 /* Routing problem. */ +#define ESPCONN_INPROGRESS -5 /* Operation in progress */ +#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/ + +#define ESPCONN_ABRT -8 /* Connection aborted. */ +#define ESPCONN_RST -9 /* Connection reset. */ +#define ESPCONN_CLSD -10 /* Connection closed. */ +#define ESPCONN_CONN -11 /* Not connected. */ + +#define ESPCONN_ARG -12 /* Illegal argument. */ +#define ESPCONN_IF -14 /* Low_level error */ +#define ESPCONN_ISCONN -15 /* Already connected. */ +#define ESPCONN_TIME -16 /* Sync Time error */ +#define ESPCONN_NODATA -17 /* No data can be read */ + +#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */ +#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/ +#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */ + +#define ESPCONN_SSL 0x01 +#define ESPCONN_NORM 0x00 + +#define ESPCONN_STA 0x01 +#define ESPCONN_AP 0x02 +#define ESPCONN_AP_STA 0x03 + +#define STA_NETIF 0x00 +#define AP_NETIF 0x01 + +/** Protocol family and type of the espconn */ +enum espconn_type { + ESPCONN_INVALID = 0, + /* ESPCONN_TCP Group */ + ESPCONN_TCP = 0x10, + /* ESPCONN_UDP Group */ + ESPCONN_UDP = 0x20, +}; + +/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */ +enum espconn_state { + ESPCONN_NONE, + ESPCONN_WAIT, + ESPCONN_LISTEN, + ESPCONN_CONNECT, + ESPCONN_WRITE, + ESPCONN_READ, + ESPCONN_CLOSE +}; + +typedef struct _esp_tcp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; + espconn_connect_callback connect_callback; + espconn_reconnect_callback reconnect_callback; + espconn_connect_callback disconnect_callback; + espconn_connect_callback write_finish_fn; +} esp_tcp; + +typedef struct _esp_udp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; +} esp_udp; + +typedef struct _remot_info{ + enum espconn_state state; + int remote_port; + uint8 remote_ip[4]; +}remot_info; + +/** A callback prototype to inform about events for a espconn */ +typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len); +typedef void (* espconn_sent_callback)(void *arg); + +/** A espconn descriptor */ +struct espconn { + /** type of the espconn (TCP, UDP) */ + enum espconn_type type; + /** current state of the espconn */ + enum espconn_state state; + union { + esp_tcp *tcp; + esp_udp *udp; + } proto; + /** A callback function that is informed about events for this espconn */ + espconn_recv_callback recv_callback; + espconn_sent_callback sent_callback; + uint8 link_cnt; + void *reverse; +}; + +enum espconn_option{ + ESPCONN_START = 0x00, + ESPCONN_REUSEADDR = 0x01, + ESPCONN_NODELAY = 0x02, + ESPCONN_COPY = 0x04, + ESPCONN_KEEPALIVE = 0x08, + ESPCONN_MANUALRECV = 0x10, + ESPCONN_END +}; + +enum espconn_level{ + ESPCONN_KEEPIDLE, + ESPCONN_KEEPINTVL, + ESPCONN_KEEPCNT +}; + +enum espconn_mode{ + ESPCONN_NOMODE, + ESPCONN_TCPSERVER_MODE, + ESPCONN_TCPCLIENT_MODE, + ESPCONN_UDP_MODE, + ESPCONN_NUM_MODE +}; + +struct espconn_packet{ + uint16 sent_length; /* sent length successful*/ + uint16 snd_buf_size; /* Available buffer size for sending */ + uint16 snd_queuelen; /* Available buffer space for sending */ + uint16 total_queuelen; /* total Available buffer space for sending */ + uint32 packseqno; /* seqno to be sent */ + uint32 packseq_nxt; /* seqno expected */ + uint32 packnum; +}; + +typedef struct _espconn_buf{ + uint8 *payload; + uint8 *punsent; + uint16 unsent; + uint16 len; + uint16 tot_len; + struct _espconn_buf *pnext; +} espconn_buf; + +typedef struct _comon_pkt{ + void *pcb; + int remote_port; + uint8 remote_ip[4]; + uint32 local_port; + uint32 local_ip; + espconn_buf *pbuf; + espconn_buf *ptail; + uint8* ptrbuf; + uint16 cntr; + sint8 err; + uint32 timeout; + uint32 recv_check; + uint8 pbuf_num; + struct espconn_packet packet_info; + bool write_flag; + enum espconn_option espconn_opt; +}comon_pkt; + +typedef struct _espconn_msg{ + struct espconn *pespconn; + comon_pkt pcommon; + uint8 count_opt; + uint8 espconn_mode; + sint16_t hs_status; //the status of the handshake + void *preverse; + void *pssl; + struct _espconn_msg *pnext; + +//***********Code for WIFI_BLOCK from upper************** + uint8 recv_hold_flag; + uint16 recv_holded_buf_Len; +//******************************************************* + ringbuf *readbuf; +}espconn_msg; + +#ifndef _MDNS_INFO +#define _MDNS_INFO +struct mdns_info { + char *host_name; + char *server_name; + uint16 server_port; + unsigned long ipAddr; + char *txt_data[10]; +}; +#endif + +#define linkMax 15 + +#define espconn_delay_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0) +#define espconn_delay_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0) +#define espconn_reuse_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0) +#define espconn_copy_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0) +#define espconn_copy_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0) +#define espconn_keepalive_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0) +#define espconn_keepalive_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0) + +#define espconn_TaskPrio 26 +#define espconn_TaskQueueLen 15 + +enum espconn_sig { + SIG_ESPCONN_NONE, + SIG_ESPCONN_ERRER, + SIG_ESPCONN_LISTEN, + SIG_ESPCONN_CONNECT, + SIG_ESPCONN_WRITE, + SIG_ESPCONN_SEND, + SIG_ESPCONN_READ, + SIG_ESPCONN_CLOSE +}; + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source); + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert); + +/****************************************************************************** + * FunctionName : espconn_list_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete); + +/****************************************************************************** + * FunctionName : espconn_find_connection + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none + *******************************************************************************/ + +bool espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode); + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags); + +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ + +sint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg); + +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_connect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_disconnect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_delete(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_accept(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_create(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_wnd + * Description : get the window size of simulatenously active TCP connections + * Parameters : none + * Returns : the number of TCP_MSS active TCP connections +*******************************************************************************/ +extern uint8 espconn_tcp_get_wnd(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the window size simulatenously active TCP connections + * Parameters : num -- the number of TCP_MSS + * Returns : ESPCONN_ARG -- Illegal argument + * ESPCONN_OK -- No error +*******************************************************************************/ +extern sint8 espconn_tcp_set_wnd(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_con(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : num -- total number + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_retran + * Description : get the Maximum number of retransmissions of data active TCP connections + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +extern uint8 espconn_tcp_get_max_retran(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_retran + * Description : set the Maximum number of retransmissions of data active TCP connections + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_retran(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_syn + * Description : get the Maximum number of retransmissions of SYN segments + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_syn(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_syn + * Description : set the Maximum number of retransmissions of SYN segments + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_syn(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_buf_count + * Description : set the total number of espconn_buf on the unsent lists + * Parameters : espconn -- espconn to set the count + * num -- the total number of espconn_buf + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : struct espconn *espconn -- espconn to set the sent callback + * espconn_sent_callback sent_cb -- sent callback function to + * call for this espconn when data is successfully sent + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +extern sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn); + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb); + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ + +extern uint32 espconn_port(void); + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_opt(struct espconn *espconn, uint8 opt); + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg); + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ +extern sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg); + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if + * ESPCONN_OK is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ + +extern err_t espconn_gethostbyname(struct espconn *pespconn, const char *name, ip_addr_t *addr, dns_found_callback found); + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : register a device with mdns + * Parameters : ipAddr -- the ip address of device + * hostname -- the hostname of device + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_init(struct mdns_info *info); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : close mdns socket + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_close(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : register a server and join a multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_register(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : unregister server and leave multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_unregister(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : get server name + * Parameters : none + * Returns : server name +*******************************************************************************/ +extern char* espconn_mdns_get_servername(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : set server name + * Parameters : server name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_servername(const char *name); +/****************************************************************************** + * FunctionName : espconn_mdns_set_hostname + * Description : set host name + * Parameters : host name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_hostname(char *name); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : get host name + * Parameters : void + * Returns : hostname +*******************************************************************************/ +extern char* espconn_mdns_get_hostname(void); +/****************************************************************************** + * FunctionName : espconn_mdns_disable + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_disable(void); +/****************************************************************************** + * FunctionName : espconn_mdns_enable + * Description : enable mdns + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_enable(void); +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +extern void espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +/****************************************************************************** + * FunctionName : espconn_dns_getserver + * Description : get dns server. + * Parameters : numdns -- the index of the DNS server ,must + * be < DNS_MAX_SERVERS = 2 + * Returns : dnsserver -- struct ip_addr_t +*******************************************************************************/ +extern ip_addr_t espconn_dns_getserver(u8_t numdns); +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_buf.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_buf.h new file mode 100644 index 0000000000..8bdfaa12ab --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_buf.h @@ -0,0 +1,60 @@ +/* + * ringbuf.h + * + * Created on: Apr 22, 2016 + * Author: liuhan + */ + +#ifndef _ESPCONN_BUF_H_ +#define _ESPCONN_BUF_H_ + +/* + * ringbuffer.c + * + * Created on: Apr 22, 2016 + * Author: liuhan + */ +#include "c_types.h" + +#include "ets_sys.h" +#include "os_type.h" + +typedef struct ringbuf_t { + uint8_t *buf; + uint8_t *head, *tail; + size_t size; +} ringbuf, *ringbuf_t; + +ringbuf_t ringbuf_new(size_t capacity); + +size_t ringbuf_buffer_size(const struct ringbuf_t *rb); + +void ringbuf_reset(ringbuf_t rb); + +void ringbuf_free(ringbuf_t *rb); + +size_t ringbuf_capacity(const struct ringbuf_t *rb); + +size_t ringbuf_bytes_free(const struct ringbuf_t *rb); + +size_t ringbuf_bytes_used(const struct ringbuf_t *rb); + +int ringbuf_is_full(const struct ringbuf_t *rb); + +int ringbuf_is_empty(const struct ringbuf_t *rb); + +const void* ringbuf_tail(const struct ringbuf_t *rb); + +const void* ringbuf_head(const struct ringbuf_t *rb); + +static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t *p); + +size_t ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset); + +size_t ringbuf_memset(ringbuf_t dst, int c, size_t len); + +void *ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count); + +void *ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count); + +#endif /* RINGBUF_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_tcp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_tcp.h new file mode 100644 index 0000000000..1dfd483fd1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_tcp.h @@ -0,0 +1,58 @@ +#ifndef __ESPCONN_TCP_H__ +#define __ESPCONN_TCP_H__ + +#ifndef ESPCONN_TCP_DEBUG +#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF +#endif +#include "lwip/app/espconn.h" + +#ifndef ESPCONN_TCP_TIMER +#define ESPCONN_TCP_TIMER 40 +#endif + +#define espconn_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) +#define espconn_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) + +#define espconn_manual_recv_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_MANUALRECV) != 0) +#define espconn_manual_recv_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_MANUALRECV) == 0) + +/****************************************************************************** + * FunctionName : espconn_kill_oldest_pcb + * Description : A oldest incoming connection has been killed. + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern void espconn_kill_oldest_pcb(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type); + +/****************************************************************************** + * FunctionName : espconn_tcp_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_client(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_server + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_server(struct espconn *espconn); + +#endif /* __CLIENT_TCP_H__ */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_udp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_udp.h new file mode 100644 index 0000000000..cdb312f73e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/espconn_udp.h @@ -0,0 +1,64 @@ +#ifndef __ESPCONN_UDP_H__ +#define __ESPCONN_UDP_H__ + +#ifndef ESPCONN_UDP_DEBUG +#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF +#endif + +#include "lwip/app/espconn.h" + +/****************************************************************************** + * FunctionName : espconn_udp_client + * Description : Initialize the client: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_client(struct espconn *pespconn); + +/****************************************************************************** + * FunctionName : espconn_udp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_udp_disconnect(espconn_msg *pdiscon); + +/****************************************************************************** + * FunctionName : espconn_udp_server + * Description : Initialize the server: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_server(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_udp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ + +extern err_t espconn_udp_sent(void *arg, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_udp_sendto + * Description : sent data for UDP + * Parameters : void *arg -- UDP to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +extern err_t espconn_udp_sendto(void *arg, uint8 *psent, uint16 length); + +#endif /* __ESPCONN_UDP_H__ */ + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/ping.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/ping.h new file mode 100644 index 0000000000..21e26e9101 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/ping.h @@ -0,0 +1,85 @@ +#ifndef __PING_H__ +#define __PING_H__ +#include "lwip/ip_addr.h" +#include "lwip/icmp.h" +/** + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used + */ +#ifndef PING_USE_SOCKETS +#define PING_USE_SOCKETS LWIP_SOCKET +#endif + +/** + * PING_DEBUG: Enable debugging for PING. + */ +#ifndef PING_DEBUG +#define PING_DEBUG LWIP_DBG_OFF +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_COARSE +#define PING_COARSE 1000 +#endif + +/** ping identifier - must fit on a u16_t */ +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +/** ping additional data size to include in the packet */ +#ifndef PING_DATA_SIZE +#define PING_DATA_SIZE 32 +#endif + +/** ping result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#endif + +#define DEFAULT_PING_MAX_COUNT 4 +#define PING_TIMEOUT_MS 1000 + +typedef void (* ping_recv_function)(void* arg, void *pdata); +typedef void (* ping_sent_function)(void* arg, void *pdata); + +struct ping_option{ + uint32 count; + uint32 ip; + uint32 coarse_time; + ping_recv_function recv_function; + ping_sent_function sent_function; + void* reverse; +}; + +struct ping_msg{ + struct ping_option *ping_opt; + struct raw_pcb *ping_pcb; + uint32 ping_start; + uint32 ping_sent; + uint32 timeout_count; + uint32 max_count; + uint32 sent_count; + uint32 coarse_time; +}; + +struct ping_resp{ + uint32 total_count; + uint32 resp_time; + uint32 seqno; + uint32 timeout_count; + uint32 bytes; + uint32 total_bytes; + uint32 total_time; + sint8 ping_err; +}; + +bool ping_start(struct ping_option *ping_opt); +bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv); +bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent); + +#endif /* __PING_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/time.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/time.h new file mode 100644 index 0000000000..4b0be21c97 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/app/time.h @@ -0,0 +1,49 @@ +/* + * time.h + * + * Created on: May 31, 2016 + * Author: liuhan + */ + +#ifndef TIME_H_ +#define TIME_H_ +#include "osapi.h" +#include "os_type.h" +#include "lwip/sntp.h" +#include + +/***************************RTC TIME OPTION***************************************/ +// daylight settings +// Base calculated with value obtained from NTP server (64 bits) +#define sntp_base (*((uint64_t*)RTC_STORE0)) +// Timer value when base was obtained +#define TIM_REF_SET(value) WRITE_PERI_REG(RTC_STORE2, value) +#define TIM_REF_GET() READ_PERI_REG(RTC_STORE2) + +// Setters and getters for CAL, TZ and DST. +#define RTC_CAL_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= ((val) & 0x0000FFFF);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) +#define RTC_DST_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= (((val)<<16) & 0x00010000);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) +#define RTC_TZ_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= (((val)<<24) & 0xFF000000);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) + +#define RTC_CAL_GET() (READ_PERI_REG(RTC_STORE3) & 0x0000FFFF) +#define RTC_DST_GET() ((READ_PERI_REG(RTC_STORE3) & 0x00010000)>>16) +#define RTC_TZ_GET() ((((int)READ_PERI_REG(RTC_STORE3)) & ((int)0xFF000000))>>24) +void system_update_rtc(time_t t, uint32_t us); +time_t sntp_get_rtc_time(sint32_t *us); + +int gettimeofday(struct timeval* t, void* timezone); +void updateTime(uint32 ms); +bool configTime(int timezone, int daylightOffset, char *server1, char *server2, char *server3, bool enable); +time_t time(time_t *t); +unsigned long millis(void); +unsigned long micros(void); +#endif /* TIME_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/arch.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/arch.h new file mode 100644 index 0000000000..524af6be03 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/arch.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ +/** Temporary upgrade helper: define format string for u8_t as hex if not + defined in cc.h */ +#ifndef X8_F +#define X8_F "02x" +#endif /* X8_F */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + + +#define ENSROK 0 /* DNS server returned answer with no data */ +#define ENSRNODATA 160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162 /* DNS server returned general failure */ +#define ENSRNOTFOUND 163 /* Domain name not found */ +#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166 /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF 172 /* End of file */ +#define ENSRFILE 173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/autoip.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/autoip.h new file mode 100644 index 0000000000..23c264a1e0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/autoip.h @@ -0,0 +1,119 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF 0 +#define AUTOIP_STATE_PROBING 1 +#define AUTOIP_STATE_ANNOUNCING 2 +#define AUTOIP_STATE_BOUND 3 + +struct autoip +{ + ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ + u8_t state; /* current AutoIP state machine state */ + u8_t sent_num; /* sent number of probes or announces, dependent on state */ + u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u8_t lastconflict; /* ticks until a conflict can be solved by defending */ + u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Set a struct autoip allocated by the application to work with */ +void autoip_set_struct(struct netif *netif, struct autoip *autoip); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ +void autoip_tmr(void); + +/** Handle a possible change in the network configuration */ +void autoip_network_changed(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_AUTOIP */ + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/debug.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/debug.h new file mode 100644 index 0000000000..d8359ea3a5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/debug.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "lwip/arch.h" + +/** lower two bits indicate debug level + * - 0 all + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_ALL 0x00 +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +#define LWIP_DBG_MASK_LEVEL 0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ + LWIP_PLATFORM_ASSERT(message); } while(0) +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +/** if "expression" isn't true, then print "message" and execute "handler" expression */ +#ifndef LWIP_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ASSERT(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + * AND is of correct type AND is at least LWIP_DBG_LEVEL + */ +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/def.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/def.h new file mode 100644 index 0000000000..9b6de6a8b8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/def.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/** Get the absolute difference between 2 u32_t values (correcting overflows) + * 'a' is expected to be 'higher' (without overflow) than 'b'. */ +#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) + +/* Endianess-optimized shifting of two u8_t to create one u16_t */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define LWIP_MAKE_U16(a, b) ((a << 8) | b) +#else +#define LWIP_MAKE_U16(a, b) ((b << 8) | a) +#endif + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#ifndef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#if LWIP_PLATFORM_BYTESWAP +#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) +#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) +#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) +#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t lwip_htons(u16_t x); +u16_t lwip_ntohs(u16_t x); +u32_t lwip_htonl(u32_t x); +u32_t lwip_ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_DEF_H__ */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dhcp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dhcp.h new file mode 100644 index 0000000000..9e8fd0ec28 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dhcp.h @@ -0,0 +1,252 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_LEN 128U + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** our connection to the DHCP server */ + struct udp_pcb *pcb; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ + ip_addr_t offered_ip_addr; + ip_addr_t offered_sn_mask; + ip_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ + /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? + integrate with possible TFTP-client for booting? */ +#define LWIP_DHCP_BOOTP_FILE 0 +#if LWIP_DHCP_BOOTP_FILE + ip_addr_t offered_si_addr; + char boot_file_name[DHCP_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FIELD(u8_t op); + PACK_STRUCT_FIELD(u8_t htype); + PACK_STRUCT_FIELD(u8_t hlen); + PACK_STRUCT_FIELD(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); + PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); + PACK_STRUCT_FIELD(ip_addr_p_t siaddr); + PACK_STRUCT_FIELD(ip_addr_p_t giaddr); + PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); +/** Handle a possible change in the network configuration */ +void dhcp_network_changed(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); + +/** DHCP message item offsets and length */ +#define DHCP_OP_OFS 0 +#define DHCP_HTYPE_OFS 1 +#define DHCP_HLEN_OFS 2 +#define DHCP_HOPS_OFS 3 +#define DHCP_XID_OFS 4 +#define DHCP_SECS_OFS 8 +#define DHCP_FLAGS_OFS 10 +#define DHCP_CIADDR_OFS 12 +#define DHCP_YIADDR_OFS 16 +#define DHCP_SIADDR_OFS 20 +#define DHCP_GIADDR_OFS 24 +#define DHCP_CHADDR_OFS 28 +#define DHCP_SNAME_OFS 44 +#define DHCP_FILE_OFS 108 +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS DHCP_MSG_LEN +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_OFF 0 +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/** DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ +#define DHCP_HTYPE_ETH 1 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/**add options for support more router by liuHan**/ +#define DHCP_OPTION_DOMAIN_NAME 15 +#define DHCP_OPTION_PRD 31 +#define DHCP_OPTION_STATIC_ROUTER 33 +#define DHCP_OPTION_VSN 43 +#define DHCP_OPTION_NB_TINS 44 +#define DHCP_OPTION_NB_TINT 46 +#define DHCP_OPTION_NB_TIS 47 +#define DHCP_OPTION_CLASSLESS_STATIC_ROUTER 121 +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*__LWIP_DHCP_H__*/ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dns.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dns.h new file mode 100644 index 0000000000..6c7d9b0739 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/dns.h @@ -0,0 +1,124 @@ +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_DNS_H__ +#define __LWIP_DNS_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* The size used for the next line is rather a hack, but it prevents including socket.h in all files + that include memp.h, and that would possibly break portability (since socket.h defines some types + and constants possibly already define by the OS). + Calculation rule: + sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ +#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +ip_addr_t dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); + +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/err.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/err.h new file mode 100644 index 0000000000..cb69a9f498 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/err.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/* Definitions for error constants. */ + +#define ERR_OK 0 /* No error, everything OK. */ +#define ERR_MEM -1 /* Out of memory error. */ +#define ERR_BUF -2 /* Buffer error. */ +#define ERR_TIMEOUT -3 /* Timeout. */ +#define ERR_RTE -4 /* Routing problem. */ +#define ERR_INPROGRESS -5 /* Operation in progress */ +#define ERR_VAL -6 /* Illegal value. */ +#define ERR_WOULDBLOCK -7 /* Operation would block. */ + +#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK) + +#define ERR_ABRT -8 /* Connection aborted. */ +#define ERR_RST -9 /* Connection reset. */ +#define ERR_CLSD -10 /* Connection closed. */ +#define ERR_CONN -11 /* Not connected. */ + +#define ERR_ARG -12 /* Illegal argument. */ + +#define ERR_USE -13 /* Address in use. */ + +#define ERR_IF -14 /* Low-level netif error */ +#define ERR_ISCONN -15 /* Already connected. */ + + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err)ICACHE_FLASH_ATTR; +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/icmp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/icmp.h new file mode 100644 index 0000000000..9bcb7bc439 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/icmp.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ + +enum icmp_dur_type { + ICMP_DUR_NET = 0, /* net unreachable */ + ICMP_DUR_HOST = 1, /* host unreachable */ + ICMP_DUR_PROTO = 2, /* protocol unreachable */ + ICMP_DUR_PORT = 3, /* port unreachable */ + ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + ICMP_DUR_SR = 5 /* source route failed */ +}; + +enum icmp_te_type { + ICMP_TE_TTL = 0, /* time to live exceeded in transit */ + ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ +}; + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is splitted to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + * ¶¨ÒåICMP»ØËÍÇëÇó±¨ÎÄÊײ¿½á¹¹£¬ + * ÓÉÓÚËùÓÐICMP±¨ÎÄÊײ¿ÓкܴóÏàËÆÐÔ£¬ + * ¸Ã½á¹¹Í¬ÑùÊÊÓÃÓÚÆäËüICMP±¨ÎÄ¡£ + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +//¶ÁÈ¡ICMPÊײ¿ÖÐ×ֶΠ+#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t ÏòICMP±¨ÎÄÊײ¿×Ö¶ÎÖÐдÈëÏàÓ¦Öµ*/ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)ICACHE_FLASH_ATTR; +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)ICACHE_FLASH_ATTR; + +#endif /* LWIP_ICMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ICMP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/igmp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/igmp.h new file mode 100644 index 0000000000..c90adcdce4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/igmp.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef __LWIP_IGMP_H__ +#define __LWIP_IGMP_H__ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* MAC Filter Actions, these are passed to a netif's + * igmp_mac_filter callback function. */ +#define IGMP_DEL_MAC_FILTER 0 +#define IGMP_ADD_MAC_FILTER 1 + + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void)ICACHE_FLASH_ATTR; +err_t igmp_start(struct netif *netif)ICACHE_FLASH_ATTR; +err_t igmp_stop(struct netif *netif)ICACHE_FLASH_ATTR; +void igmp_report_groups(struct netif *netif)ICACHE_FLASH_ATTR; +struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLASH_ATTR; +err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +void igmp_tmr(void)ICACHE_FLASH_ATTR; +#define LWIP_RAND() r_rand() +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet.h new file mode 100644 index 0000000000..7bff49b59e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** For compatibility with BSD code */ +struct in_addr { + u32_t s_addr; +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + +#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ +#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) +#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet_chksum.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet_chksum.h new file mode 100644 index 0000000000..41be6415bc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/inet_chksum.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_CHKSUM_H__ +#define __LWIP_INET_CHKSUM_H__ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +#ifndef LWIP_CHKSUM_COPY +#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +#ifndef LWIP_CHKSUM_COPY_ALGORITHM +#define LWIP_CHKSUM_COPY_ALGORITHM 1 +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +#endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +#define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pbuf(struct pbuf *p)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo_partial(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len)ICACHE_FLASH_ATTR; +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/init.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/init.h new file mode 100644 index 0000000000..7a58aece9e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/init.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INIT_H__ +#define __LWIP_INIT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 1U +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 4U +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 0U +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC 2U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT 0U + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ + LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +/* Modules initialization */ +void lwip_init(void) ICACHE_FLASH_ATTR; +//void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip.h new file mode 100644 index 0000000000..1f361fa448 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND LWIP_IGMP + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ +#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { + /* version / header length / type of service */ + PACK_STRUCT_FIELD(u16_t _v_hl_tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FIELD(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FIELD(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(ip_addr_p_t src); + PACK_STRUCT_FIELD(ip_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +/** The interface that provided the packet for the current callback invocation. */ +extern struct netif *current_netif; +/** Header of the input packet currently being processed. */ +extern const struct ip_hdr *current_header; +/** Source IP address of current_header */ +extern ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +extern ip_addr_t current_iphdr_dest; + +#define ip_init() /* Compatibility define, not init needed. */ +struct netif *ip_route(ip_addr_t *dest)ICACHE_FLASH_ATTR; +struct netif *ip_router(ip_addr_t *dest, ip_addr_t *source); + +err_t ip_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto)ICACHE_FLASH_ATTR; +err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, + struct netif *netif)ICACHE_FLASH_ATTR; +#if LWIP_NETIF_HWADDRHINT +err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen)ICACHE_FLASH_ATTR; +#endif /* IP_OPTIONS_SEND */ +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (current_netif) +/** Get the IP header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_header() (current_header) +/** Source IP address of current_header */ +#define ip_current_src_addr() (¤t_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (¤t_iphdr_dest) + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p)ICACHE_FLASH_ATTR; +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_addr.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_addr.h new file mode 100644 index 0000000000..1e46ee5936 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_addr.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the aligned version of ip_addr_t, + used as local variable, on the stack, etc. */ +struct ip_addr { + u32_t addr; +}; + +/* This is the packed version of ip_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** ip_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip_addr_t as well as on ip_addr_p_t. */ +typedef struct ip_addr ip_addr_t; +typedef struct ip_addr_packed ip_addr_p_t; + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Forward declaration to not include netif.h */ +struct netif; + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + * for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + + +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IP address given by the four byte-parts. + Little-endian version that prevents the use of htonl. */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) +#endif + +/** Copy IP address - faster than ip_addr_set: no NULL check */ +#define ip_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for htonl()) */ +#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) + +#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) +u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)ICACHE_FLASH_ATTR; + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask)ICACHE_FLASH_ATTR; + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ + ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) + +/* Get one byte from the 4-byte address */ +#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp)ICACHE_FLASH_ATTR; +int ipaddr_aton(const char *cp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +/** returns ptr to static buffer; not reentrant! */ +char *ipaddr_ntoa(const ip_addr_t *addr)ICACHE_FLASH_ATTR; +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)ICACHE_FLASH_ATTR; + +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +#define IPSTR "%d.%d.%d.%d" + +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_frag.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_frag.h new file mode 100644 index 0000000000..df6db5f5c1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/ip_frag.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/* IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void)ICACHE_FLASH_ATTR; +void ip_reass_tmr(void)ICACHE_FLASH_ATTR; +struct pbuf * ip_reass(struct pbuf *p)ICACHE_FLASH_ATTR; +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)ICACHE_FLASH_ATTR; +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mdns.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mdns.h new file mode 100644 index 0000000000..cd910cb26f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mdns.h @@ -0,0 +1,114 @@ +/** + * lwip MDNS resolver header file. + * + * Created on: Jul 29, 2010 + * Author: Daniel Toma + + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_MDNS_H__ +#define __LWIP_MDNS_H__ + +#include "lwip/opt.h" + +#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */ + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/** mDNS Address offset flag*/ +#define DNS_OFFSET_FLAG 0xC0 /* the offset flag in the DNS message */ +#define DNS_DEFAULT_OFFSET 0x0C /* the offset is set at the beginning of the DNS message */ + +#define DNS_IP_ADDR_LEN 4 + + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_SRV 33 /* Service record */ +#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */ +#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */ +#define DNS_RRTYPE_ANY 255 /*Not a DNS type, but a DNS query type, meaning "all types"*/ + +/* DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ +#define DNS_RRCLASS_FLUSH_IN 0x8001/* Flush bit and Internet*/ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +#ifndef _MDNS_INFO +#define _MDNS_INFO +struct mdns_info { + char *host_name; + char *server_name; + uint16 server_port; + unsigned long ipAddr; + char *txt_data[10]; +}; +#endif +//void mdns_enable(void); +//void mdns_disable(void); +//void mdns_init(struct mdns_info *info); +//void mdns_close(void); +//char* mdns_get_hostname(void); +//void mdns_set_hostname(char *name); +//void mdns_set_servername(const char *name); +//char* mdns_get_servername(void); +//void mdns_server_unregister(void); +//void mdns_server_register(void) ; +//void mdns_tmr(void); +//void Delay(unsigned long ulSeconds); + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mem.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mem.h new file mode 100644 index 0000000000..af6e3609a5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/mem.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" +//#include "mem_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include /* for size_t */ + +typedef size_t mem_size_t; + +/* aliases for C library malloc() */ +#define mem_init() +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef MEMLEAK_DEBUG +#ifndef mem_free +#define mem_free vPortFree +#endif +#ifndef mem_malloc +#define mem_malloc pvPortMalloc +#endif +#ifndef mem_calloc +#define mem_calloc pvPortCalloc +#endif +#ifndef mem_realloc +#define mem_realloc pvPortRealloc +#endif +#ifndef mem_zalloc +#define mem_zalloc pvPortZalloc +#endif +#else +#ifndef mem_free +#define mem_free(s) \ +do{\ + const char *file = mem_debug_file;\ + vPortFree(s, file, __LINE__);\ +}while(0) +#endif +#ifndef mem_malloc +#define mem_malloc(s) ({const char *file = mem_debug_file; pvPortMalloc(s, file, __LINE__);}) +#endif +#ifndef mem_calloc +#define mem_calloc(s) ({const char *file = mem_debug_file; pvPortCalloc(s, file, __LINE__);}) +#endif +#ifndef mem_realloc +#define mem_realloc(p, s) ({const char *file = mem_debug_file; pvPortRealloc(p, s, file, __LINE__);}) +#endif +#ifndef mem_zalloc +#define mem_zalloc(s) ({const char *file = mem_debug_file; pvPortZalloc(s, file, __LINE__);}) +#endif + +#endif + +#ifndef os_malloc +#define os_malloc(s) mem_malloc((s)) +#endif +#ifndef os_realloc +#define os_realloc(p, s) mem_realloc((p), (s)) +#endif +#ifndef os_zalloc +#define os_zalloc(s) mem_zalloc((s)) +#endif +#ifndef os_free +#define os_free(p) mem_free((p)) +#endif + +/* Since there is no C library allocation function to shrink memory without + moving it, define this to nothing. */ +#ifndef mem_trim +#define mem_trim(mem, size) (mem) +#endif +#else /* MEM_LIBC_MALLOC */ + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ + +#if MEM_USE_POOLS +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_trim is not used when using pools instead of a heap: + we can't free part of a pool element and don't want to copy the rest */ +#define mem_trim(mem, size) (mem) +#else /* MEM_USE_POOLS */ +/* lwIP alternative malloc */ +void mem_init(void)ICACHE_FLASH_ATTR; +void *mem_trim(void *mem, mem_size_t size)ICACHE_FLASH_ATTR; +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size)ICACHE_FLASH_ATTR; +void *mem_calloc(mem_size_t count, mem_size_t size)ICACHE_FLASH_ATTR; +void mem_free(void *mem)ICACHE_FLASH_ATTR; +#endif /* MEM_LIBC_MALLOC */ + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEM_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp.h new file mode 100644 index 0000000000..6a2127db23 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc, attr) MEMP_##name, +#include "lwip/memp_std.h" + MEMP_MAX +} memp_t; + +#if MEM_USE_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC || MEM_USE_POOLS +extern const u32_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#include "mem.h" + +#define memp_init() +#define memp_malloc(type) mem_malloc(memp_sizes[type]) +#define memp_free(type, mem) mem_free(mem) + +#else /* MEMP_MEM_MALLOC */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ + memp_t poolnr; +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void)ICACHE_FLASH_ATTR; + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line)ICACHE_FLASH_ATTR; +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type)ICACHE_FLASH_ATTR; +#endif +void memp_free(memp_t type, void *mem)ICACHE_FLASH_ATTR; + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp_std.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp_std.h new file mode 100644 index 0000000000..b20a240535 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/memp_std.h @@ -0,0 +1,126 @@ +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size, attr) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc, attr) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc, attr) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB", DMEM_ATTR) +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB", DMEM_ATTR) +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB", DMEM_ATTR) +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN", DMEM_ATTR) +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG", DMEM_ATTR) +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA", DMEM_ATTR) +#endif /* IP_REASSEMBLY */ +#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF", DMEM_ATTR) +#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +#if LWIP_NETCONN +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE", DMEM_ATTR) +#endif /* ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP", DMEM_ATTR) +#endif /* LWIP_IGMP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT", DMEM_ATTR) +#endif /* LWIP_TIMERS */ + +#if LWIP_SNMP +LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") +LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") +LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") +LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") +#endif /* LWIP_SNMP */ +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#if PPP_SUPPORT && PPPOE_SUPPORT +LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM", DMEM_ATTR) + +/* XXX: need to align to 4 byte as memp strcut is 4-byte long. otherwise will crash */ +#define LWIP_MEM_ALIGN4_SIZE(size) (((size) + 4 - 1) & ~(4-1)) + +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, LWIP_MEM_ALIGN4_SIZE(PBUF_POOL_BUFSIZE), "PBUF_POOL", DMEM_ATTR) + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netbuf.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netbuf.h new file mode 100644 index 0000000000..b554a579d4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netbuf.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETBUF_H__ +#define __LWIP_NETBUF_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void)ICACHE_FLASH_ATTR; +void netbuf_delete (struct netbuf *buf)ICACHE_FLASH_ATTR; +void * netbuf_alloc (struct netbuf *buf, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_free (struct netbuf *buf)ICACHE_FLASH_ATTR; +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_chain (struct netbuf *head, + struct netbuf *tail)ICACHE_FLASH_ATTR; + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len)ICACHE_FLASH_ATTR; +s8_t netbuf_next (struct netbuf *buf)ICACHE_FLASH_ATTR; +void netbuf_first (struct netbuf *buf)ICACHE_FLASH_ATTR; + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netdb.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netdb.h new file mode 100644 index 0000000000..7587e2f2d1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netdb.h @@ -0,0 +1,124 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef __LWIP_NETDB_H__ +#define __LWIP_NETDB_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include /* for size_t */ + +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessable error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +#define gethostbyname(name) lwip_gethostbyname(name) +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* __LWIP_NETDB_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netif.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netif.h new file mode 100644 index 0000000000..04e4f7a0a0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netif.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths + across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It is set by the startup code (for static IP configuration) or + * by dhcp/autoip when an address has been assigned. + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the netif is one end of a point-to-point connection. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_POINTTOPOINT 0x04U +/** If set, the interface is configured using DHCP. + * Set by the DHCP code when starting or stopping DHCP. */ +#define NETIF_FLAG_DHCP 0x08U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x10U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x20U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x40U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x80U + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr); +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + ip_addr_t *group, u8_t action); + +/*add DHCP event processing by LiuHan*/ +typedef void (*dhcp_event_fn)(void); + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { + /** pointer to next in linked list */ + struct netif *next; + + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; + + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. ÏòIP²ãÊäÈëÊý¾Ý°ü*/ + netif_input_fn input; + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. ·¢ËÍIPÊý¾Ý°ü*/ + netif_output_fn output; + /** This function is called by the ARP module when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. µ×²ãÊý¾Ý°ü·¢ËÍ*/ + netif_linkoutput_fn linkoutput; +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. ×ÔÓÉÉèÖÃ×ֶΣ¬±ÈÈçÖ¸Ïòµ×²ãÉ豸Ïà¹ØÐÅÏ¢*/ + void *state; +#if LWIP_DHCP + /** the DHCP client state information for this netif */ + struct dhcp *dhcp; + struct udp_pcb *dhcps_pcb; //dhcps + dhcp_event_fn dhcp_event; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /** the AutoIP client state information for this netif */ + struct autoip *autoip; +#endif +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ + /** maximum transfer unit (in bytes) ¸Ã½Ó¿ÚÔÊÐíµÄ×î´óÊý¾Ý°ü³¤¶È£¬¶àÊÇ1500*/ + u16_t mtu; + /** number of bytes used in hwaddr¸Ã½Ó¿ÚÎïÀíµØÖ·³¤¶È */ + u8_t hwaddr_len; + /** link level hardware address of this interface ¸Ã½Ó¿ÚÎïÀíµØÖ·*/ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** flags (see NETIF_FLAG_ above) ¸Ã½Ó¿Ú״̬¡¢ÊôÐÔ×Ö¶Î*/ + u8_t flags; + /** descriptive abbreviation ¸Ã½Ó¿ÚµÄÃû×Ö*/ + char name[2]; + /** number of this interface ¸Ã½Ó¿ÚµÄ±àºÅ*/ + u8_t num; +#if LWIP_SNMP + /** link type (from "snmp_ifType" enum from snmp.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + u32_t ifinoctets; + u32_t ifinucastpkts; + u32_t ifinnucastpkts; + u32_t ifindiscards; + u32_t ifoutoctets; + u32_t ifoutucastpkts; + u32_t ifoutnucastpkts; + u32_t ifoutdiscards; +#endif /* LWIP_SNMP */ +#if LWIP_IGMP + /** This function could be called to add or delete a entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. Ö¸Ïò·¢Ë͸ø×Ô¼ºµÄÊý¾Ý°üµÄpbuf*/ + struct pbuf *loop_first;//µÚÒ»¸ö + struct pbuf *loop_last;//×îºóÒ»¸ö +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_SNMP +#define NETIF_INIT_SNMP(netif, type, speed) \ + /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ + (netif)->link_type = (type); \ + /* your link speed here (units: bits per second) */ \ + (netif)->link_speed = (speed); \ + (netif)->ts = 0; \ + (netif)->ifinoctets = 0; \ + (netif)->ifinucastpkts = 0; \ + (netif)->ifinnucastpkts = 0; \ + (netif)->ifindiscards = 0; \ + (netif)->ifoutoctets = 0; \ + (netif)->ifoutucastpkts = 0; \ + (netif)->ifoutnucastpkts = 0; \ + (netif)->ifoutdiscards = 0 +#else /* LWIP_SNMP */ +#define NETIF_INIT_SNMP(netif, type, speed) +#endif /* LWIP_SNMP */ + + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void)ICACHE_FLASH_ATTR; + +struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)ICACHE_FLASH_ATTR; + +void +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw)ICACHE_FLASH_ATTR; +void netif_remove(struct netif * netif)ICACHE_FLASH_ATTR; + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(char *name)ICACHE_FLASH_ATTR; + +void netif_set_default(struct netif *netif)ICACHE_FLASH_ATTR; + +void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +void netif_set_netmask(struct netif *netif, ip_addr_t *netmask)ICACHE_FLASH_ATTR; +void netif_set_gw(struct netif *netif, ip_addr_t *gw)ICACHE_FLASH_ATTR; + +void netif_set_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if an interface is up */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +void netif_set_link_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_link_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip)ICACHE_FLASH_ATTR; +void netif_poll(struct netif *netif)ICACHE_FLASH_ATTR; +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void)ICACHE_FLASH_ATTR; +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETIF_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netifapi.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netifapi.h new file mode 100644 index 0000000000..33318efaf6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/netifapi.h @@ -0,0 +1,108 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef __LWIP_NETIFAPI_H__ +#define __LWIP_NETIFAPI_H__ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg_msg { +#if !LWIP_TCPIP_CORE_LOCKING + sys_sem_t sem; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + err_t err; + struct netif *netif; + union { + struct { + ip_addr_t *ipaddr; + ip_addr_t *netmask; + ip_addr_t *gw; + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + } msg; +}; + +struct netifapi_msg { + void (* function)(struct netifapi_msg_msg *msg); + struct netifapi_msg_msg msg; +}; + + +/* API for application */ +err_t netifapi_netif_add ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, + void *state, + netif_init_fn init, + netif_input_fn input); + +err_t netifapi_netif_set_addr ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw ); + +err_t netifapi_netif_common ( struct netif *netif, + netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/opt.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/opt.h new file mode 100644 index 0000000000..0d2b3fcc5f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/opt.h @@ -0,0 +1,2043 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you dont like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 1 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 0 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 0 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 3 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 50 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 30 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 2 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 3 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 16 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 0 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 0 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 0 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 0 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + * Does not have to be changed unless external MIBs answer request asynchronously + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 1 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * SNMP_PRIVATE_MIB: + * When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 256 +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +//#ifndef LWIP_EVENT_API +//#define LWIP_EVENT_API 0 +//#define LWIP_CALLBACK_API 1 +//#else +//#define LWIP_EVENT_API 1 +//#define LWIP_CALLBACK_API 0 +//#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 1 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 1 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else + +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/pbuf.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/pbuf.h new file mode 100644 index 0000000000..3d24db4d4b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/pbuf.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG */ +#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN 20 + +typedef enum { + PBUF_TRANSPORT, + PBUF_IP, + PBUF_LINK, + PBUF_RAW +} pbuf_layer; + +typedef enum { + PBUF_RAM, /* pbuf data is stored in RAM */ + PBUF_ROM, /* pbuf data is stored in ROM */ + PBUF_REF, /* pbuf comes from the pbuf pool */ + PBUF_POOL, /* pbuf payload refers to RAM */ +#ifdef EBUF_LWIP + PBUF_ESF_RX /* pbuf payload is from WLAN */ +#endif /* ESF_LWIP */ +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a + a pbuf differently */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U + +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** pbuf_type as u8_t instead of enum to save space */ + u8_t /*pbuf_type*/ type; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; + + /* add a pointer for esf_buf */ + void * eb; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)ICACHE_FLASH_ATTR; +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len)ICACHE_FLASH_ATTR; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size)ICACHE_FLASH_ATTR; +u8_t pbuf_header(struct pbuf *p, s16_t header_size)ICACHE_FLASH_ATTR; +void pbuf_ref(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_free(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_clen(struct pbuf *p)ICACHE_FLASH_ATTR; +void pbuf_cat(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +void pbuf_chain(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_dechain(struct pbuf *p)ICACHE_FLASH_ATTR; +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)ICACHE_FLASH_ATTR; +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)ICACHE_FLASH_ATTR; +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)ICACHE_FLASH_ATTR; +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +u8_t pbuf_get_at(struct pbuf* p, u16_t offset)ICACHE_FLASH_ATTR; +u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)ICACHE_FLASH_ATTR; +u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)ICACHE_FLASH_ATTR; +u16_t pbuf_strstr(struct pbuf* p, const char* substr)ICACHE_FLASH_ATTR; + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/puck_def.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/puck_def.h new file mode 100644 index 0000000000..c20027a15c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/puck_def.h @@ -0,0 +1,44 @@ +/* + * puck_def.h + * + * Created on: Jul 22, 2010 + * Author: dtoma + */ + +#ifndef PUCK_DEF_H_ +#define PUCK_DEF_H_ + + + +#define INSTRUMENT_PORT 8760 + +#define INSTRUMENT_LENGTH 80 + +#define MDNS_NAME_LENGTH 68 //68 + +char* PUCK_SERVICE = NULL; +//#define PUCK_SERVICE "_Escpressif._tcp.local" +#define DNS_SD_SERVICE "_services._dns-sd._udp.local" +#define SERVICE_DESCRIPTION "PUCK PROTOCOL" +#define PUCK_SERVICE_LENGTH 30 + +#define UUID_LEN 16 +#define DS_VERS_LEN 2 +#define DS_SIZE_LEN 2 +#define MAN_ID_LEN 4 +#define MAN_MODEL_LEN 2 +#define MAN_VERS_LEN 2 +#define SER_NUM_LEN 4 +#define NAME_LEN 64 +#define PUCK_DATASHEET_SIZE 96 + +#define UUID_OFFSET 0 +#define DS_VERS_OFFSET UUID_LEN + UUID_OFFSET +#define DS_SIZE_OFFSET DS_VERS_LEN + DS_VERS_OFFSET +#define MAN_ID_OFFSET DS_SIZE_LEN + DS_SIZE_OFFSET +#define MAN_MODEL_OFFSET MAN_ID_LEN + MAN_ID_OFFSET +#define MAN_VERS_OFFSET MAN_MODEL_LEN + MAN_MODEL_OFFSET +#define SER_NUM_OFFSET MAN_VERS_LEN + MAN_VERS_OFFSET +#define NAME_OFFSET SER_NUM_LEN + SER_NUM_OFFSET + +#endif /* __PUCK_DEF_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/raw.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/raw.h new file mode 100644 index 0000000000..c9c40871b1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/raw.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip_addr_t *addr); + +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto)ICACHE_FLASH_ATTR; +void raw_remove (struct raw_pcb *pcb)ICACHE_FLASH_ATTR; +err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)ICACHE_FLASH_ATTR; +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +#define raw_init() /* Compatibility define, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sio.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sio.h new file mode 100644 index 0000000000..228c857772 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sio.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef __SIO_H__ +#define __SIO_H__ + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __SIO_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp.h new file mode 100644 index 0000000000..2ed043dd5f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/ip_addr.h" + +struct udp_pcb; +struct netif; + +/** + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** SNMP "sysuptime" Interval */ +#define SNMP_SYSUPTIME_INTERVAL 10 + +/** fixed maximum length for object identifier type */ +#define LWIP_SNMP_OBJ_ID_LEN 32 + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + s32_t id[LWIP_SNMP_OBJ_ID_LEN]; +}; + +/* system */ +void snmp_set_sysdesr(u8_t* str, u8_t* len); +void snmp_set_sysobjid(struct snmp_obj_id *oid); +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); +void snmp_inc_sysuptime(void); +void snmp_add_sysuptime(u32_t value); +void snmp_get_sysuptime(u32_t *value); +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); + +/* network interface */ +void snmp_add_ifinoctets(struct netif *ni, u32_t value); +void snmp_inc_ifinucastpkts(struct netif *ni); +void snmp_inc_ifinnucastpkts(struct netif *ni); +void snmp_inc_ifindiscards(struct netif *ni); +void snmp_add_ifoutoctets(struct netif *ni, u32_t value); +void snmp_inc_ifoutucastpkts(struct netif *ni); +void snmp_inc_ifoutnucastpkts(struct netif *ni); +void snmp_inc_ifoutdiscards(struct netif *ni); +void snmp_inc_iflist(void); +void snmp_dec_iflist(void); + +/* ARP (for atTable and ipNetToMediaTable) */ +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipinhdrerrors(void); +void snmp_inc_ipinaddrerrors(void); +void snmp_inc_ipforwdatagrams(void); +void snmp_inc_ipinunknownprotos(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutnoroutes(void); +void snmp_inc_ipreasmreqds(void); +void snmp_inc_ipreasmoks(void); +void snmp_inc_ipreasmfails(void); +void snmp_inc_ipfragoks(void); +void snmp_inc_ipfragfails(void); +void snmp_inc_ipfragcreates(void); +void snmp_inc_iproutingdiscards(void); +void snmp_insert_ipaddridx_tree(struct netif *ni); +void snmp_delete_ipaddridx_tree(struct netif *ni); +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void); +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); +void snmp_insert_udpidx_tree(struct udp_pcb *pcb); +void snmp_delete_udpidx_tree(struct udp_pcb *pcb); + +/* SNMP */ +void snmp_inc_snmpinpkts(void); +void snmp_inc_snmpoutpkts(void); +void snmp_inc_snmpinbadversions(void); +void snmp_inc_snmpinbadcommunitynames(void); +void snmp_inc_snmpinbadcommunityuses(void); +void snmp_inc_snmpinasnparseerrs(void); +void snmp_inc_snmpintoobigs(void); +void snmp_inc_snmpinnosuchnames(void); +void snmp_inc_snmpinbadvalues(void); +void snmp_inc_snmpinreadonlys(void); +void snmp_inc_snmpingenerrs(void); +void snmp_add_snmpintotalreqvars(u8_t value); +void snmp_add_snmpintotalsetvars(u8_t value); +void snmp_inc_snmpingetrequests(void); +void snmp_inc_snmpingetnexts(void); +void snmp_inc_snmpinsetrequests(void); +void snmp_inc_snmpingetresponses(void); +void snmp_inc_snmpintraps(void); +void snmp_inc_snmpouttoobigs(void); +void snmp_inc_snmpoutnosuchnames(void); +void snmp_inc_snmpoutbadvalues(void); +void snmp_inc_snmpoutgenerrs(void); +void snmp_inc_snmpoutgetrequests(void); +void snmp_inc_snmpoutgetnexts(void); +void snmp_inc_snmpoutsetrequests(void); +void snmp_inc_snmpoutgetresponses(void); +void snmp_inc_snmpouttraps(void); +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); +void snmp_set_snmpenableauthentraps(u8_t *value); +void snmp_get_snmpenableauthentraps(u8_t *value); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* system */ +#define snmp_set_sysdesr(str, len) +#define snmp_set_sysobjid(oid); +#define snmp_get_sysobjid_ptr(oid) +#define snmp_inc_sysuptime() +#define snmp_add_sysuptime(value) +#define snmp_get_sysuptime(value) +#define snmp_set_syscontact(ocstr, ocstrlen); +#define snmp_set_sysname(ocstr, ocstrlen); +#define snmp_set_syslocation(ocstr, ocstrlen); + +/* network interface */ +#define snmp_add_ifinoctets(ni,value) +#define snmp_inc_ifinucastpkts(ni) +#define snmp_inc_ifinnucastpkts(ni) +#define snmp_inc_ifindiscards(ni) +#define snmp_add_ifoutoctets(ni,value) +#define snmp_inc_ifoutucastpkts(ni) +#define snmp_inc_ifoutnucastpkts(ni) +#define snmp_inc_ifoutdiscards(ni) +#define snmp_inc_iflist() +#define snmp_dec_iflist() + +/* ARP */ +#define snmp_insert_arpidx_tree(ni,ip) +#define snmp_delete_arpidx_tree(ni,ip) + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipinhdrerrors() +#define snmp_inc_ipinaddrerrors() +#define snmp_inc_ipforwdatagrams() +#define snmp_inc_ipinunknownprotos() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutnoroutes() +#define snmp_inc_ipreasmreqds() +#define snmp_inc_ipreasmoks() +#define snmp_inc_ipreasmfails() +#define snmp_inc_ipfragoks() +#define snmp_inc_ipfragfails() +#define snmp_inc_ipfragcreates() +#define snmp_inc_iproutingdiscards() +#define snmp_insert_ipaddridx_tree(ni) +#define snmp_delete_ipaddridx_tree(ni) +#define snmp_insert_iprteidx_tree(dflt, ni) +#define snmp_delete_iprteidx_tree(dflt, ni) + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors() +#define snmp_inc_icmpindestunreachs() +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs() +#define snmp_inc_icmpinsrcquenchs() +#define snmp_inc_icmpinredirects() +#define snmp_inc_icmpinechos() +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps() +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs() +#define snmp_inc_icmpouttimeexcds() +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects() +#define snmp_inc_icmpoutechos() +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() +#define snmp_insert_udpidx_tree(pcb) +#define snmp_delete_udpidx_tree(pcb) + +/* SNMP */ +#define snmp_inc_snmpinpkts() +#define snmp_inc_snmpoutpkts() +#define snmp_inc_snmpinbadversions() +#define snmp_inc_snmpinbadcommunitynames() +#define snmp_inc_snmpinbadcommunityuses() +#define snmp_inc_snmpinasnparseerrs() +#define snmp_inc_snmpintoobigs() +#define snmp_inc_snmpinnosuchnames() +#define snmp_inc_snmpinbadvalues() +#define snmp_inc_snmpinreadonlys() +#define snmp_inc_snmpingenerrs() +#define snmp_add_snmpintotalreqvars(value) +#define snmp_add_snmpintotalsetvars(value) +#define snmp_inc_snmpingetrequests() +#define snmp_inc_snmpingetnexts() +#define snmp_inc_snmpinsetrequests() +#define snmp_inc_snmpingetresponses() +#define snmp_inc_snmpintraps() +#define snmp_inc_snmpouttoobigs() +#define snmp_inc_snmpoutnosuchnames() +#define snmp_inc_snmpoutbadvalues() +#define snmp_inc_snmpoutgenerrs() +#define snmp_inc_snmpoutgetrequests() +#define snmp_inc_snmpoutgetnexts() +#define snmp_inc_snmpoutsetrequests() +#define snmp_inc_snmpoutgetresponses() +#define snmp_inc_snmpouttraps() +#define snmp_get_snmpgrpid_ptr(oid) +#define snmp_set_snmpenableauthentraps(value) +#define snmp_get_snmpenableauthentraps(value) + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_asn1.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_asn1.h new file mode 100644 index 0000000000..605fa3f16c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_asn1.h @@ -0,0 +1,101 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_ASN1_H__ +#define __LWIP_SNMP_ASN1_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" + +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ +#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ +#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ + +#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ +#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ + +/* universal tags */ +#define SNMP_ASN1_INTEG 2 +#define SNMP_ASN1_OC_STR 4 +#define SNMP_ASN1_NUL 5 +#define SNMP_ASN1_OBJ_ID 6 +#define SNMP_ASN1_SEQ 16 + +/* application specific (SNMP) tags */ +#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */ +#define SNMP_ASN1_COUNTER 1 /* u32_t */ +#define SNMP_ASN1_GAUGE 2 /* u32_t */ +#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ +#define SNMP_ASN1_OPAQUE 4 /* octet string */ + +/* context specific (SNMP) tags */ +#define SNMP_ASN1_PDU_GET_REQ 0 +#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_PDU_GET_RESP 2 +#define SNMP_ASN1_PDU_SET_REQ 3 +#define SNMP_ASN1_PDU_TRAP 4 + +err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); +err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); +err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); +err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); +err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); +err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); +err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_msg.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_msg.h new file mode 100644 index 0000000000..1183e3a95b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_msg.h @@ -0,0 +1,315 @@ +/** + * @file + * SNMP Agent message handling structures. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_MSG_H__ +#define __LWIP_SNMP_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/snmp.h" +#include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#if LWIP_SNMP + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to + this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't + work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +#define SNMP_ES_NOERROR 0 +#define SNMP_ES_TOOBIG 1 +#define SNMP_ES_NOSUCHNAME 2 +#define SNMP_ES_BADVALUE 3 +#define SNMP_ES_READONLY 4 +#define SNMP_ES_GENERROR 5 + +#define SNMP_GENTRAP_COLDSTART 0 +#define SNMP_GENTRAP_WARMSTART 1 +#define SNMP_GENTRAP_AUTHFAIL 4 +#define SNMP_GENTRAP_ENTERPRISESPC 6 + +struct snmp_varbind +{ + /* next pointer, NULL for last in list */ + struct snmp_varbind *next; + /* previous pointer, NULL for first in list */ + struct snmp_varbind *prev; + + /* object identifier length (in s32_t) */ + u8_t ident_len; + /* object identifier array */ + s32_t *ident; + + /* object value ASN1 type */ + u8_t value_type; + /* object value length (in u8_t) */ + u8_t value_len; + /* object value */ + void *value; + + /* encoding varbind seq length length */ + u8_t seqlenlen; + /* encoding object identifier length length */ + u8_t olenlen; + /* encoding object value length length */ + u8_t vlenlen; + /* encoding varbind seq length */ + u16_t seqlen; + /* encoding object identifier length */ + u16_t olen; + /* encoding object value length */ + u16_t vlen; +}; + +struct snmp_varbind_root +{ + struct snmp_varbind *head; + struct snmp_varbind *tail; + /* number of variable bindings in list */ + u8_t count; + /* encoding varbind-list seq length length */ + u8_t seqlenlen; + /* encoding varbind-list seq length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_resp_header_lengths +{ + /* encoding error-index length length */ + u8_t erridxlenlen; + /* encoding error-status length length */ + u8_t errstatlenlen; + /* encoding request id length length */ + u8_t ridlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding error-index length */ + u16_t erridxlen; + /* encoding error-status length */ + u16_t errstatlen; + /* encoding request id length */ + u16_t ridlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_trap_header_lengths +{ + /* encoding timestamp length length */ + u8_t tslenlen; + /* encoding specific-trap length length */ + u8_t strplenlen; + /* encoding generic-trap length length */ + u8_t gtrplenlen; + /* encoding agent-addr length length */ + u8_t aaddrlenlen; + /* encoding enterprise-id length length */ + u8_t eidlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding timestamp length */ + u16_t tslen; + /* encoding specific-trap length */ + u16_t strplen; + /* encoding generic-trap length */ + u16_t gtrplen; + /* encoding agent-addr length */ + u16_t aaddrlen; + /* encoding enterprise-id length */ + u16_t eidlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/* Accepting new SNMP messages. */ +#define SNMP_MSG_EMPTY 0 +/* Search for matching object for variable binding. */ +#define SNMP_MSG_SEARCH_OBJ 1 +/* Perform SNMP operation on in-memory object. + Pass-through states, for symmetry only. */ +#define SNMP_MSG_INTERNAL_GET_OBJDEF 2 +#define SNMP_MSG_INTERNAL_GET_VALUE 3 +#define SNMP_MSG_INTERNAL_SET_TEST 4 +#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 +#define SNMP_MSG_INTERNAL_SET_VALUE 6 +/* Perform SNMP operation on object located externally. + In theory this could be used for building a proxy agent. + Practical use is for an enterprise spc. app. gateway. */ +#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7 +#define SNMP_MSG_EXTERNAL_GET_VALUE 8 +#define SNMP_MSG_EXTERNAL_SET_TEST 9 +#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 +#define SNMP_MSG_EXTERNAL_SET_VALUE 11 + +#define SNMP_COMMUNITY_STR_LEN 64 +struct snmp_msg_pstat +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* source IP address */ + ip_addr_t sip; + /* source UDP port */ + u16_t sp; + /* request type */ + u8_t rt; + /* request ID */ + s32_t rid; + /* error status */ + s32_t error_status; + /* error index */ + s32_t error_index; + /* community name (zero terminated) */ + u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; + /* community string length (exclusive zero term) */ + u8_t com_strlen; + /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ + u8_t state; + /* saved arguments for MSG_EXTERNAL_x */ + struct mib_external_node *ext_mib_node; + struct snmp_name_ptr ext_name_ptr; + struct obj_def ext_object_def; + struct snmp_obj_id ext_oid; + /* index into input variable binding list */ + u8_t vb_idx; + /* ptr into input variable binding list */ + struct snmp_varbind *vb_ptr; + /* list of variable bindings from input */ + struct snmp_varbind_root invb; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output response lengths used in ASN encoding */ + struct snmp_resp_header_lengths rhl; +}; + +struct snmp_msg_trap +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* destination IP address in network order */ + ip_addr_t dip; + + /* source enterprise ID (sysObjectID) */ + struct snmp_obj_id *enterprise; + /* source IP address, raw network order format */ + u8_t sip_raw[4]; + /* generic trap code */ + u32_t gen_trap; + /* specific trap code */ + u32_t spc_trap; + /* timestamp */ + u32_t ts; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output trap lengths used in ASN encoding */ + struct snmp_trap_header_lengths thl; +}; + +/** Agent Version constant, 0 = v1 oddity */ +extern const s32_t snmp_version; +/** Agent default "public" community string */ +extern const char snmp_publiccommunity[7]; + +extern struct snmp_msg_trap trap_msg; + +/** Agent setup, start listening to port 161. */ +void snmp_init(void); +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); + +/** Varbind-list functions. */ +struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); +void snmp_varbind_free(struct snmp_varbind *vb); +void snmp_varbind_list_free(struct snmp_varbind_root *root); +void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); +struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); + +/** Handle an internal (recv) or external (private response) event. */ +void snmp_msg_event(u8_t request_id); +err_t snmp_send_response(struct snmp_msg_pstat *m_stat); +err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_structs.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_structs.h new file mode 100644 index 0000000000..0d3b46a928 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/snmp_structs.h @@ -0,0 +1,268 @@ +/** + * @file + * Generic MIB tree structures. + * + * @todo namespace prefixes + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_STRUCTS_H__ +#define __LWIP_SNMP_STRUCTS_H__ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MIB object instance */ +#define MIB_OBJECT_NONE 0 +#define MIB_OBJECT_SCALAR 1 +#define MIB_OBJECT_TAB 2 + +/* MIB access types */ +#define MIB_ACCESS_READ 1 +#define MIB_ACCESS_WRITE 2 + +/* MIB object access */ +#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ +#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) +#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE +#define MIB_OBJECT_NOT_ACCESSIBLE 0 + +/** object definition returned by (get_object_def)() */ +struct obj_def +{ + /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ + u8_t instance; + /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ + u8_t access; + /* ASN type for this object */ + u8_t asn_type; + /* value length (host length) */ + u16_t v_len; + /* length of instance part of supplied object identifier */ + u8_t id_inst_len; + /* instance part of supplied object identifier */ + s32_t *id_inst_ptr; +}; + +struct snmp_name_ptr +{ + u8_t ident_len; + s32_t *ident; +}; + +/** MIB const scalar (.0) node */ +#define MIB_NODE_SC 0x01 +/** MIB const array node */ +#define MIB_NODE_AR 0x02 +/** MIB array node (mem_malloced from RAM) */ +#define MIB_NODE_RA 0x03 +/** MIB list root node (mem_malloced from RAM) */ +#define MIB_NODE_LR 0x04 +/** MIB node for external objects */ +#define MIB_NODE_EX 0x05 + +/** node "base class" layout, the mandatory fields for a node */ +struct mib_node +{ + /** returns struct obj_def for the given object identifier */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + /** returns object value for the given object identifier, + @note the caller must allocate at least len bytes for the value */ + void (*get_value)(struct obj_def *od, u16_t len, void *value); + /** tests length and/or range BEFORE setting */ + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + /** sets object value, only to be called when set_test() */ + void (*set_value)(struct obj_def *od, u16_t len, void *value); + /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ + u8_t node_type; + /* array or max list length */ + u16_t maxlength; +}; + +/** derived node for scalars .0 index */ +typedef struct mib_node mib_scalar_node; + +/** derived node, points to a fixed size const array + of sub-identifiers plus a 'child' pointer */ +struct mib_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + const s32_t *objid; + struct mib_node* const *nptr; +}; + +/** derived node, points to a fixed size mem_malloced array + of sub-identifiers plus a 'child' pointer */ +struct mib_ram_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* aditional struct members */ + s32_t *objid; + struct mib_node **nptr; +}; + +struct mib_list_node +{ + struct mib_list_node *prev; + struct mib_list_node *next; + s32_t objid; + struct mib_node *nptr; +}; + +/** derived node, points to a doubly linked list + of sub-identifiers plus a 'child' pointer */ +struct mib_list_rootnode +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + struct mib_list_node *head; + struct mib_list_node *tail; + /* counts list nodes in list */ + u16_t count; +}; + +/** derived node, has access functions for mib object in external memory or device + using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ +struct mib_external_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + /** points to an external (in memory) record of some sort of addressing + information, passed to and interpreted by the funtions below */ + void* addr_inf; + /** tree levels under this node */ + u8_t tree_levels; + /** number of objects at this level */ + u16_t (*level_length)(void* addr_inf, u8_t level); + /** compares object sub identifier with external id + return zero when equal, nonzero when unequal */ + s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); + void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); + + /** async Questions */ + void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_q)(u8_t rid, struct obj_def *od); + void (*set_test_q)(u8_t rid, struct obj_def *od); + void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Answers */ + void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Panic Close (agent returns error reply, + e.g. used for external transaction cleanup) */ + void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_pc)(u8_t rid, struct obj_def *od); + void (*set_test_pc)(u8_t rid, struct obj_def *od); + void (*set_value_pc)(u8_t rid, struct obj_def *od); +}; + +/** export MIB tree from mib2.c */ +extern const struct mib_array_node internet; + +/** dummy function pointers for non-leaf MIB nodes from mib2.c */ +void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +void noleafs_get_value(struct obj_def *od, u16_t len, void *value); +u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); +void noleafs_set_value(struct obj_def *od, u16_t len, void *value); + +void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); +void snmp_iptooid(ip_addr_t *ip, s32_t *ident); +void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); +void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); + +struct mib_list_node* snmp_mib_ln_alloc(s32_t id); +void snmp_mib_ln_free(struct mib_list_node *ln); +struct mib_list_rootnode* snmp_mib_lrn_alloc(void); +void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); + +s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); +s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); +struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); + +struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); +struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); +u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); +u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sntp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sntp.h new file mode 100644 index 0000000000..d6018ae036 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sntp.h @@ -0,0 +1,60 @@ +#ifndef LWIP_SNTP_H +#define LWIP_SNTP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** The maximum number of SNTP servers that can be set */ +#ifndef SNTP_MAX_SERVERS +#define SNTP_MAX_SERVERS 3 +#endif + +/** Set this to 1 to implement the callback function called by dhcp when + * NTP servers are received. */ +#ifndef SNTP_GET_SERVERS_FROM_DHCP +#define SNTP_GET_SERVERS_FROM_DHCP 0//LWIP_DHCP_GET_NTP_SRV +#endif + +/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */ +#ifndef SNTP_SERVER_DNS +#define SNTP_SERVER_DNS 1 +#endif + +bool sntp_get_timetype(void); +void sntp_set_receive_time_size(void); +/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * #define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +uint64 sntp_get_current_timestamp(); +char* sntp_get_real_time(long t); + +void sntp_init(void); +void sntp_stop(void); + +sint8 sntp_get_timezone(void); +bool sntp_set_timezone(sint8 timezone); +void sntp_setserver(u8_t idx, ip_addr_t *addr); +ip_addr_t sntp_getserver(u8_t idx); + +#if SNTP_SERVER_DNS +void sntp_setservername(u8_t idx, char *server); +char *sntp_getservername(u8_t idx); +#endif /* SNTP_SERVER_DNS */ + +#if SNTP_GET_SERVERS_FROM_DHCP +void sntp_servermode_dhcp(int set_servers_from_dhcp); +#else /* SNTP_GET_SERVERS_FROM_DHCP */ +#define sntp_servermode_dhcp(x) +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNTP_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sockets.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sockets.h new file mode 100644 index 0000000000..3c8fed24e6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sockets.h @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + u8_t sin_family; + u16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr { + u8_t sa_len; + u8_t sa_family; + char sa_data[14]; +}; + +#ifndef socklen_t +# define socklen_t u32_t +#endif + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ + +#define SO_DONTLINGER ((int)(~SO_LINGER)) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define IPPROTO_UDPLITE 136 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET + #undef FD_SETSIZE + /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ + #define FD_SETSIZE MEMP_NUM_NETCONN + #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) + #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) + #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) + #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) + + typedef struct fd_set { + unsigned char fd_bits [(FD_SETSIZE+7)/8]; + } fd_set; + +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define shutdown(a,b) lwip_shutdown(a,b) +#define closesocket(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#define getsockname(a,b,c) lwip_getsockname(a,b,c) +#define getpeername(a,b,c) lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b) lwip_listen(a,b) +#define recv(a,b,c,d) lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket(a,b,c) +#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c) lwip_read(a,b,c) +#define write(a,b,c) lwip_write(a,b,c) +#define close(s) lwip_close(s) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/stats.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/stats.h new file mode 100644 index 0000000000..43883217ec --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/stats.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +struct stats_mem { +#ifdef LWIP_DEBUG + const char *name; +#endif /* LWIP_DEBUG */ + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER err; + STAT_COUNTER illegal; +}; + +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +struct stats_ { +#if LINK_STATS + struct stats_proto link; +#endif +#if ETHARP_STATS + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + struct stats_proto ip_frag; +#endif +#if IP_STATS + struct stats_proto ip; +#endif +#if ICMP_STATS + struct stats_proto icmp; +#endif +#if IGMP_STATS + struct stats_igmp igmp; +#endif +#if UDP_STATS + struct stats_proto udp; +#endif +#if TCP_STATS + struct stats_proto tcp; +#endif +#if MEM_STATS + struct stats_mem mem; +#endif +#if MEMP_STATS + struct stats_mem memp[MEMP_MAX]; +#endif +#if SYS_STATS + struct stats_sys sys; +#endif +}; + +extern struct stats_ lwip_stats; + +void stats_init(void)ICACHE_FLASH_ATTR; + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void)ICACHE_FLASH_ATTR; +void stats_display_proto(struct stats_proto *proto, char *name)ICACHE_FLASH_ATTR; +void stats_display_igmp(struct stats_igmp *igmp)ICACHE_FLASH_ATTR; +void stats_display_mem(struct stats_mem *mem, char *name)ICACHE_FLASH_ATTR; +void stats_display_memp(struct stats_mem *mem, int index)ICACHE_FLASH_ATTR; +void stats_display_sys(struct stats_sys *sys)ICACHE_FLASH_ATTR; +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_STATS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sys.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sys.h new file mode 100644 index 0000000000..31a9dea741 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/sys.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "lwip/opt.h" + +#include "eagle_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** Set a mutex invalid so that sys_mutex_valid returns 0 */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** Signals a semaphore + * @param sem the semaphore to signal */ +void sys_sem_signal(sys_sem_t *sem); +/** Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** Delete a semaphore + * @param sem semaphore to delete */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** Set a semaphore invalid so that sys_sem_valid returns 0 */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif + +/* Mailbox functions. */ + +/** Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (miminum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** For now, we map straight to sys_arch implementation. */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** Delete an mbox + * @param mbox mbox to delete */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** Set an mbox invalid so that sys_mbox_valid returns 0 */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif + +/** The only thread function: + * Creates a new thread + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/* sys_init() must be called before anthing else. */ +void sys_init(void)ICACHE_FLASH_ATTR; + +#ifndef sys_jiffies +/** Ticks/jiffies since power up. */ +u32_t sys_jiffies(void)ICACHE_FLASH_ATTR; +#endif + +/** Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. */ +static inline u32_t sys_now(void) ICACHE_FLASH_ATTR; +static inline u32_t sys_now(void) +{ + return NOW()/(TIMER_CLK_FREQ/1000); +} + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void)ICACHE_FLASH_ATTR; +void sys_arch_unprotect(sys_prot_t pval)ICACHE_FLASH_ATTR; + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) lev = os_intr_lock() //fix by ives at 2014.3.24 +#define SYS_ARCH_UNPROTECT(lev) lev = os_intr_unlock() + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SYS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp.h new file mode 100644 index 0000000000..909ff9b70b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) TODO! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. + * @param arg user-supplied argument (tcp_pcb.callback_arg) + * @param pcb a new tcp_pcb that now is connected + * @param err an error argument (TODO: that is current always ERR_OK?) + * @return ERR_OK: accept the new connection, + * any other err_t abortsthe new connection + */ +#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + void *callback_arg; \ + /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ + DEF_ACCEPT_CALLBACK \ + /* ports are in host byte order */ \ + u16_t local_port + + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + u8_t flags; +#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */ +#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ +#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ +#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ +#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */ +#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + u16_t rcv_wnd; /* receiver window available */ + u16_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + + /* Timers */ + u32_t tmr; + u8_t polltmr, pollinterval; + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + s16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u32_t lastack; /* Highest acknowledged seqno. */ + u8_t dupacks; + + /* congestion avoidance/control variables */ + u16_t cwnd; + u16_t ssthresh; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u16_t snd_wnd; /* sender window */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + + u16_t acked; + + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) + u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u32_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; +}; + +struct tcp_pcb_listen { +/* Common members of all PCB types */ + IP_PCB; +/* Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void)ICACHE_FLASH_ATTR; + +void tcp_arg (struct tcp_pcb *pcb, void *arg) ICACHE_FLASH_ATTR; +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept) ICACHE_FLASH_ATTR; +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv) ICACHE_FLASH_ATTR; +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent)ICACHE_FLASH_ATTR; +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)ICACHE_FLASH_ATTR; +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err)ICACHE_FLASH_ATTR; + +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#define tcp_sndbuf(pcb) ((pcb)->snd_buf) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) + +#if TCP_LISTEN_BACKLOG +#define tcp_accepted(pcb) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ + (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ + pcb->state == LISTEN) +#endif /* TCP_LISTEN_BACKLOG */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len)ICACHE_FLASH_ATTR; +err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected)ICACHE_FLASH_ATTR; + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)ICACHE_FLASH_ATTR; +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_close (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)ICACHE_FLASH_ATTR; + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags)ICACHE_FLASH_ATTR; + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio)ICACHE_FLASH_ATTR; + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +extern err_t tcp_output(struct tcp_pcb *pcb); + + +const char* tcp_debug_state_str(enum tcp_state s)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp_impl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp_impl.h new file mode 100644 index 0000000000..24ca8bb958 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcp_impl.h @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_IMPL_H__ +#define __LWIP_TCP_IMPL_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, no init needed. */ +void tcp_tmr (void)ICACHE_FLASH_ATTR; /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void)ICACHE_FLASH_ATTR; +void tcp_fasttmr (void)ICACHE_FLASH_ATTR; + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio)ICACHE_FLASH_ATTR; +void tcp_abandon (struct tcp_pcb *pcb, int reset)ICACHE_FLASH_ATTR; +err_t tcp_send_empty_ack(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_rto (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_fast (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 125 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 120000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 10000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); //Դ�˿� + PACK_STRUCT_FIELD(u16_t dest); //Ŀ�Ķ˿� + PACK_STRUCT_FIELD(u32_t seqno); //��� + PACK_STRUCT_FIELD(u32_t ackno); //Ӧ����� + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//�ײ�����+����λ+��־λ + PACK_STRUCT_FIELD(u16_t wnd); //���ڴ�С + PACK_STRUCT_FIELD(u16_t chksum); //��� + PACK_STRUCT_FIELD(u16_t urgp); //����ָ�� +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ + LWIP_EVENT_ERR, NULL, 0, (err)) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + do { \ + if((pcb)->accept != NULL) \ + (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(errf,arg,err) \ + do { \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segements on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + void *dataptr; /* pointer to the TCP data in the pbuf */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversized only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ + (flags & TF_SEG_OPTS_TS ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ + ((u32_t)4 << 16) | \ + (((u32_t)TCP_MSS / 256) << 8) | \ + (TCP_MSS & 255)) + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for(tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_purge(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +void tcp_segs_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +void tcp_seg_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)ICACHE_FLASH_ATTR; + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +void tcp_rst(u32_t seqno, u32_t ackno, + ip_addr_t *local_ip, ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port)ICACHE_FLASH_ATTR; + +u32_t tcp_next_iss(void)ICACHE_FLASH_ATTR; + +void tcp_keepalive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_zero_window_probe(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)ICACHE_FLASH_ATTR; +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)ICACHE_FLASH_ATTR; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr)ICACHE_FLASH_ATTR; +void tcp_debug_print_flags(u8_t flags)ICACHE_FLASH_ATTR; +void tcp_debug_print_state(enum tcp_state s)ICACHE_FLASH_ATTR; +void tcp_debug_print_pcbs(void)ICACHE_FLASH_ATTR; +s16_t tcp_pcbs_sane(void)ICACHE_FLASH_ATTR; +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcpip.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcpip.h new file mode 100644 index 0000000000..995ba8ad00 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/tcpip.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" +#include "lwip/netifapi.h" +#include "lwip/pbuf.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. */ +#ifndef LWIP_TCPIP_THREAD_ALIVE +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m) +#define TCPIP_APIMSG_ACK(m) +#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) +#define TCPIP_NETIFAPI_ACK(m) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#define TCPIP_APIMSG(m) tcpip_apimsg(m) +#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) +#define TCPIP_NETIFAPI(m) tcpip_netifapi(m) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_apimsg_lock(struct api_msg *apimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +#if LWIP_NETIF_API +err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT */ + +enum tcpip_msg_type { +#if LWIP_NETCONN + TCPIP_MSG_API, +#endif /* LWIP_NETCONN */ + TCPIP_MSG_INPKT, +#if LWIP_NETIF_API + TCPIP_MSG_NETIFAPI, +#endif /* LWIP_NETIF_API */ +#if LWIP_TCPIP_TIMEOUT + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT */ + TCPIP_MSG_CALLBACK +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + sys_sem_t *sem; + union { +#if LWIP_NETCONN + struct api_msg *apimsg; +#endif /* LWIP_NETCONN */ +#if LWIP_NETIF_API + struct netifapi_msg *netifapimsg; +#endif /* LWIP_NETIF_API */ + struct { + struct pbuf *p; + struct netif *netif; + } inp; + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/timers.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/timers.h new file mode 100644 index 0000000000..e9db02a2f4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/timers.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef __LWIP_TIMERS_H__ +#define __LWIP_TIMERS_H__ + +#include "lwip/opt.h" + +/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) + +#if LWIP_TIMERS + +#include "lwip/err.h" +#include "lwip/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void)ICACHE_FLASH_ATTR; + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)ICACHE_FLASH_ATTR; +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#if NO_SYS +void sys_check_timeouts(void)ICACHE_FLASH_ATTR; +void sys_restart_timeouts(void)ICACHE_FLASH_ATTR; +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TIMERS */ +#endif /* __LWIP_TIMERS_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/udp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/udp.h new file mode 100644 index 0000000000..cb53d33e70 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwip/udp.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf + * makes 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *addr, u16_t port); + + +struct udp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_IGMP + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; +#endif /* LWIP_IGMP */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void)ICACHE_FLASH_ATTR; +void udp_remove (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +void udp_disconnect (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg)ICACHE_FLASH_ATTR; +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif)ICACHE_FLASH_ATTR; +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port)ICACHE_FLASH_ATTR; +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p)ICACHE_FLASH_ATTR; + +#if LWIP_CHECKSUM_ON_COPY +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; + +#define udp_init() /* Compatibility define, not init needed. */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr)ICACHE_FLASH_ATTR; +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwipopts.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwipopts.h new file mode 100644 index 0000000000..0a0fcfcf68 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/lwipopts.h @@ -0,0 +1,2068 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#define ESP_SYSTEM_APP 1 +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 0 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 1 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 1 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 16000 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 1 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 1 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 10 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 0 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 0 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 10 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 8 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 0 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 0 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 4 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 0 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 0 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 0 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 0 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 0 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 0 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 0 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 10 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 1 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 1 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 0 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 1 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 128 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 1 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * DHCP_MAXRTX: Maximum number of retries of current request. + */ +#ifndef DHCP_MAXRTX +#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 0 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 0 +#endif + +/** + * SNMP_PRIVATE_MIB: + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 0 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 1 +#endif +/* + ---------------------------------- + ---------- MDNS options ---------- + ---------------------------------- +*/ +/** + * LWIP_MDNS==1: Turn on MDNS module. + */ +#ifndef LWIP_MDNS +#define LWIP_MDNS 1 +#endif +/* +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 1 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) +#endif + +/** + * TCP_MAXRTO: Maximum retransmission timeout of data segments. + */ +#ifndef TCP_MAXRTO +#define TCP_MAXRTO 10 +#endif + +/** + * TCP_MINRTO: Minimum retransmission timeout of data segments. + */ +#ifndef TCP_MINRTO +#define TCP_MINRTO 2 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 1 +#endif + +#if 1 +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 1460 +#endif +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (*(volatile uint32*)0x600011F0) +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 2 * TCP_MSS +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#define LWIP_EVENT_API 1 +#define LWIP_CALLBACK_API 0 +#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 1 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 0 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 0 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 1 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 0 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else +#define ETHARP_STATS 0 +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aes.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aes.h new file mode 100644 index 0000000000..a36e825a2e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aes.h @@ -0,0 +1,297 @@ +/** + * \file aes.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_AES_H +#define MBEDTLS_AES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* padlock.c and aesni.c rely on these values! */ +#define MBEDTLS_AES_ENCRYPT 1 +#define MBEDTLS_AES_DECRYPT 0 + +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES context structure + * + * \note buf is able to hold 32 extra bytes, which can be used: + * - for alignment purposes if VIA padlock is used, and/or + * - to simplify key expansion in the 256-bit case by + * generating an extra round key + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ + uint32_t buf[68]; /*!< unaligned data */ +} +mbedtls_aes_context; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + */ +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + */ +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aesni.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aesni.h new file mode 100644 index 0000000000..b1b7f1cdec --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/aesni.h @@ -0,0 +1,111 @@ +/** + * \file aesni.h + * + * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_AESNI_H +#define MBEDTLS_AESNI_H + +#include "aes.h" + +#define MBEDTLS_AESNI_AES 0x02000000u +#define MBEDTLS_AESNI_CLMUL 0x00000002u + +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \ + ( defined(__amd64__) || defined(__x86_64__) ) && \ + ! defined(MBEDTLS_HAVE_X86_64) +#define MBEDTLS_HAVE_X86_64 +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES-NI features detection routine + * + * \param what The feature to detect + * (MBEDTLS_AESNI_AES or MBEDTLS_AESNI_CLMUL) + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_aesni_has_support( unsigned int what ); + +/** + * \brief AES-NI AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 on success (cannot fail) + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief GCM multiplication: c = a * b in GF(2^128) + * + * \param c Result + * \param a First operand + * \param b Second operand + * + * \note Both operands and result are bit strings interpreted as + * elements of GF(2^128) as per the GCM spec. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ); + +/** + * \brief Compute decryption round keys from encryption round keys + * + * \param invkey Round keys for the equivalent inverse cipher + * \param fwdkey Original round keys (for encryption) + * \param nr Number of rounds (that is, number of round keys minus one) + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, int nr ); + +/** + * \brief Perform key expansion (for encryption) + * + * \param rk Destination buffer where the round keys are written + * \param key Encryption key + * \param bits Key size in bits (must be 128, 192 or 256) + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/arc4.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/arc4.h new file mode 100644 index 0000000000..5fc5395a8c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/arc4.h @@ -0,0 +1,113 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ARC4_H +#define MBEDTLS_ARC4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +mbedtls_arc4_context; + +/** + * \brief Initialize ARC4 context + * + * \param ctx ARC4 context to be initialized + */ +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ); + +/** + * \brief Clear ARC4 context + * + * \param ctx ARC4 context to be cleared + */ +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ); + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be setup + * \param key the secret key + * \param keylen length of the key, in bytes + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1.h new file mode 100644 index 0000000000..082832c87f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1.h @@ -0,0 +1,342 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_H +#define MBEDTLS_ASN1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "bignum.h" +#endif + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::mbedtls_x509_buf. + * \{ + */ +#define MBEDTLS_ASN1_BOOLEAN 0x01 +#define MBEDTLS_ASN1_INTEGER 0x02 +#define MBEDTLS_ASN1_BIT_STRING 0x03 +#define MBEDTLS_ASN1_OCTET_STRING 0x04 +#define MBEDTLS_ASN1_NULL 0x05 +#define MBEDTLS_ASN1_OID 0x06 +#define MBEDTLS_ASN1_UTF8_STRING 0x0C +#define MBEDTLS_ASN1_SEQUENCE 0x10 +#define MBEDTLS_ASN1_SET 0x11 +#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13 +#define MBEDTLS_ASN1_T61_STRING 0x14 +#define MBEDTLS_ASN1_IA5_STRING 0x16 +#define MBEDTLS_ASN1_UTC_TIME 0x17 +#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18 +#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C +#define MBEDTLS_ASN1_BMP_STRING 0x1E +#define MBEDTLS_ASN1_PRIMITIVE 0x00 +#define MBEDTLS_ASN1_CONSTRUCTED 0x20 +#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80 +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1) + +/** + * Compares an mbedtls_asn1_buf structure to a reference OID. + * + * Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a + * 'unsigned char *oid' here! + */ +#define MBEDTLS_OID_CMP(oid_str, oid_buf) \ + ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct mbedtls_asn1_buf +{ + int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +mbedtls_asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct mbedtls_asn1_bitstring +{ + size_t len; /**< ASN1 length, in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +mbedtls_asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct mbedtls_asn1_sequence +{ + mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */ +} +mbedtls_asn1_sequence; + +/** + * Container for a sequence or list of 'named' ASN.1 data items + */ +typedef struct mbedtls_asn1_named_data +{ + mbedtls_asn1_buf oid; /**< The object identifier. */ + mbedtls_asn1_buf val; /**< The named value. */ + struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */ + unsigned char next_merged; /**< Merge next item into the current one? */ +} +mbedtls_asn1_named_data; + +/** + * \brief Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * \brief Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * \brief Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs); + +/** + * \brief Retrieve a bitstring ASN.1 tag without unused bits and its + * value. + * Updates the pointer to the beginning of the bit/octet string. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len Length of the actual bit/octect string in bytes + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ); + +/** + * \brief Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * \param params The buffer to receive the params (if any) + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ); + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no + * params. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ); + +/** + * \brief Find a specific named_data entry in a sequence or list based on + * the OID. + * + * \param list The list to seek through + * \param oid The OID to look for + * \param len Size of the OID + * + * \return NULL if not found, or a pointer to the existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ); + +/** + * \brief Free a mbedtls_asn1_named_data entry + * + * \param entry The named data entry to free + */ +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry ); + +/** + * \brief Free all entries in a mbedtls_asn1_named_data list + * Head will be set to NULL + * + * \param head Pointer to the head of the list of named data entries to free + */ +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ); + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1write.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1write.h new file mode 100644 index 0000000000..73ff32b669 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/asn1write.h @@ -0,0 +1,239 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_WRITE_H +#define MBEDTLS_ASN1_WRITE_H + +#include "asn1.h" + +#define MBEDTLS_ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else \ + g += ret; } while( 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Write a length field in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param len the length to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); + +/** + * \brief Write a ASN.1 tag in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param tag the tag to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, + unsigned char tag ); + +/** + * \brief Write raw buffer data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Write a big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param X the MPI to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Write a NULL tag (MBEDTLS_ASN1_NULL) with zero data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ); + +/** + * \brief Write an OID tag (MBEDTLS_ASN1_OID) and data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID to write + * \param oid_len length of the OID + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ); + +/** + * \brief Write an AlgorithmIdentifier sequence in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID of the algorithm + * \param oid_len length of the OID + * \param par_len length of parameters, which must be already written. + * If 0, NULL parameters are added + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ); + +/** + * \brief Write a boolean tag (MBEDTLS_ASN1_BOOLEAN) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param boolean 0 or 1 + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ); + +/** + * \brief Write an int tag (MBEDTLS_ASN1_INTEGER) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param val the integer value + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); + +/** + * \brief Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a bitstring tag (MBEDTLS_ASN1_BIT_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf the bitstring + * \param bits the total number of bits in the bitstring + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ); + +/** + * \brief Write an octet string tag (MBEDTLS_ASN1_OCTET_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +/** + * \brief Create or find a specific named_data entry for writing in a + * sequence or list based on the OID. If not already in there, + * a new entry is added to the head of the list. + * Warning: Destructive behaviour for the val data! + * + * \param list Pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry) + * \param oid The OID to look for + * \param oid_len Size of the OID + * \param val Data to store (can be NULL if you want to fill it by hand) + * \param val_len Minimum length of the data buffer needed + * + * \return NULL if if there was a memory allocation error, or a pointer + * to the new / existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_ASN1_WRITE_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/base64.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/base64.h new file mode 100644 index 0000000000..352c652db9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/base64.h @@ -0,0 +1,88 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BASE64_H +#define MBEDTLS_BASE64_H + +#include + +#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * If that length cannot be represented, then no data is + * written to the buffer and *olen is set to the maximum + * length representable as a size_t. + * + * \note Call this function with dlen = 0 to obtain the + * required buffer size in *olen + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer (can be NULL for checking size) + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or + * MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dst = NULL or dlen = 0 to obtain + * the required buffer size in *olen + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bignum.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bignum.h new file mode 100644 index 0000000000..aa51556a57 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bignum.h @@ -0,0 +1,717 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BIGNUM_H +#define MBEDTLS_BIGNUM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS ) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32-bit integers can be forced on 64-bit arches (eg. for testing purposes) + * by defining MBEDTLS_HAVE_INT32 and undefining MBEDTLS_HAVE_ASM + */ +#if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(_MSC_VER) && defined(_M_AMD64) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; +#else + #if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) || defined(__mips64) ) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #else + #define MBEDTLS_HAVE_INT32 + typedef int32_t mbedtls_mpi_sint; + typedef uint32_t mbedtls_mpi_uint; + typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_HAVE_INT32 && __GNUC__ && 64-bit platform */ +#endif /* !MBEDTLS_HAVE_INT32 && _MSC_VER && _M_AMD64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_copy( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mbedtls_mpi value + * \param Y Second mbedtls_mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); + +/** + * \brief Division by mbedtls_mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mbedtls_mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/blowfish.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/blowfish.h new file mode 100644 index 0000000000..34626eef48 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/blowfish.h @@ -0,0 +1,203 @@ +/** + * \file blowfish.h + * + * \brief Blowfish block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BLOWFISH_H +#define MBEDTLS_BLOWFISH_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_BLOWFISH_ENCRYPT 1 +#define MBEDTLS_BLOWFISH_DECRYPT 0 +#define MBEDTLS_BLOWFISH_MAX_KEY_BITS 448 +#define MBEDTLS_BLOWFISH_MIN_KEY_BITS 32 +#define MBEDTLS_BLOWFISH_ROUNDS 16 /**< Rounds to use. When increasing this value, make sure to extend the initialisation vectors */ +#define MBEDTLS_BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ + +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Blowfish context structure + */ +typedef struct +{ + uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +mbedtls_blowfish_context; + +/** + * \brief Initialize Blowfish context + * + * \param ctx Blowfish context to be initialized + */ +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); + +/** + * \brief Clear Blowfish context + * + * \param ctx Blowfish context to be cleared + */ +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); + +/** + * \brief Blowfish key schedule + * + * \param ctx Blowfish context to be initialized + * \param key encryption key + * \param keybits must be between 32 and 448 bits + * + * \return 0 if successful, or MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Blowfish-ECB block encryption/decryption + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Blowfish-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (8 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Blowfish CFB buffer encryption/decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Blowfish-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * \param ctx Blowfish context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 64-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + +#endif /* blowfish.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bn_mul.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bn_mul.h new file mode 100644 index 0000000000..5408d4146b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/bn_mul.h @@ -0,0 +1,876 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef MBEDTLS_BN_MUL_H +#define MBEDTLS_BN_MUL_H + +#include "bignum.h" + +#if defined(MBEDTLS_HAVE_ASM) + +#ifndef asm +#define asm __asm +#endif + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( \ + "movl %%ebx, %0 \n\t" \ + "movl %5, %%esi \n\t" \ + "movl %6, %%edi \n\t" \ + "movl %7, %%ecx \n\t" \ + "movl %8, %%ebx \n\t" + +#define MULADDC_CORE \ + "lodsl \n\t" \ + "mull %%ebx \n\t" \ + "addl %%ecx, %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "addl (%%edi), %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "movl %%edx, %%ecx \n\t" \ + "stosl \n\t" + +#if defined(MBEDTLS_HAVE_SSE2) + +#define MULADDC_HUIT \ + "movd %%ecx, %%mm1 \n\t" \ + "movd %%ebx, %%mm0 \n\t" \ + "movd (%%edi), %%mm3 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd (%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "movd 4(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "movd 8(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd 12(%%esi), %%mm7 \n\t" \ + "pmuludq %%mm0, %%mm7 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 4(%%edi), %%mm3 \n\t" \ + "paddq %%mm4, %%mm3 \n\t" \ + "movd 8(%%edi), %%mm5 \n\t" \ + "paddq %%mm6, %%mm5 \n\t" \ + "movd 12(%%edi), %%mm4 \n\t" \ + "paddq %%mm4, %%mm7 \n\t" \ + "movd %%mm1, (%%edi) \n\t" \ + "movd 16(%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 20(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd 24(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd %%mm1, 4(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 28(%%esi), %%mm3 \n\t" \ + "pmuludq %%mm0, %%mm3 \n\t" \ + "paddq %%mm5, %%mm1 \n\t" \ + "movd 16(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm2 \n\t" \ + "movd %%mm1, 8(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm7, %%mm1 \n\t" \ + "movd 20(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm4 \n\t" \ + "movd %%mm1, 12(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 24(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm6 \n\t" \ + "movd %%mm1, 16(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm4, %%mm1 \n\t" \ + "movd 28(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm3 \n\t" \ + "movd %%mm1, 20(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm6, %%mm1 \n\t" \ + "movd %%mm1, 24(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd %%mm1, 28(%%edi) \n\t" \ + "addl $32, %%edi \n\t" \ + "addl $32, %%esi \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd %%mm1, %%ecx \n\t" + +#define MULADDC_STOP \ + "emms \n\t" \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( \ + "movq %3, %%rsi \n\t" \ + "movq %4, %%rdi \n\t" \ + "movq %5, %%rcx \n\t" \ + "movq %6, %%rbx \n\t" \ + "xorq %%r8, %%r8 \n\t" + +#define MULADDC_CORE \ + "movq (%%rsi), %%rax \n\t" \ + "mulq %%rbx \n\t" \ + "addq $8, %%rsi \n\t" \ + "addq %%rcx, %%rax \n\t" \ + "movq %%r8, %%rcx \n\t" \ + "adcq $0, %%rdx \n\t" \ + "nop \n\t" \ + "addq %%rax, (%%rdi) \n\t" \ + "adcq %%rdx, %%rcx \n\t" \ + "addq $8, %%rdi \n\t" + +#define MULADDC_STOP \ + "movq %%rcx, %0 \n\t" \ + "movq %%rdi, %1 \n\t" \ + "movq %%rsi, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" \ + ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( \ + "movl %3, %%a2 \n\t" \ + "movl %4, %%a3 \n\t" \ + "movl %5, %%d3 \n\t" \ + "movl %6, %%d2 \n\t" \ + "moveq #0, %%d0 \n\t" + +#define MULADDC_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "moveq #0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d4, %%d3 \n\t" + +#define MULADDC_STOP \ + "movl %%d3, %0 \n\t" \ + "movl %%a3, %1 \n\t" \ + "movl %%a2, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \ + ); + +#define MULADDC_HUIT \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d0, %%d3 \n\t" + +#endif /* MC68000 */ + +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "ld r3, %3 \n\t" \ + "ld r4, %4 \n\t" \ + "ld r5, %5 \n\t" \ + "ld r6, %6 \n\t" \ + "addi r3, r3, -8 \n\t" \ + "addi r4, r4, -8 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu r7, 8(r3) \n\t" \ + "mulld r8, r7, r6 \n\t" \ + "mulhdu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "ld r7, 8(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stdu r8, 8(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 8 \n\t" \ + "addi r3, r3, 8 \n\t" \ + "std r5, %0 \n\t" \ + "std r4, %1 \n\t" \ + "std r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %%r3, %3 \n\t" \ + "ld %%r4, %4 \n\t" \ + "ld %%r5, %5 \n\t" \ + "ld %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -8 \n\t" \ + "addi %%r4, %%r4, -8 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu %%r7, 8(%%r3) \n\t" \ + "mulld %%r8, %%r7, %%r6 \n\t" \ + "mulhdu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "ld %%r7, 8(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stdu %%r8, 8(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 8 \n\t" \ + "addi %%r3, %%r3, 8 \n\t" \ + "std %%r5, %0 \n\t" \ + "std %%r4, %1 \n\t" \ + "std %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "lwz r3, %3 \n\t" \ + "lwz r4, %4 \n\t" \ + "lwz r5, %5 \n\t" \ + "lwz r6, %6 \n\t" \ + "addi r3, r3, -4 \n\t" \ + "addi r4, r4, -4 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu r7, 4(r3) \n\t" \ + "mullw r8, r7, r6 \n\t" \ + "mulhwu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "lwz r7, 4(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stwu r8, 4(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 4 \n\t" \ + "addi r3, r3, 4 \n\t" \ + "stw r5, %0 \n\t" \ + "stw r4, %1 \n\t" \ + "stw r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "lwz %%r3, %3 \n\t" \ + "lwz %%r4, %4 \n\t" \ + "lwz %%r5, %5 \n\t" \ + "lwz %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -4 \n\t" \ + "addi %%r4, %%r4, -4 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu %%r7, 4(%%r3) \n\t" \ + "mullw %%r8, %%r7, %%r6 \n\t" \ + "mulhwu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "lwz %%r7, 4(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stwu %%r8, 4(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 4 \n\t" \ + "addi %%r3, %%r3, 4 \n\t" \ + "stw %%r5, %0 \n\t" \ + "stw %%r4, %1 \n\t" \ + "stw %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#endif /* PPC32 */ + +/* + * The Sparc(64) assembly is reported to be broken. + * Disable it for now, until we're able to fix it. + */ +#if 0 && defined(__sparc__) +#if defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + "ldx %3, %%o0 \n\t" \ + "ldx %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + + #define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "stx %%o1, %1 \n\t" \ + "stx %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#else /* __sparc64__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %3, %%o0 \n\t" \ + "ld %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "st %%o1, %1 \n\t" \ + "st %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* __sparc64__ */ +#endif /* __sparc__ */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( \ + "lwi r3, %3 \n\t" \ + "lwi r4, %4 \n\t" \ + "lwi r5, %5 \n\t" \ + "lwi r6, %6 \n\t" \ + "andi r7, r6, 0xffff \n\t" \ + "bsrli r6, r6, 16 \n\t" + +#define MULADDC_CORE \ + "lhui r8, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "mul r10, r9, r6 \n\t" \ + "mul r11, r8, r7 \n\t" \ + "mul r12, r9, r7 \n\t" \ + "mul r13, r8, r6 \n\t" \ + "bsrli r8, r10, 16 \n\t" \ + "bsrli r9, r11, 16 \n\t" \ + "add r13, r13, r8 \n\t" \ + "add r13, r13, r9 \n\t" \ + "bslli r10, r10, 16 \n\t" \ + "bslli r11, r11, 16 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r11 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "lwi r10, r4, 0 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r5 \n\t" \ + "addc r5, r13, r0 \n\t" \ + "swi r12, r4, 0 \n\t" \ + "addi r4, r4, 4 \n\t" + +#define MULADDC_STOP \ + "swi r5, %0 \n\t" \ + "swi r4, %1 \n\t" \ + "swi r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4" "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "r13" \ + ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( \ + "ld.a %%a2, %3 \n\t" \ + "ld.a %%a3, %4 \n\t" \ + "ld.w %%d4, %5 \n\t" \ + "ld.w %%d1, %6 \n\t" \ + "xor %%d5, %%d5 \n\t" + +#define MULADDC_CORE \ + "ld.w %%d0, [%%a2+] \n\t" \ + "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \ + "ld.w %%d0, [%%a3] \n\t" \ + "addx %%d2, %%d2, %%d0 \n\t" \ + "addc %%d3, %%d3, 0 \n\t" \ + "mov %%d4, %%d3 \n\t" \ + "st.w [%%a3+], %%d2 \n\t" + +#define MULADDC_STOP \ + "st.w %0, %%d4 \n\t" \ + "st.a %1, %%a3 \n\t" \ + "st.a %2, %%a2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "e2", "d4", "a2", "a3" \ + ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#if defined(__thumb__) && !defined(__thumb2__) + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" \ + "lsr r7, r3, #16 \n\t" \ + "mov r9, r7 \n\t" \ + "lsl r7, r3, #16 \n\t" \ + "lsr r7, r7, #16 \n\t" \ + "mov r8, r7 \n\t" + +#define MULADDC_CORE \ + "ldmia r0!, {r6} \n\t" \ + "lsr r7, r6, #16 \n\t" \ + "lsl r6, r6, #16 \n\t" \ + "lsr r6, r6, #16 \n\t" \ + "mov r4, r8 \n\t" \ + "mul r4, r6 \n\t" \ + "mov r3, r9 \n\t" \ + "mul r6, r3 \n\t" \ + "mov r5, r9 \n\t" \ + "mul r5, r7 \n\t" \ + "mov r3, r8 \n\t" \ + "mul r7, r3 \n\t" \ + "lsr r3, r6, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "lsr r3, r7, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "add r4, r4, r2 \n\t" \ + "mov r2, #0 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r6, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r7, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "ldr r3, [r1] \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r2, r5 \n\t" \ + "stmia r1!, {r4} \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "r8", "r9", "cc" \ + ); + +#else + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" + +#define MULADDC_CORE \ + "ldr r4, [r0], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r1] \n\t" \ + "umlal r2, r5, r3, r4 \n\t" \ + "adds r7, r6, r2 \n\t" \ + "adc r2, r5, #0 \n\t" \ + "str r7, [r1], #4 \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "cc" \ + ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( \ + "ldq $1, %3 \n\t" \ + "ldq $2, %4 \n\t" \ + "ldq $3, %5 \n\t" \ + "ldq $4, %6 \n\t" + +#define MULADDC_CORE \ + "ldq $6, 0($1) \n\t" \ + "addq $1, 8, $1 \n\t" \ + "mulq $6, $4, $7 \n\t" \ + "umulh $6, $4, $6 \n\t" \ + "addq $7, $3, $7 \n\t" \ + "cmpult $7, $3, $3 \n\t" \ + "ldq $5, 0($2) \n\t" \ + "addq $7, $5, $7 \n\t" \ + "cmpult $7, $5, $5 \n\t" \ + "stq $7, 0($2) \n\t" \ + "addq $2, 8, $2 \n\t" \ + "addq $6, $3, $3 \n\t" \ + "addq $5, $3, $3 \n\t" + +#define MULADDC_STOP \ + "stq $3, %0 \n\t" \ + "stq $2, %1 \n\t" \ + "stq $1, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \ + ); +#endif /* Alpha */ + +#if defined(__mips__) && !defined(__mips64) + +#define MULADDC_INIT \ + asm( \ + "lw $10, %3 \n\t" \ + "lw $11, %4 \n\t" \ + "lw $12, %5 \n\t" \ + "lw $13, %6 \n\t" + +#define MULADDC_CORE \ + "lw $14, 0($10) \n\t" \ + "multu $13, $14 \n\t" \ + "addi $10, $10, 4 \n\t" \ + "mflo $14 \n\t" \ + "mfhi $9 \n\t" \ + "addu $14, $12, $14 \n\t" \ + "lw $15, 0($11) \n\t" \ + "sltu $12, $14, $12 \n\t" \ + "addu $15, $14, $15 \n\t" \ + "sltu $14, $15, $14 \n\t" \ + "addu $12, $12, $9 \n\t" \ + "sw $15, 0($11) \n\t" \ + "addu $12, $12, $14 \n\t" \ + "addi $11, $11, 4 \n\t" + +#define MULADDC_STOP \ + "sw $12, %0 \n\t" \ + "sw $11, %1 \n\t" \ + "sw $10, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$9", "$10", "$11", "$12", "$13", "$14", "$15" \ + ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(MBEDTLS_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* MBEDTLS_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(MBEDTLS_HAVE_UDBL) + +#define MULADDC_INIT \ +{ \ + mbedtls_t_udbl r; \ + mbedtls_mpi_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (mbedtls_t_udbl) b; \ + r0 = (mbedtls_mpi_uint) r; \ + r1 = (mbedtls_mpi_uint)( r >> biL ); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + mbedtls_mpi_uint s0, s1, b0, b1; \ + mbedtls_mpi_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/camellia.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/camellia.h new file mode 100644 index 0000000000..0424d623fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/camellia.h @@ -0,0 +1,235 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CAMELLIA_H +#define MBEDTLS_CAMELLIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 + +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +/** + * \brief Initialize CAMELLIA context + * + * \param ctx CAMELLIA context to be initialized + */ +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); + +/** + * \brief Clear CAMELLIA context + * + * \param ctx CAMELLIA context to be cleared + */ +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief CAMELLIA-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and MBEDTLS_CAMELLIA_DECRYPT. + * + * \param ctx CAMELLIA context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ccm.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ccm.h new file mode 100644 index 0000000000..ef75839baa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ccm.h @@ -0,0 +1,141 @@ +/** + * \file ccm.h + * + * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CCM_H +#define MBEDTLS_CCM_H + +#include "cipher.h" + +#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx; /*!< cipher context used */ +} +mbedtls_ccm_context; + +/** + * \brief Initialize CCM context (just makes references valid) + * Makes the context ready for mbedtls_ccm_setkey() or + * mbedtls_ccm_free(). + * + * \param ctx CCM context to initialize + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM initialization (encryption and decryption) + * + * \param ctx CCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits key size in bits (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Free a CCM context and underlying cipher sub-context + * + * \param ctx CCM context to free + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM buffer encryption + * + * \param ctx CCM context + * \param length length of the input data in bytes + * \param iv nonce (initialization vector) + * \param iv_len length of IV in bytes + * must be 2, 3, 4, 5, 6, 7 or 8 + * \param add additional data + * \param add_len length of additional data in bytes + * must be less than 2^16 - 2^8 + * \param input buffer holding the input data + * \param output buffer for holding the output data + * must be at least 'length' bytes wide + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate in bytes + * must be 4, 6, 8, 10, 14 or 16 + * + * \note The tag is written to a separate buffer. To get the tag + * concatenated with the output as in the CCM spec, use + * tag = output + length and make sure the output buffer is + * at least length + tag_len wide. + * + * \return 0 if successful + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief CCM buffer authenticated decryption + * + * \param ctx CCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ccm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CCM_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/certs.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/certs.h new file mode 100644 index 0000000000..6b7e40bce5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/certs.h @@ -0,0 +1,103 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CERTS_H +#define MBEDTLS_CERTS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all CA certificates in PEM format if available */ +extern const char mbedtls_test_cas_pem[]; +extern const size_t mbedtls_test_cas_pem_len; +#endif + +/* List of all CA certificates, terminated by NULL */ +extern const char * mbedtls_test_cas[]; +extern const size_t mbedtls_test_cas_len[]; + +/* + * Convenience for users who just want a certificate: + * RSA by default, or ECDSA if RSA is not available + */ +extern const char * mbedtls_test_ca_crt; +extern const size_t mbedtls_test_ca_crt_len; +extern const char * mbedtls_test_ca_key; +extern const size_t mbedtls_test_ca_key_len; +extern const char * mbedtls_test_ca_pwd; +extern const size_t mbedtls_test_ca_pwd_len; +extern const char * mbedtls_test_srv_crt; +extern const size_t mbedtls_test_srv_crt_len; +extern const char * mbedtls_test_srv_key; +extern const size_t mbedtls_test_srv_key_len; +extern const char * mbedtls_test_cli_crt; +extern const size_t mbedtls_test_cli_crt_len; +extern const char * mbedtls_test_cli_key; +extern const size_t mbedtls_test_cli_key_len; + +#if defined(MBEDTLS_ECDSA_C) +extern const char mbedtls_test_ca_crt_ec[]; +extern const size_t mbedtls_test_ca_crt_ec_len; +extern const char mbedtls_test_ca_key_ec[]; +extern const size_t mbedtls_test_ca_key_ec_len; +extern const char mbedtls_test_ca_pwd_ec[]; +extern const size_t mbedtls_test_ca_pwd_ec_len; +extern const char mbedtls_test_srv_crt_ec[]; +extern const size_t mbedtls_test_srv_crt_ec_len; +extern const char mbedtls_test_srv_key_ec[]; +extern const size_t mbedtls_test_srv_key_ec_len; +extern const char mbedtls_test_cli_crt_ec[]; +extern const size_t mbedtls_test_cli_crt_ec_len; +extern const char mbedtls_test_cli_key_ec[]; +extern const size_t mbedtls_test_cli_key_ec_len; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const char mbedtls_test_ca_crt_rsa[]; +extern const size_t mbedtls_test_ca_crt_rsa_len; +extern const char mbedtls_test_ca_key_rsa[]; +extern const size_t mbedtls_test_ca_key_rsa_len; +extern const char mbedtls_test_ca_pwd_rsa[]; +extern const size_t mbedtls_test_ca_pwd_rsa_len; +extern const char mbedtls_test_srv_crt_rsa[]; +extern const size_t mbedtls_test_srv_crt_rsa_len; +extern const char mbedtls_test_srv_key_rsa[]; +extern const size_t mbedtls_test_srv_key_rsa_len; +extern const char mbedtls_test_cli_crt_rsa[]; +extern const size_t mbedtls_test_cli_crt_rsa_len; +extern const char mbedtls_test_cli_key_rsa[]; +extern const size_t mbedtls_test_cli_key_rsa_len; +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/check_config.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/check_config.h new file mode 100644 index 0000000000..b6448ecef9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/check_config.h @@ -0,0 +1,540 @@ +/** + * \file check_config.h + * + * \brief Consistency checks for configuration options + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * It is recommended to include this file from your config.h + * in order to catch dependency issues early. + */ + +#ifndef MBEDTLS_CHECK_CONFIG_H +#define MBEDTLS_CHECK_CONFIG_H + +/* + * We assume CHAR_BIT is 8 in many places. In practice, this is true on our + * target platforms, so not an issue, but let's just be extra sure. + */ +#include +#if CHAR_BIT != 8 +#error "mbed TLS requires a platform with 8-bit chars" +#endif + +#if defined(_WIN32) +#if !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_C is required on Windows" +#endif + +/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as + * it would confuse config.pl. */ +#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \ + !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#endif /* _WIN32 */ + +#if defined(TARGET_LIKE_MBED) && \ + ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) ) +#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS" +#endif + +#if defined(MBEDTLS_DEPRECATED_WARNING) && \ + !defined(__GNUC__) && !defined(__clang__) +#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang" +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME) +#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense" +#endif + +#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_AESNI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) +#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C) +#error "MBEDTLS_DHM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C) +#error "MBEDTLS_ECDH_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_C) && \ + ( !defined(MBEDTLS_ECP_C) || \ + !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_ASN1_WRITE_C) ) +#error "MBEDTLS_ECDSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECJPAKE_C) && \ + ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C) +#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) ) +#error "MBEDTLS_ECP_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \ + !defined(MBEDTLS_SHA256_C)) +#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \ + defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \ + && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C) +#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_GCM_C) && ( \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) ) +#error "MBEDTLS_GCM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C) +#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C) +#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_ECDH_C) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \ + ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ) +#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_C) && \ + ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) ) +#error "MBEDTLS_PK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PKCS11_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\ + defined(MBEDTLS_PLATFORM_EXIT_ALT) ) +#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\ + defined(MBEDTLS_PLATFORM_FPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_FREE) +#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_CALLOC) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO) +#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\ + defined(MBEDTLS_PLATFORM_PRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ + !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\ + !defined(MBEDTLS_PLATFORM_EXIT_ALT) +#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\ + !defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) ) +#error "MBEDTLS_RSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) ) +#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \ + !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \ + !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2)) +#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1))) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ + !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C) +#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \ + !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1) +#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \ + !defined(MBEDTLS_X509_CRT_PARSE_C) +#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_THREADING_PTHREAD) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_ALT) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_C defined, single threading implementation required" +#endif +#undef MBEDTLS_THREADING_IMPL + +#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C) +#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_PK_PARSE_C) ) +#error "MBEDTLS_X509_USE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \ + !defined(MBEDTLS_PK_WRITE_C) ) +#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites" +#endif + +/* + * Avoid warning from -pedantic. This is a convenient place for this + * workaround since this is included by every single file before the + * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units. + */ +typedef int mbedtls_iso_c_forbids_empty_translation_units; + +#endif /* MBEDTLS_CHECK_CONFIG_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher.h new file mode 100644 index 0000000000..70000f5e61 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher.h @@ -0,0 +1,698 @@ +/** + * \file cipher.h + * + * \brief Generic cipher wrapper. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CIPHER_H +#define MBEDTLS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) +#define MBEDTLS_CIPHER_MODE_AEAD +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_MODE_WITH_PADDING +#endif + +#if defined(MBEDTLS_ARC4_C) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ +#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */ + +#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length */ +#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, + MBEDTLS_CIPHER_ID_NULL, + MBEDTLS_CIPHER_ID_AES, + MBEDTLS_CIPHER_ID_DES, + MBEDTLS_CIPHER_ID_3DES, + MBEDTLS_CIPHER_ID_CAMELLIA, + MBEDTLS_CIPHER_ID_BLOWFISH, + MBEDTLS_CIPHER_ID_ARC4, +} mbedtls_cipher_id_t; + +typedef enum { + MBEDTLS_CIPHER_NONE = 0, + MBEDTLS_CIPHER_NULL, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_CIPHER_CAMELLIA_256_CCM, +} mbedtls_cipher_type_t; + +typedef enum { + MBEDTLS_MODE_NONE = 0, + MBEDTLS_MODE_ECB, + MBEDTLS_MODE_CBC, + MBEDTLS_MODE_CFB, + MBEDTLS_MODE_OFB, /* Unused! */ + MBEDTLS_MODE_CTR, + MBEDTLS_MODE_GCM, + MBEDTLS_MODE_STREAM, + MBEDTLS_MODE_CCM, +} mbedtls_cipher_mode_t; + +typedef enum { + MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default) */ + MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding */ + MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding */ + MBEDTLS_PADDING_ZEROS, /**< zero padding (not reversible!) */ + MBEDTLS_PADDING_NONE, /**< never pad (full blocks only) */ +} mbedtls_cipher_padding_t; + +typedef enum { + MBEDTLS_OPERATION_NONE = -1, + MBEDTLS_DECRYPT = 0, + MBEDTLS_ENCRYPT, +} mbedtls_operation_t; + +enum { + /** Undefined key length */ + MBEDTLS_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys */ + MBEDTLS_KEY_LENGTH_DES = 64, + /** Key length, in bits (including parity), for DES in two key EDE */ + MBEDTLS_KEY_LENGTH_DES_EDE = 128, + /** Key length, in bits (including parity), for DES in three-key EDE */ + MBEDTLS_KEY_LENGTH_DES_EDE3 = 192, +}; + +/** Maximum length of any IV, in bytes */ +#define MBEDTLS_MAX_IV_LENGTH 16 +/** Maximum block size of any cipher, in bytes */ +#define MBEDTLS_MAX_BLOCK_LENGTH 16 + +/** + * Base cipher information (opaque struct). + */ +typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t; + +/** + * Cipher information. Allows cipher functions to be called in a generic way. + */ +typedef struct { + /** Full cipher identifier (e.g. MBEDTLS_CIPHER_AES_256_CBC) */ + mbedtls_cipher_type_t type; + + /** Cipher mode (e.g. MBEDTLS_MODE_CBC) */ + mbedtls_cipher_mode_t mode; + + /** Cipher key length, in bits (default length for variable sized ciphers) + * (Includes parity bits for ciphers like DES) */ + unsigned int key_bitlen; + + /** Name of the cipher */ + const char * name; + + /** IV/NONCE size, in bytes. + * For cipher that accept many sizes: recommended size */ + unsigned int iv_size; + + /** Flags for variable IV size, variable key size, etc. */ + int flags; + + /** block size, in bytes */ + unsigned int block_size; + + /** Base cipher information and functions */ + const mbedtls_cipher_base_t *base; + +} mbedtls_cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct { + /** Information about the associated cipher */ + const mbedtls_cipher_info_t *cipher_info; + + /** Key length to use */ + int key_bitlen; + + /** Operation that the context's key has been initialised for */ + mbedtls_operation_t operation; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for cipher mode */ + void (*add_padding)( unsigned char *output, size_t olen, size_t data_len ); + int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len ); +#endif + + /** Buffer for data that hasn't been encrypted yet */ + unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of bytes that still need processing */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode */ + unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in bytes (for ciphers with variable-length IVs) */ + size_t iv_size; + + /** Cipher-specific context */ + void *cipher_ctx; +} mbedtls_cipher_context_t; + +/** + * \brief Returns the list of ciphers supported by the generic cipher module. + * + * \return a statically allocated array of ciphers, the last entry + * is 0. + */ +const int *mbedtls_cipher_list( void ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_name, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher id, key size and mode. + * + * \param cipher_id Id of the cipher to search for + * (e.g. MBEDTLS_CIPHER_ID_AES) + * \param key_bitlen Length of the key in bits + * \param mode Cipher mode (e.g. MBEDTLS_MODE_CBC) + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ); + +/** + * \brief Initialize a cipher_context (as NONE) + */ +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Free and clear the cipher-specific context of ctx. + * Freeing ctx itself remains the responsibility of the + * caller. + */ +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Initialises and fills the cipher context structure with + * the appropriate values. + * + * \note Currently also clears structure. In future versions you + * will be required to call mbedtls_cipher_init() on the structure + * first. + * + * \param ctx context to initialise. May not be NULL. + * \param cipher_info cipher to use. + * + * \return 0 on success, + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, + * MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context failed. + */ +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ); + +/** + * \brief Returns the block size of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's blocks, or 0 if ctx has not been + * initialised. + */ +static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief Returns the mode of operation for the cipher. + * (e.g. MBEDTLS_MODE_CBC) + * + * \param ctx cipher's context. Must have been initialised. + * + * \return mode of operation, or MBEDTLS_MODE_NONE if ctx + * has not been initialised. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief Returns the size of the cipher's IV/NONCE in bytes. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return If IV has not been set yet: (recommended) IV size + * (0 for ciphers not using IV/NONCE). + * If IV has already been set: actual size. + */ +static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + if( ctx->iv_size != 0 ) + return (int) ctx->iv_size; + + return (int) ctx->cipher_info->iv_size; +} + +/** + * \brief Returns the type of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return type of the cipher, or MBEDTLS_CIPHER_NONE if ctx has + * not been initialised. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief Returns the name of the given cipher, as a string. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return name of the cipher, or NULL if ctx was not initialised. + */ +static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief Returns the key length of the cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return cipher's key length, in bits, or + * MBEDTLS_KEY_LENGTH_NONE if ctx has not been + * initialised. + */ +static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_KEY_LENGTH_NONE; + + return (int) ctx->cipher_info->key_bitlen; +} + +/** + * \brief Returns the operation of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return operation (MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT), + * or MBEDTLS_OPERATION_NONE if ctx has not been + * initialised. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief Set the key to use with the given context. + * + * \param ctx generic cipher context. May not be NULL. Must have been + * initialised using cipher_context_from_type or + * cipher_context_from_string. + * \param key The key to use. + * \param key_bitlen key length to use, in bits. + * \param operation Operation that the key will be used for, either + * MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails or a cipher specific + * error code. + */ +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +/** + * \brief Set padding mode, for cipher modes that use padding. + * (Default: PKCS7 padding.) + * + * \param ctx generic cipher context + * \param mode padding mode + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if selected padding mode is not supported, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * does not support padding. + */ +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ); +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +/** + * \brief Set the initialization vector (IV) or nonce + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * + * \returns 0 on success, or MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, this function has no effect. + */ +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ); + +/** + * \brief Finish preparation of the given context + * + * \param ctx generic cipher context + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Add additional data (for AEAD ciphers). + * Currently only supported with GCM. + * Must be called exactly once, after mbedtls_cipher_reset(). + * + * \param ctx generic cipher context + * \param ad Additional data to use. + * \param ad_len Length of ad. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic cipher update function. Encrypts/decrypts + * using the given cipher context. Writes as many block + * size'd blocks of data as possible to output. Any data + * that cannot be written immediately will either be added + * to the next block, or flushed when cipher_final is + * called. + * Exception: for MBEDTLS_MODE_ECB, expects single block + * in size (e.g. 16 bytes for AES) + * + * \param ctx generic cipher context + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher or a cipher specific + * error code. + * + * \note If the underlying cipher is GCM, all calls to this + * function, except the last one before mbedtls_cipher_finish(), + * must have ilen a multiple of the block size. + */ +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ); + +/** + * \brief Generic cipher finalisation function. If data still + * needs to be flushed from an incomplete block, data + * contained within it will be padded with the size of + * the last block, and written to the output buffer. + * + * \param ctx Generic cipher context + * \param output buffer to write data to. Needs block_size available. + * \param olen length of the data written to the output buffer. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting or a cipher specific error code. + */ +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Write tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag buffer to write the tag + * \param tag_len Length of the tag to write + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ); + +/** + * \brief Check tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag Buffer holding the tag + * \param tag_len Length of the tag to check + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic all-in-one encryption/decryption + * (for all ciphers except AEAD constructs). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, use iv = NULL and iv_len = 0. + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, or + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting, or + * a cipher specific error code. + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/** + * \brief Generic autenticated encryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to authenticate. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer for the authentication tag + * \param tag_len desired tag length + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * a cipher specific error code. + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ); + +/** + * \brief Generic autenticated decryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to be authenticated. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer holding the authentication tag + * \param tag_len length of the authentication tag + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_AUTH_FAILED if data isn't authentic, + * or a cipher specific error code. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext to + * be used by mistake, making this interface safer. + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher_internal.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher_internal.h new file mode 100644 index 0000000000..6c58bcc525 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/cipher_internal.h @@ -0,0 +1,109 @@ +/** + * \file cipher_internal.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CIPHER_WRAP_H +#define MBEDTLS_CIPHER_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Base cipher information. The non-mode specific functions and values. + */ +struct mbedtls_cipher_base_t +{ + /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */ + mbedtls_cipher_id_t cipher; + + /** Encrypt using ECB */ + int (*ecb_func)( void *ctx, mbedtls_operation_t mode, + const unsigned char *input, unsigned char *output ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /** Encrypt using CFB (Full length) */ + int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + /** Encrypt using STREAM */ + int (*stream_func)( void *ctx, size_t length, + const unsigned char *input, unsigned char *output ); +#endif + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen ); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +}; + +typedef struct +{ + mbedtls_cipher_type_t type; + const mbedtls_cipher_info_t *info; +} mbedtls_cipher_definition_t; + +extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[]; + +extern int mbedtls_cipher_supported[]; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_WRAP_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/compat-1.3.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/compat-1.3.h new file mode 100644 index 0000000000..27abbd9720 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/compat-1.3.h @@ -0,0 +1,2634 @@ +/** + * \file compat-1.3.h + * + * \brief Compatibility definitions for using mbed TLS with client code written + * for the PolarSSL naming conventions. + * + * \deprecated Use the new names directly instead + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Including compat-1.3.h is deprecated" +#endif + +#ifndef MBEDTLS_COMPAT13_H +#define MBEDTLS_COMPAT13_H + +/* + * config.h options + */ +#if defined MBEDTLS_AESNI_C +#define POLARSSL_AESNI_C MBEDTLS_AESNI_C +#endif +#if defined MBEDTLS_AES_ALT +#define POLARSSL_AES_ALT MBEDTLS_AES_ALT +#endif +#if defined MBEDTLS_AES_C +#define POLARSSL_AES_C MBEDTLS_AES_C +#endif +#if defined MBEDTLS_AES_ROM_TABLES +#define POLARSSL_AES_ROM_TABLES MBEDTLS_AES_ROM_TABLES +#endif +#if defined MBEDTLS_ARC4_ALT +#define POLARSSL_ARC4_ALT MBEDTLS_ARC4_ALT +#endif +#if defined MBEDTLS_ARC4_C +#define POLARSSL_ARC4_C MBEDTLS_ARC4_C +#endif +#if defined MBEDTLS_ASN1_PARSE_C +#define POLARSSL_ASN1_PARSE_C MBEDTLS_ASN1_PARSE_C +#endif +#if defined MBEDTLS_ASN1_WRITE_C +#define POLARSSL_ASN1_WRITE_C MBEDTLS_ASN1_WRITE_C +#endif +#if defined MBEDTLS_BASE64_C +#define POLARSSL_BASE64_C MBEDTLS_BASE64_C +#endif +#if defined MBEDTLS_BIGNUM_C +#define POLARSSL_BIGNUM_C MBEDTLS_BIGNUM_C +#endif +#if defined MBEDTLS_BLOWFISH_ALT +#define POLARSSL_BLOWFISH_ALT MBEDTLS_BLOWFISH_ALT +#endif +#if defined MBEDTLS_BLOWFISH_C +#define POLARSSL_BLOWFISH_C MBEDTLS_BLOWFISH_C +#endif +#if defined MBEDTLS_CAMELLIA_ALT +#define POLARSSL_CAMELLIA_ALT MBEDTLS_CAMELLIA_ALT +#endif +#if defined MBEDTLS_CAMELLIA_C +#define POLARSSL_CAMELLIA_C MBEDTLS_CAMELLIA_C +#endif +#if defined MBEDTLS_CAMELLIA_SMALL_MEMORY +#define POLARSSL_CAMELLIA_SMALL_MEMORY MBEDTLS_CAMELLIA_SMALL_MEMORY +#endif +#if defined MBEDTLS_CCM_C +#define POLARSSL_CCM_C MBEDTLS_CCM_C +#endif +#if defined MBEDTLS_CERTS_C +#define POLARSSL_CERTS_C MBEDTLS_CERTS_C +#endif +#if defined MBEDTLS_CIPHER_C +#define POLARSSL_CIPHER_C MBEDTLS_CIPHER_C +#endif +#if defined MBEDTLS_CIPHER_MODE_CBC +#define POLARSSL_CIPHER_MODE_CBC MBEDTLS_CIPHER_MODE_CBC +#endif +#if defined MBEDTLS_CIPHER_MODE_CFB +#define POLARSSL_CIPHER_MODE_CFB MBEDTLS_CIPHER_MODE_CFB +#endif +#if defined MBEDTLS_CIPHER_MODE_CTR +#define POLARSSL_CIPHER_MODE_CTR MBEDTLS_CIPHER_MODE_CTR +#endif +#if defined MBEDTLS_CIPHER_NULL_CIPHER +#define POLARSSL_CIPHER_NULL_CIPHER MBEDTLS_CIPHER_NULL_CIPHER +#endif +#if defined MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_PKCS7 +#define POLARSSL_CIPHER_PADDING_PKCS7 MBEDTLS_CIPHER_PADDING_PKCS7 +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS +#define POLARSSL_CIPHER_PADDING_ZEROS MBEDTLS_CIPHER_PADDING_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#endif +#if defined MBEDTLS_CTR_DRBG_C +#define POLARSSL_CTR_DRBG_C MBEDTLS_CTR_DRBG_C +#endif +#if defined MBEDTLS_DEBUG_C +#define POLARSSL_DEBUG_C MBEDTLS_DEBUG_C +#endif +#if defined MBEDTLS_DEPRECATED_REMOVED +#define POLARSSL_DEPRECATED_REMOVED MBEDTLS_DEPRECATED_REMOVED +#endif +#if defined MBEDTLS_DEPRECATED_WARNING +#define POLARSSL_DEPRECATED_WARNING MBEDTLS_DEPRECATED_WARNING +#endif +#if defined MBEDTLS_DES_ALT +#define POLARSSL_DES_ALT MBEDTLS_DES_ALT +#endif +#if defined MBEDTLS_DES_C +#define POLARSSL_DES_C MBEDTLS_DES_C +#endif +#if defined MBEDTLS_DHM_C +#define POLARSSL_DHM_C MBEDTLS_DHM_C +#endif +#if defined MBEDTLS_ECDH_C +#define POLARSSL_ECDH_C MBEDTLS_ECDH_C +#endif +#if defined MBEDTLS_ECDSA_C +#define POLARSSL_ECDSA_C MBEDTLS_ECDSA_C +#endif +#if defined MBEDTLS_ECDSA_DETERMINISTIC +#define POLARSSL_ECDSA_DETERMINISTIC MBEDTLS_ECDSA_DETERMINISTIC +#endif +#if defined MBEDTLS_ECP_C +#define POLARSSL_ECP_C MBEDTLS_ECP_C +#endif +#if defined MBEDTLS_ECP_DP_BP256R1_ENABLED +#define POLARSSL_ECP_DP_BP256R1_ENABLED MBEDTLS_ECP_DP_BP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP384R1_ENABLED +#define POLARSSL_ECP_DP_BP384R1_ENABLED MBEDTLS_ECP_DP_BP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP512R1_ENABLED +#define POLARSSL_ECP_DP_BP512R1_ENABLED MBEDTLS_ECP_DP_BP512R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define POLARSSL_ECP_DP_M255_ENABLED MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define POLARSSL_ECP_DP_SECP192K1_ENABLED MBEDTLS_ECP_DP_SECP192K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define POLARSSL_ECP_DP_SECP192R1_ENABLED MBEDTLS_ECP_DP_SECP192R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define POLARSSL_ECP_DP_SECP224K1_ENABLED MBEDTLS_ECP_DP_SECP224K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define POLARSSL_ECP_DP_SECP224R1_ENABLED MBEDTLS_ECP_DP_SECP224R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define POLARSSL_ECP_DP_SECP256K1_ENABLED MBEDTLS_ECP_DP_SECP256K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define POLARSSL_ECP_DP_SECP256R1_ENABLED MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define POLARSSL_ECP_DP_SECP384R1_ENABLED MBEDTLS_ECP_DP_SECP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define POLARSSL_ECP_DP_SECP521R1_ENABLED MBEDTLS_ECP_DP_SECP521R1_ENABLED +#endif +#if defined MBEDTLS_ECP_FIXED_POINT_OPTIM +#define POLARSSL_ECP_FIXED_POINT_OPTIM MBEDTLS_ECP_FIXED_POINT_OPTIM +#endif +#if defined MBEDTLS_ECP_MAX_BITS +#define POLARSSL_ECP_MAX_BITS MBEDTLS_ECP_MAX_BITS +#endif +#if defined MBEDTLS_ECP_NIST_OPTIM +#define POLARSSL_ECP_NIST_OPTIM MBEDTLS_ECP_NIST_OPTIM +#endif +#if defined MBEDTLS_ECP_WINDOW_SIZE +#define POLARSSL_ECP_WINDOW_SIZE MBEDTLS_ECP_WINDOW_SIZE +#endif +#if defined MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#define POLARSSL_ENABLE_WEAK_CIPHERSUITES MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#endif +#if defined MBEDTLS_ENTROPY_C +#define POLARSSL_ENTROPY_C MBEDTLS_ENTROPY_C +#endif +#if defined MBEDTLS_ENTROPY_FORCE_SHA256 +#define POLARSSL_ENTROPY_FORCE_SHA256 MBEDTLS_ENTROPY_FORCE_SHA256 +#endif +#if defined MBEDTLS_ERROR_C +#define POLARSSL_ERROR_C MBEDTLS_ERROR_C +#endif +#if defined MBEDTLS_ERROR_STRERROR_BC +#define POLARSSL_ERROR_STRERROR_BC MBEDTLS_ERROR_STRERROR_BC +#endif +#if defined MBEDTLS_ERROR_STRERROR_DUMMY +#define POLARSSL_ERROR_STRERROR_DUMMY MBEDTLS_ERROR_STRERROR_DUMMY +#endif +#if defined MBEDTLS_FS_IO +#define POLARSSL_FS_IO MBEDTLS_FS_IO +#endif +#if defined MBEDTLS_GCM_C +#define POLARSSL_GCM_C MBEDTLS_GCM_C +#endif +#if defined MBEDTLS_GENPRIME +#define POLARSSL_GENPRIME MBEDTLS_GENPRIME +#endif +#if defined MBEDTLS_HAVEGE_C +#define POLARSSL_HAVEGE_C MBEDTLS_HAVEGE_C +#endif +#if defined MBEDTLS_HAVE_ASM +#define POLARSSL_HAVE_ASM MBEDTLS_HAVE_ASM +#endif +#if defined MBEDTLS_HAVE_SSE2 +#define POLARSSL_HAVE_SSE2 MBEDTLS_HAVE_SSE2 +#endif +#if defined MBEDTLS_HAVE_TIME +#define POLARSSL_HAVE_TIME MBEDTLS_HAVE_TIME +#endif +#if defined MBEDTLS_HMAC_DRBG_C +#define POLARSSL_HMAC_DRBG_C MBEDTLS_HMAC_DRBG_C +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_INPUT +#define POLARSSL_HMAC_DRBG_MAX_INPUT MBEDTLS_HMAC_DRBG_MAX_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_REQUEST +#define POLARSSL_HMAC_DRBG_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#endif +#if defined MBEDTLS_MD2_ALT +#define POLARSSL_MD2_ALT MBEDTLS_MD2_ALT +#endif +#if defined MBEDTLS_MD2_C +#define POLARSSL_MD2_C MBEDTLS_MD2_C +#endif +#if defined MBEDTLS_MD2_PROCESS_ALT +#define POLARSSL_MD2_PROCESS_ALT MBEDTLS_MD2_PROCESS_ALT +#endif +#if defined MBEDTLS_MD4_ALT +#define POLARSSL_MD4_ALT MBEDTLS_MD4_ALT +#endif +#if defined MBEDTLS_MD4_C +#define POLARSSL_MD4_C MBEDTLS_MD4_C +#endif +#if defined MBEDTLS_MD4_PROCESS_ALT +#define POLARSSL_MD4_PROCESS_ALT MBEDTLS_MD4_PROCESS_ALT +#endif +#if defined MBEDTLS_MD5_ALT +#define POLARSSL_MD5_ALT MBEDTLS_MD5_ALT +#endif +#if defined MBEDTLS_MD5_C +#define POLARSSL_MD5_C MBEDTLS_MD5_C +#endif +#if defined MBEDTLS_MD5_PROCESS_ALT +#define POLARSSL_MD5_PROCESS_ALT MBEDTLS_MD5_PROCESS_ALT +#endif +#if defined MBEDTLS_MD_C +#define POLARSSL_MD_C MBEDTLS_MD_C +#endif +#if defined MBEDTLS_MEMORY_ALIGN_MULTIPLE +#define POLARSSL_MEMORY_ALIGN_MULTIPLE MBEDTLS_MEMORY_ALIGN_MULTIPLE +#endif +#if defined MBEDTLS_MEMORY_BACKTRACE +#define POLARSSL_MEMORY_BACKTRACE MBEDTLS_MEMORY_BACKTRACE +#endif +#if defined MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define POLARSSL_MEMORY_BUFFER_ALLOC_C MBEDTLS_MEMORY_BUFFER_ALLOC_C +#endif +#if defined MBEDTLS_MEMORY_C +#define POLARSSL_MEMORY_C MBEDTLS_MEMORY_C +#endif +#if defined MBEDTLS_MEMORY_DEBUG +#define POLARSSL_MEMORY_DEBUG MBEDTLS_MEMORY_DEBUG +#endif +#if defined MBEDTLS_MPI_MAX_SIZE +#define POLARSSL_MPI_MAX_SIZE MBEDTLS_MPI_MAX_SIZE +#endif +#if defined MBEDTLS_MPI_WINDOW_SIZE +#define POLARSSL_MPI_WINDOW_SIZE MBEDTLS_MPI_WINDOW_SIZE +#endif +#if defined MBEDTLS_NET_C +#define POLARSSL_NET_C MBEDTLS_NET_C +#endif +#if defined MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#endif +#if defined MBEDTLS_NO_PLATFORM_ENTROPY +#define POLARSSL_NO_PLATFORM_ENTROPY MBEDTLS_NO_PLATFORM_ENTROPY +#endif +#if defined MBEDTLS_OID_C +#define POLARSSL_OID_C MBEDTLS_OID_C +#endif +#if defined MBEDTLS_PADLOCK_C +#define POLARSSL_PADLOCK_C MBEDTLS_PADLOCK_C +#endif +#if defined MBEDTLS_PBKDF2_C +#define POLARSSL_PBKDF2_C MBEDTLS_PBKDF2_C +#endif +#if defined MBEDTLS_PEM_PARSE_C +#define POLARSSL_PEM_PARSE_C MBEDTLS_PEM_PARSE_C +#endif +#if defined MBEDTLS_PEM_WRITE_C +#define POLARSSL_PEM_WRITE_C MBEDTLS_PEM_WRITE_C +#endif +#if defined MBEDTLS_PKCS11_C +#define POLARSSL_PKCS11_C MBEDTLS_PKCS11_C +#endif +#if defined MBEDTLS_PKCS12_C +#define POLARSSL_PKCS12_C MBEDTLS_PKCS12_C +#endif +#if defined MBEDTLS_PKCS1_V15 +#define POLARSSL_PKCS1_V15 MBEDTLS_PKCS1_V15 +#endif +#if defined MBEDTLS_PKCS1_V21 +#define POLARSSL_PKCS1_V21 MBEDTLS_PKCS1_V21 +#endif +#if defined MBEDTLS_PKCS5_C +#define POLARSSL_PKCS5_C MBEDTLS_PKCS5_C +#endif +#if defined MBEDTLS_PK_C +#define POLARSSL_PK_C MBEDTLS_PK_C +#endif +#if defined MBEDTLS_PK_PARSE_C +#define POLARSSL_PK_PARSE_C MBEDTLS_PK_PARSE_C +#endif +#if defined MBEDTLS_PK_PARSE_EC_EXTENDED +#define POLARSSL_PK_PARSE_EC_EXTENDED MBEDTLS_PK_PARSE_EC_EXTENDED +#endif +#if defined MBEDTLS_PK_RSA_ALT_SUPPORT +#define POLARSSL_PK_RSA_ALT_SUPPORT MBEDTLS_PK_RSA_ALT_SUPPORT +#endif +#if defined MBEDTLS_PK_WRITE_C +#define POLARSSL_PK_WRITE_C MBEDTLS_PK_WRITE_C +#endif +#if defined MBEDTLS_PLATFORM_C +#define POLARSSL_PLATFORM_C MBEDTLS_PLATFORM_C +#endif +#if defined MBEDTLS_PLATFORM_EXIT_ALT +#define POLARSSL_PLATFORM_EXIT_ALT MBEDTLS_PLATFORM_EXIT_ALT +#endif +#if defined MBEDTLS_PLATFORM_EXIT_MACRO +#define POLARSSL_PLATFORM_EXIT_MACRO MBEDTLS_PLATFORM_EXIT_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_ALT +#define POLARSSL_PLATFORM_FPRINTF_ALT MBEDTLS_PLATFORM_FPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_MACRO +#define POLARSSL_PLATFORM_FPRINTF_MACRO MBEDTLS_PLATFORM_FPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FREE_MACRO +#define POLARSSL_PLATFORM_FREE_MACRO MBEDTLS_PLATFORM_FREE_MACRO +#endif +#if defined MBEDTLS_PLATFORM_MEMORY +#define POLARSSL_PLATFORM_MEMORY MBEDTLS_PLATFORM_MEMORY +#endif +#if defined MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_ALT +#define POLARSSL_PLATFORM_PRINTF_ALT MBEDTLS_PLATFORM_PRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_MACRO +#define POLARSSL_PLATFORM_PRINTF_MACRO MBEDTLS_PLATFORM_PRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_ALT +#define POLARSSL_PLATFORM_SNPRINTF_ALT MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_MACRO +#define POLARSSL_PLATFORM_SNPRINTF_MACRO MBEDTLS_PLATFORM_SNPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_STD_EXIT +#define POLARSSL_PLATFORM_STD_EXIT MBEDTLS_PLATFORM_STD_EXIT +#endif +#if defined MBEDTLS_PLATFORM_STD_FPRINTF +#define POLARSSL_PLATFORM_STD_FPRINTF MBEDTLS_PLATFORM_STD_FPRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_FREE +#define POLARSSL_PLATFORM_STD_FREE MBEDTLS_PLATFORM_STD_FREE +#endif +#if defined MBEDTLS_PLATFORM_STD_MALLOC +#define POLARSSL_PLATFORM_STD_MALLOC MBEDTLS_PLATFORM_STD_MALLOC +#endif +#if defined MBEDTLS_PLATFORM_STD_MEM_HDR +#define POLARSSL_PLATFORM_STD_MEM_HDR MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#if defined MBEDTLS_PLATFORM_STD_PRINTF +#define POLARSSL_PLATFORM_STD_PRINTF MBEDTLS_PLATFORM_STD_PRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_SNPRINTF +#define POLARSSL_PLATFORM_STD_SNPRINTF MBEDTLS_PLATFORM_STD_SNPRINTF +#endif +#if defined MBEDTLS_PSK_MAX_LEN +#define POLARSSL_PSK_MAX_LEN MBEDTLS_PSK_MAX_LEN +#endif +#if defined MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define POLARSSL_REMOVE_ARC4_CIPHERSUITES MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#endif +#if defined MBEDTLS_RIPEMD160_ALT +#define POLARSSL_RIPEMD160_ALT MBEDTLS_RIPEMD160_ALT +#endif +#if defined MBEDTLS_RIPEMD160_C +#define POLARSSL_RIPEMD160_C MBEDTLS_RIPEMD160_C +#endif +#if defined MBEDTLS_RIPEMD160_PROCESS_ALT +#define POLARSSL_RIPEMD160_PROCESS_ALT MBEDTLS_RIPEMD160_PROCESS_ALT +#endif +#if defined MBEDTLS_RSA_C +#define POLARSSL_RSA_C MBEDTLS_RSA_C +#endif +#if defined MBEDTLS_RSA_NO_CRT +#define POLARSSL_RSA_NO_CRT MBEDTLS_RSA_NO_CRT +#endif +#if defined MBEDTLS_SELF_TEST +#define POLARSSL_SELF_TEST MBEDTLS_SELF_TEST +#endif +#if defined MBEDTLS_SHA1_ALT +#define POLARSSL_SHA1_ALT MBEDTLS_SHA1_ALT +#endif +#if defined MBEDTLS_SHA1_C +#define POLARSSL_SHA1_C MBEDTLS_SHA1_C +#endif +#if defined MBEDTLS_SHA1_PROCESS_ALT +#define POLARSSL_SHA1_PROCESS_ALT MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA256_ALT +#define POLARSSL_SHA256_ALT MBEDTLS_SHA256_ALT +#endif +#if defined MBEDTLS_SHA256_C +#define POLARSSL_SHA256_C MBEDTLS_SHA256_C +#endif +#if defined MBEDTLS_SHA256_PROCESS_ALT +#define POLARSSL_SHA256_PROCESS_ALT MBEDTLS_SHA256_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA512_ALT +#define POLARSSL_SHA512_ALT MBEDTLS_SHA512_ALT +#endif +#if defined MBEDTLS_SHA512_C +#define POLARSSL_SHA512_C MBEDTLS_SHA512_C +#endif +#if defined MBEDTLS_SHA512_PROCESS_ALT +#define POLARSSL_SHA512_PROCESS_ALT MBEDTLS_SHA512_PROCESS_ALT +#endif +#if defined MBEDTLS_SSL_AEAD_RANDOM_IV +#define POLARSSL_SSL_AEAD_RANDOM_IV MBEDTLS_SSL_AEAD_RANDOM_IV +#endif +#if defined MBEDTLS_SSL_ALERT_MESSAGES +#define POLARSSL_SSL_ALERT_MESSAGES MBEDTLS_SSL_ALERT_MESSAGES +#endif +#if defined MBEDTLS_SSL_ALL_ALERT_MESSAGES +#define POLARSSL_SSL_ALL_ALERT_MESSAGES MBEDTLS_SSL_ALL_ALERT_MESSAGES +#endif +#if defined MBEDTLS_SSL_ALPN +#define POLARSSL_SSL_ALPN MBEDTLS_SSL_ALPN +#endif +#if defined MBEDTLS_SSL_CACHE_C +#define POLARSSL_SSL_CACHE_C MBEDTLS_SSL_CACHE_C +#endif +#if defined MBEDTLS_SSL_CBC_RECORD_SPLITTING +#define POLARSSL_SSL_CBC_RECORD_SPLITTING MBEDTLS_SSL_CBC_RECORD_SPLITTING +#endif +#if defined MBEDTLS_SSL_CLI_C +#define POLARSSL_SSL_CLI_C MBEDTLS_SSL_CLI_C +#endif +#if defined MBEDTLS_SSL_COOKIE_C +#define POLARSSL_SSL_COOKIE_C MBEDTLS_SSL_COOKIE_C +#endif +#if defined MBEDTLS_SSL_COOKIE_TIMEOUT +#define POLARSSL_SSL_COOKIE_TIMEOUT MBEDTLS_SSL_COOKIE_TIMEOUT +#endif +#if defined MBEDTLS_SSL_DEBUG_ALL +#define POLARSSL_SSL_DEBUG_ALL MBEDTLS_SSL_DEBUG_ALL +#endif +#if defined MBEDTLS_SSL_DISABLE_RENEGOTIATION +#define POLARSSL_SSL_DISABLE_RENEGOTIATION MBEDTLS_SSL_DISABLE_RENEGOTIATION +#endif +#if defined MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define POLARSSL_SSL_DTLS_ANTI_REPLAY MBEDTLS_SSL_DTLS_ANTI_REPLAY +#endif +#if defined MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#define POLARSSL_SSL_DTLS_BADMAC_LIMIT MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#endif +#if defined MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define POLARSSL_SSL_DTLS_HELLO_VERIFY MBEDTLS_SSL_DTLS_HELLO_VERIFY +#endif +#if defined MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define POLARSSL_SSL_ENCRYPT_THEN_MAC MBEDTLS_SSL_ENCRYPT_THEN_MAC +#endif +#if defined MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define POLARSSL_SSL_EXTENDED_MASTER_SECRET MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#endif +#if defined MBEDTLS_SSL_FALLBACK_SCSV +#define POLARSSL_SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#endif +#if defined MBEDTLS_SSL_HW_RECORD_ACCEL +#define POLARSSL_SSL_HW_RECORD_ACCEL MBEDTLS_SSL_HW_RECORD_ACCEL +#endif +#if defined MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#endif +#if defined MBEDTLS_SSL_PROTO_DTLS +#define POLARSSL_SSL_PROTO_DTLS MBEDTLS_SSL_PROTO_DTLS +#endif +#if defined MBEDTLS_SSL_PROTO_SSL3 +#define POLARSSL_SSL_PROTO_SSL3 MBEDTLS_SSL_PROTO_SSL3 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1 +#define POLARSSL_SSL_PROTO_TLS1 MBEDTLS_SSL_PROTO_TLS1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_1 +#define POLARSSL_SSL_PROTO_TLS1_1 MBEDTLS_SSL_PROTO_TLS1_1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_2 +#define POLARSSL_SSL_PROTO_TLS1_2 MBEDTLS_SSL_PROTO_TLS1_2 +#endif +#if defined MBEDTLS_SSL_RENEGOTIATION +#define POLARSSL_SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#endif +#if defined MBEDTLS_SSL_SERVER_NAME_INDICATION +#define POLARSSL_SSL_SERVER_NAME_INDICATION MBEDTLS_SSL_SERVER_NAME_INDICATION +#endif +#if defined MBEDTLS_SSL_SESSION_TICKETS +#define POLARSSL_SSL_SESSION_TICKETS MBEDTLS_SSL_SESSION_TICKETS +#endif +#if defined MBEDTLS_SSL_SRV_C +#define POLARSSL_SSL_SRV_C MBEDTLS_SSL_SRV_C +#endif +#if defined MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#endif +#if defined MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#endif +#if defined MBEDTLS_SSL_TLS_C +#define POLARSSL_SSL_TLS_C MBEDTLS_SSL_TLS_C +#endif +#if defined MBEDTLS_SSL_TRUNCATED_HMAC +#define POLARSSL_SSL_TRUNCATED_HMAC MBEDTLS_SSL_TRUNCATED_HMAC +#endif +#if defined MBEDTLS_THREADING_ALT +#define POLARSSL_THREADING_ALT MBEDTLS_THREADING_ALT +#endif +#if defined MBEDTLS_THREADING_C +#define POLARSSL_THREADING_C MBEDTLS_THREADING_C +#endif +#if defined MBEDTLS_THREADING_PTHREAD +#define POLARSSL_THREADING_PTHREAD MBEDTLS_THREADING_PTHREAD +#endif +#if defined MBEDTLS_TIMING_ALT +#define POLARSSL_TIMING_ALT MBEDTLS_TIMING_ALT +#endif +#if defined MBEDTLS_TIMING_C +#define POLARSSL_TIMING_C MBEDTLS_TIMING_C +#endif +#if defined MBEDTLS_VERSION_C +#define POLARSSL_VERSION_C MBEDTLS_VERSION_C +#endif +#if defined MBEDTLS_VERSION_FEATURES +#define POLARSSL_VERSION_FEATURES MBEDTLS_VERSION_FEATURES +#endif +#if defined MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#endif +#if defined MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#endif +#if defined MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CHECK_KEY_USAGE +#define POLARSSL_X509_CHECK_KEY_USAGE MBEDTLS_X509_CHECK_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CREATE_C +#define POLARSSL_X509_CREATE_C MBEDTLS_X509_CREATE_C +#endif +#if defined MBEDTLS_X509_CRL_PARSE_C +#define POLARSSL_X509_CRL_PARSE_C MBEDTLS_X509_CRL_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_PARSE_C +#define POLARSSL_X509_CRT_PARSE_C MBEDTLS_X509_CRT_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_WRITE_C +#define POLARSSL_X509_CRT_WRITE_C MBEDTLS_X509_CRT_WRITE_C +#endif +#if defined MBEDTLS_X509_CSR_PARSE_C +#define POLARSSL_X509_CSR_PARSE_C MBEDTLS_X509_CSR_PARSE_C +#endif +#if defined MBEDTLS_X509_CSR_WRITE_C +#define POLARSSL_X509_CSR_WRITE_C MBEDTLS_X509_CSR_WRITE_C +#endif +#if defined MBEDTLS_X509_MAX_INTERMEDIATE_CA +#define POLARSSL_X509_MAX_INTERMEDIATE_CA MBEDTLS_X509_MAX_INTERMEDIATE_CA +#endif +#if defined MBEDTLS_X509_RSASSA_PSS_SUPPORT +#define POLARSSL_X509_RSASSA_PSS_SUPPORT MBEDTLS_X509_RSASSA_PSS_SUPPORT +#endif +#if defined MBEDTLS_X509_USE_C +#define POLARSSL_X509_USE_C MBEDTLS_X509_USE_C +#endif +#if defined MBEDTLS_XTEA_ALT +#define POLARSSL_XTEA_ALT MBEDTLS_XTEA_ALT +#endif +#if defined MBEDTLS_XTEA_C +#define POLARSSL_XTEA_C MBEDTLS_XTEA_C +#endif +#if defined MBEDTLS_ZLIB_SUPPORT +#define POLARSSL_ZLIB_SUPPORT MBEDTLS_ZLIB_SUPPORT +#endif + +/* + * Misc names (macros, types, functions, enum constants...) + */ +#define AES_DECRYPT MBEDTLS_AES_DECRYPT +#define AES_ENCRYPT MBEDTLS_AES_ENCRYPT +#define ASN1_BIT_STRING MBEDTLS_ASN1_BIT_STRING +#define ASN1_BMP_STRING MBEDTLS_ASN1_BMP_STRING +#define ASN1_BOOLEAN MBEDTLS_ASN1_BOOLEAN +#define ASN1_CHK_ADD MBEDTLS_ASN1_CHK_ADD +#define ASN1_CONSTRUCTED MBEDTLS_ASN1_CONSTRUCTED +#define ASN1_CONTEXT_SPECIFIC MBEDTLS_ASN1_CONTEXT_SPECIFIC +#define ASN1_GENERALIZED_TIME MBEDTLS_ASN1_GENERALIZED_TIME +#define ASN1_IA5_STRING MBEDTLS_ASN1_IA5_STRING +#define ASN1_INTEGER MBEDTLS_ASN1_INTEGER +#define ASN1_NULL MBEDTLS_ASN1_NULL +#define ASN1_OCTET_STRING MBEDTLS_ASN1_OCTET_STRING +#define ASN1_OID MBEDTLS_ASN1_OID +#define ASN1_PRIMITIVE MBEDTLS_ASN1_PRIMITIVE +#define ASN1_PRINTABLE_STRING MBEDTLS_ASN1_PRINTABLE_STRING +#define ASN1_SEQUENCE MBEDTLS_ASN1_SEQUENCE +#define ASN1_SET MBEDTLS_ASN1_SET +#define ASN1_T61_STRING MBEDTLS_ASN1_T61_STRING +#define ASN1_UNIVERSAL_STRING MBEDTLS_ASN1_UNIVERSAL_STRING +#define ASN1_UTC_TIME MBEDTLS_ASN1_UTC_TIME +#define ASN1_UTF8_STRING MBEDTLS_ASN1_UTF8_STRING +#define BADCERT_CN_MISMATCH MBEDTLS_X509_BADCERT_CN_MISMATCH +#define BADCERT_EXPIRED MBEDTLS_X509_BADCERT_EXPIRED +#define BADCERT_FUTURE MBEDTLS_X509_BADCERT_FUTURE +#define BADCERT_MISSING MBEDTLS_X509_BADCERT_MISSING +#define BADCERT_NOT_TRUSTED MBEDTLS_X509_BADCERT_NOT_TRUSTED +#define BADCERT_OTHER MBEDTLS_X509_BADCERT_OTHER +#define BADCERT_REVOKED MBEDTLS_X509_BADCERT_REVOKED +#define BADCERT_SKIP_VERIFY MBEDTLS_X509_BADCERT_SKIP_VERIFY +#define BADCRL_EXPIRED MBEDTLS_X509_BADCRL_EXPIRED +#define BADCRL_FUTURE MBEDTLS_X509_BADCRL_FUTURE +#define BADCRL_NOT_TRUSTED MBEDTLS_X509_BADCRL_NOT_TRUSTED +#define BLOWFISH_BLOCKSIZE MBEDTLS_BLOWFISH_BLOCKSIZE +#define BLOWFISH_DECRYPT MBEDTLS_BLOWFISH_DECRYPT +#define BLOWFISH_ENCRYPT MBEDTLS_BLOWFISH_ENCRYPT +#define BLOWFISH_MAX_KEY MBEDTLS_BLOWFISH_MAX_KEY_BITS +#define BLOWFISH_MIN_KEY MBEDTLS_BLOWFISH_MIN_KEY_BITS +#define BLOWFISH_ROUNDS MBEDTLS_BLOWFISH_ROUNDS +#define CAMELLIA_DECRYPT MBEDTLS_CAMELLIA_DECRYPT +#define CAMELLIA_ENCRYPT MBEDTLS_CAMELLIA_ENCRYPT +#define COLLECT_SIZE MBEDTLS_HAVEGE_COLLECT_SIZE +#define CTR_DRBG_BLOCKSIZE MBEDTLS_CTR_DRBG_BLOCKSIZE +#define CTR_DRBG_ENTROPY_LEN MBEDTLS_CTR_DRBG_ENTROPY_LEN +#define CTR_DRBG_KEYBITS MBEDTLS_CTR_DRBG_KEYBITS +#define CTR_DRBG_KEYSIZE MBEDTLS_CTR_DRBG_KEYSIZE +#define CTR_DRBG_MAX_INPUT MBEDTLS_CTR_DRBG_MAX_INPUT +#define CTR_DRBG_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST +#define CTR_DRBG_MAX_SEED_INPUT MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +#define CTR_DRBG_PR_OFF MBEDTLS_CTR_DRBG_PR_OFF +#define CTR_DRBG_PR_ON MBEDTLS_CTR_DRBG_PR_ON +#define CTR_DRBG_RESEED_INTERVAL MBEDTLS_CTR_DRBG_RESEED_INTERVAL +#define CTR_DRBG_SEEDLEN MBEDTLS_CTR_DRBG_SEEDLEN +#define DEPRECATED MBEDTLS_DEPRECATED +#define DES_DECRYPT MBEDTLS_DES_DECRYPT +#define DES_ENCRYPT MBEDTLS_DES_ENCRYPT +#define DES_KEY_SIZE MBEDTLS_DES_KEY_SIZE +#define ENTROPY_BLOCK_SIZE MBEDTLS_ENTROPY_BLOCK_SIZE +#define ENTROPY_MAX_GATHER MBEDTLS_ENTROPY_MAX_GATHER +#define ENTROPY_MAX_SEED_SIZE MBEDTLS_ENTROPY_MAX_SEED_SIZE +#define ENTROPY_MAX_SOURCES MBEDTLS_ENTROPY_MAX_SOURCES +#define ENTROPY_MIN_HARDCLOCK MBEDTLS_ENTROPY_MIN_HARDCLOCK +#define ENTROPY_MIN_HAVEGE MBEDTLS_ENTROPY_MIN_HAVEGE +#define ENTROPY_MIN_PLATFORM MBEDTLS_ENTROPY_MIN_PLATFORM +#define ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_SOURCE_MANUAL +#define EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER +#define EXT_BASIC_CONSTRAINTS MBEDTLS_X509_EXT_BASIC_CONSTRAINTS +#define EXT_CERTIFICATE_POLICIES MBEDTLS_X509_EXT_CERTIFICATE_POLICIES +#define EXT_CRL_DISTRIBUTION_POINTS MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS +#define EXT_EXTENDED_KEY_USAGE MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE +#define EXT_FRESHEST_CRL MBEDTLS_X509_EXT_FRESHEST_CRL +#define EXT_INIHIBIT_ANYPOLICY MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY +#define EXT_ISSUER_ALT_NAME MBEDTLS_X509_EXT_ISSUER_ALT_NAME +#define EXT_KEY_USAGE MBEDTLS_X509_EXT_KEY_USAGE +#define EXT_NAME_CONSTRAINTS MBEDTLS_X509_EXT_NAME_CONSTRAINTS +#define EXT_NS_CERT_TYPE MBEDTLS_X509_EXT_NS_CERT_TYPE +#define EXT_POLICY_CONSTRAINTS MBEDTLS_X509_EXT_POLICY_CONSTRAINTS +#define EXT_POLICY_MAPPINGS MBEDTLS_X509_EXT_POLICY_MAPPINGS +#define EXT_SUBJECT_ALT_NAME MBEDTLS_X509_EXT_SUBJECT_ALT_NAME +#define EXT_SUBJECT_DIRECTORY_ATTRS MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS +#define EXT_SUBJECT_KEY_IDENTIFIER MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER +#define GCM_DECRYPT MBEDTLS_GCM_DECRYPT +#define GCM_ENCRYPT MBEDTLS_GCM_ENCRYPT +#define KU_CRL_SIGN MBEDTLS_X509_KU_CRL_SIGN +#define KU_DATA_ENCIPHERMENT MBEDTLS_X509_KU_DATA_ENCIPHERMENT +#define KU_DIGITAL_SIGNATURE MBEDTLS_X509_KU_DIGITAL_SIGNATURE +#define KU_KEY_AGREEMENT MBEDTLS_X509_KU_KEY_AGREEMENT +#define KU_KEY_CERT_SIGN MBEDTLS_X509_KU_KEY_CERT_SIGN +#define KU_KEY_ENCIPHERMENT MBEDTLS_X509_KU_KEY_ENCIPHERMENT +#define KU_NON_REPUDIATION MBEDTLS_X509_KU_NON_REPUDIATION +#define LN_2_DIV_LN_10_SCALE100 MBEDTLS_LN_2_DIV_LN_10_SCALE100 +#define MD_CONTEXT_T_INIT MBEDTLS_MD_CONTEXT_T_INIT +#define MEMORY_VERIFY_ALLOC MBEDTLS_MEMORY_VERIFY_ALLOC +#define MEMORY_VERIFY_ALWAYS MBEDTLS_MEMORY_VERIFY_ALWAYS +#define MEMORY_VERIFY_FREE MBEDTLS_MEMORY_VERIFY_FREE +#define MEMORY_VERIFY_NONE MBEDTLS_MEMORY_VERIFY_NONE +#define MPI_CHK MBEDTLS_MPI_CHK +#define NET_PROTO_TCP MBEDTLS_NET_PROTO_TCP +#define NET_PROTO_UDP MBEDTLS_NET_PROTO_UDP +#define NS_CERT_TYPE_EMAIL MBEDTLS_X509_NS_CERT_TYPE_EMAIL +#define NS_CERT_TYPE_EMAIL_CA MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA +#define NS_CERT_TYPE_OBJECT_SIGNING MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING +#define NS_CERT_TYPE_OBJECT_SIGNING_CA MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA +#define NS_CERT_TYPE_RESERVED MBEDTLS_X509_NS_CERT_TYPE_RESERVED +#define NS_CERT_TYPE_SSL_CA MBEDTLS_X509_NS_CERT_TYPE_SSL_CA +#define NS_CERT_TYPE_SSL_CLIENT MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT +#define NS_CERT_TYPE_SSL_SERVER MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER +#define OID_ANSI_X9_62 MBEDTLS_OID_ANSI_X9_62 +#define OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE +#define OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD +#define OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62_SIG +#define OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 +#define OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE +#define OID_AT MBEDTLS_OID_AT +#define OID_AT_CN MBEDTLS_OID_AT_CN +#define OID_AT_COUNTRY MBEDTLS_OID_AT_COUNTRY +#define OID_AT_DN_QUALIFIER MBEDTLS_OID_AT_DN_QUALIFIER +#define OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT_GENERATION_QUALIFIER +#define OID_AT_GIVEN_NAME MBEDTLS_OID_AT_GIVEN_NAME +#define OID_AT_INITIALS MBEDTLS_OID_AT_INITIALS +#define OID_AT_LOCALITY MBEDTLS_OID_AT_LOCALITY +#define OID_AT_ORGANIZATION MBEDTLS_OID_AT_ORGANIZATION +#define OID_AT_ORG_UNIT MBEDTLS_OID_AT_ORG_UNIT +#define OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT_POSTAL_ADDRESS +#define OID_AT_POSTAL_CODE MBEDTLS_OID_AT_POSTAL_CODE +#define OID_AT_PSEUDONYM MBEDTLS_OID_AT_PSEUDONYM +#define OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT_SERIAL_NUMBER +#define OID_AT_STATE MBEDTLS_OID_AT_STATE +#define OID_AT_SUR_NAME MBEDTLS_OID_AT_SUR_NAME +#define OID_AT_TITLE MBEDTLS_OID_AT_TITLE +#define OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT_UNIQUE_IDENTIFIER +#define OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER +#define OID_BASIC_CONSTRAINTS MBEDTLS_OID_BASIC_CONSTRAINTS +#define OID_CERTICOM MBEDTLS_OID_CERTICOM +#define OID_CERTIFICATE_POLICIES MBEDTLS_OID_CERTIFICATE_POLICIES +#define OID_CLIENT_AUTH MBEDTLS_OID_CLIENT_AUTH +#define OID_CMP MBEDTLS_OID_CMP +#define OID_CODE_SIGNING MBEDTLS_OID_CODE_SIGNING +#define OID_COUNTRY_US MBEDTLS_OID_COUNTRY_US +#define OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_CRL_DISTRIBUTION_POINTS +#define OID_CRL_NUMBER MBEDTLS_OID_CRL_NUMBER +#define OID_DES_CBC MBEDTLS_OID_DES_CBC +#define OID_DES_EDE3_CBC MBEDTLS_OID_DES_EDE3_CBC +#define OID_DIGEST_ALG_MD2 MBEDTLS_OID_DIGEST_ALG_MD2 +#define OID_DIGEST_ALG_MD4 MBEDTLS_OID_DIGEST_ALG_MD4 +#define OID_DIGEST_ALG_MD5 MBEDTLS_OID_DIGEST_ALG_MD5 +#define OID_DIGEST_ALG_SHA1 MBEDTLS_OID_DIGEST_ALG_SHA1 +#define OID_DIGEST_ALG_SHA224 MBEDTLS_OID_DIGEST_ALG_SHA224 +#define OID_DIGEST_ALG_SHA256 MBEDTLS_OID_DIGEST_ALG_SHA256 +#define OID_DIGEST_ALG_SHA384 MBEDTLS_OID_DIGEST_ALG_SHA384 +#define OID_DIGEST_ALG_SHA512 MBEDTLS_OID_DIGEST_ALG_SHA512 +#define OID_DOMAIN_COMPONENT MBEDTLS_OID_DOMAIN_COMPONENT +#define OID_ECDSA_SHA1 MBEDTLS_OID_ECDSA_SHA1 +#define OID_ECDSA_SHA224 MBEDTLS_OID_ECDSA_SHA224 +#define OID_ECDSA_SHA256 MBEDTLS_OID_ECDSA_SHA256 +#define OID_ECDSA_SHA384 MBEDTLS_OID_ECDSA_SHA384 +#define OID_ECDSA_SHA512 MBEDTLS_OID_ECDSA_SHA512 +#define OID_EC_ALG_ECDH MBEDTLS_OID_EC_ALG_ECDH +#define OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_EC_ALG_UNRESTRICTED +#define OID_EC_BRAINPOOL_V1 MBEDTLS_OID_EC_BRAINPOOL_V1 +#define OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_GRP_BP256R1 +#define OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_GRP_BP384R1 +#define OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_GRP_BP512R1 +#define OID_EC_GRP_SECP192K1 MBEDTLS_OID_EC_GRP_SECP192K1 +#define OID_EC_GRP_SECP192R1 MBEDTLS_OID_EC_GRP_SECP192R1 +#define OID_EC_GRP_SECP224K1 MBEDTLS_OID_EC_GRP_SECP224K1 +#define OID_EC_GRP_SECP224R1 MBEDTLS_OID_EC_GRP_SECP224R1 +#define OID_EC_GRP_SECP256K1 MBEDTLS_OID_EC_GRP_SECP256K1 +#define OID_EC_GRP_SECP256R1 MBEDTLS_OID_EC_GRP_SECP256R1 +#define OID_EC_GRP_SECP384R1 MBEDTLS_OID_EC_GRP_SECP384R1 +#define OID_EC_GRP_SECP521R1 MBEDTLS_OID_EC_GRP_SECP521R1 +#define OID_EMAIL_PROTECTION MBEDTLS_OID_EMAIL_PROTECTION +#define OID_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE +#define OID_FRESHEST_CRL MBEDTLS_OID_FRESHEST_CRL +#define OID_GOV MBEDTLS_OID_GOV +#define OID_HMAC_SHA1 MBEDTLS_OID_HMAC_SHA1 +#define OID_ID_CE MBEDTLS_OID_ID_CE +#define OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_INIHIBIT_ANYPOLICY +#define OID_ISO_CCITT_DS MBEDTLS_OID_ISO_CCITT_DS +#define OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ISO_IDENTIFIED_ORG +#define OID_ISO_ITU_COUNTRY MBEDTLS_OID_ISO_ITU_COUNTRY +#define OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_US_ORG +#define OID_ISO_MEMBER_BODIES MBEDTLS_OID_ISO_MEMBER_BODIES +#define OID_ISSUER_ALT_NAME MBEDTLS_OID_ISSUER_ALT_NAME +#define OID_KEY_USAGE MBEDTLS_OID_KEY_USAGE +#define OID_KP MBEDTLS_OID_KP +#define OID_MGF1 MBEDTLS_OID_MGF1 +#define OID_NAME_CONSTRAINTS MBEDTLS_OID_NAME_CONSTRAINTS +#define OID_NETSCAPE MBEDTLS_OID_NETSCAPE +#define OID_NS_BASE_URL MBEDTLS_OID_NS_BASE_URL +#define OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CA_POLICY_URL +#define OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CA_REVOCATION_URL +#define OID_NS_CERT MBEDTLS_OID_NS_CERT +#define OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_CERT_SEQUENCE +#define OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT_TYPE +#define OID_NS_COMMENT MBEDTLS_OID_NS_COMMENT +#define OID_NS_DATA_TYPE MBEDTLS_OID_NS_DATA_TYPE +#define OID_NS_RENEWAL_URL MBEDTLS_OID_NS_RENEWAL_URL +#define OID_NS_REVOCATION_URL MBEDTLS_OID_NS_REVOCATION_URL +#define OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_SSL_SERVER_NAME +#define OID_OCSP_SIGNING MBEDTLS_OID_OCSP_SIGNING +#define OID_OIW_SECSIG MBEDTLS_OID_OIW_SECSIG +#define OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG_ALG +#define OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_SHA1 +#define OID_ORGANIZATION MBEDTLS_OID_ORGANIZATION +#define OID_ORG_ANSI_X9_62 MBEDTLS_OID_ORG_ANSI_X9_62 +#define OID_ORG_CERTICOM MBEDTLS_OID_ORG_CERTICOM +#define OID_ORG_DOD MBEDTLS_OID_ORG_DOD +#define OID_ORG_GOV MBEDTLS_OID_ORG_GOV +#define OID_ORG_NETSCAPE MBEDTLS_OID_ORG_NETSCAPE +#define OID_ORG_OIW MBEDTLS_OID_ORG_OIW +#define OID_ORG_RSA_DATA_SECURITY MBEDTLS_OID_ORG_RSA_DATA_SECURITY +#define OID_ORG_TELETRUST MBEDTLS_OID_ORG_TELETRUST +#define OID_PKCS MBEDTLS_OID_PKCS +#define OID_PKCS1 MBEDTLS_OID_PKCS1 +#define OID_PKCS12 MBEDTLS_OID_PKCS12 +#define OID_PKCS12_PBE MBEDTLS_OID_PKCS12_PBE +#define OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC +#define OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC +#define OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC +#define OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC +#define OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 +#define OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 +#define OID_PKCS1_MD2 MBEDTLS_OID_PKCS1_MD2 +#define OID_PKCS1_MD4 MBEDTLS_OID_PKCS1_MD4 +#define OID_PKCS1_MD5 MBEDTLS_OID_PKCS1_MD5 +#define OID_PKCS1_RSA MBEDTLS_OID_PKCS1_RSA +#define OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1_SHA1 +#define OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1_SHA224 +#define OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1_SHA256 +#define OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1_SHA384 +#define OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1_SHA512 +#define OID_PKCS5 MBEDTLS_OID_PKCS5 +#define OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5_PBES2 +#define OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC +#define OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC +#define OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC +#define OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC +#define OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC +#define OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC +#define OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5_PBKDF2 +#define OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5_PBMAC1 +#define OID_PKCS9 MBEDTLS_OID_PKCS9 +#define OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9_CSR_EXT_REQ +#define OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9_EMAIL +#define OID_PKIX MBEDTLS_OID_PKIX +#define OID_POLICY_CONSTRAINTS MBEDTLS_OID_POLICY_CONSTRAINTS +#define OID_POLICY_MAPPINGS MBEDTLS_OID_POLICY_MAPPINGS +#define OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD +#define OID_RSASSA_PSS MBEDTLS_OID_RSASSA_PSS +#define OID_RSA_COMPANY MBEDTLS_OID_RSA_COMPANY +#define OID_RSA_SHA_OBS MBEDTLS_OID_RSA_SHA_OBS +#define OID_SERVER_AUTH MBEDTLS_OID_SERVER_AUTH +#define OID_SIZE MBEDTLS_OID_SIZE +#define OID_SUBJECT_ALT_NAME MBEDTLS_OID_SUBJECT_ALT_NAME +#define OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS +#define OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER +#define OID_TELETRUST MBEDTLS_OID_TELETRUST +#define OID_TIME_STAMPING MBEDTLS_OID_TIME_STAMPING +#define PADLOCK_ACE MBEDTLS_PADLOCK_ACE +#define PADLOCK_ALIGN16 MBEDTLS_PADLOCK_ALIGN16 +#define PADLOCK_PHE MBEDTLS_PADLOCK_PHE +#define PADLOCK_PMM MBEDTLS_PADLOCK_PMM +#define PADLOCK_RNG MBEDTLS_PADLOCK_RNG +#define PKCS12_DERIVE_IV MBEDTLS_PKCS12_DERIVE_IV +#define PKCS12_DERIVE_KEY MBEDTLS_PKCS12_DERIVE_KEY +#define PKCS12_DERIVE_MAC_KEY MBEDTLS_PKCS12_DERIVE_MAC_KEY +#define PKCS12_PBE_DECRYPT MBEDTLS_PKCS12_PBE_DECRYPT +#define PKCS12_PBE_ENCRYPT MBEDTLS_PKCS12_PBE_ENCRYPT +#define PKCS5_DECRYPT MBEDTLS_PKCS5_DECRYPT +#define PKCS5_ENCRYPT MBEDTLS_PKCS5_ENCRYPT +#define POLARSSL_AESNI_AES MBEDTLS_AESNI_AES +#define POLARSSL_AESNI_CLMUL MBEDTLS_AESNI_CLMUL +#define POLARSSL_AESNI_H MBEDTLS_AESNI_H +#define POLARSSL_AES_H MBEDTLS_AES_H +#define POLARSSL_ARC4_H MBEDTLS_ARC4_H +#define POLARSSL_ASN1_H MBEDTLS_ASN1_H +#define POLARSSL_ASN1_WRITE_H MBEDTLS_ASN1_WRITE_H +#define POLARSSL_BASE64_H MBEDTLS_BASE64_H +#define POLARSSL_BIGNUM_H MBEDTLS_BIGNUM_H +#define POLARSSL_BLOWFISH_H MBEDTLS_BLOWFISH_H +#define POLARSSL_BN_MUL_H MBEDTLS_BN_MUL_H +#define POLARSSL_CAMELLIA_H MBEDTLS_CAMELLIA_H +#define POLARSSL_CCM_H MBEDTLS_CCM_H +#define POLARSSL_CERTS_H MBEDTLS_CERTS_H +#define POLARSSL_CHECK_CONFIG_H MBEDTLS_CHECK_CONFIG_H +#define POLARSSL_CIPHERSUITE_NODTLS MBEDTLS_CIPHERSUITE_NODTLS +#define POLARSSL_CIPHERSUITE_SHORT_TAG MBEDTLS_CIPHERSUITE_SHORT_TAG +#define POLARSSL_CIPHERSUITE_WEAK MBEDTLS_CIPHERSUITE_WEAK +#define POLARSSL_CIPHER_AES_128_CBC MBEDTLS_CIPHER_AES_128_CBC +#define POLARSSL_CIPHER_AES_128_CCM MBEDTLS_CIPHER_AES_128_CCM +#define POLARSSL_CIPHER_AES_128_CFB128 MBEDTLS_CIPHER_AES_128_CFB128 +#define POLARSSL_CIPHER_AES_128_CTR MBEDTLS_CIPHER_AES_128_CTR +#define POLARSSL_CIPHER_AES_128_ECB MBEDTLS_CIPHER_AES_128_ECB +#define POLARSSL_CIPHER_AES_128_GCM MBEDTLS_CIPHER_AES_128_GCM +#define POLARSSL_CIPHER_AES_192_CBC MBEDTLS_CIPHER_AES_192_CBC +#define POLARSSL_CIPHER_AES_192_CCM MBEDTLS_CIPHER_AES_192_CCM +#define POLARSSL_CIPHER_AES_192_CFB128 MBEDTLS_CIPHER_AES_192_CFB128 +#define POLARSSL_CIPHER_AES_192_CTR MBEDTLS_CIPHER_AES_192_CTR +#define POLARSSL_CIPHER_AES_192_ECB MBEDTLS_CIPHER_AES_192_ECB +#define POLARSSL_CIPHER_AES_192_GCM MBEDTLS_CIPHER_AES_192_GCM +#define POLARSSL_CIPHER_AES_256_CBC MBEDTLS_CIPHER_AES_256_CBC +#define POLARSSL_CIPHER_AES_256_CCM MBEDTLS_CIPHER_AES_256_CCM +#define POLARSSL_CIPHER_AES_256_CFB128 MBEDTLS_CIPHER_AES_256_CFB128 +#define POLARSSL_CIPHER_AES_256_CTR MBEDTLS_CIPHER_AES_256_CTR +#define POLARSSL_CIPHER_AES_256_ECB MBEDTLS_CIPHER_AES_256_ECB +#define POLARSSL_CIPHER_AES_256_GCM MBEDTLS_CIPHER_AES_256_GCM +#define POLARSSL_CIPHER_ARC4_128 MBEDTLS_CIPHER_ARC4_128 +#define POLARSSL_CIPHER_BLOWFISH_CBC MBEDTLS_CIPHER_BLOWFISH_CBC +#define POLARSSL_CIPHER_BLOWFISH_CFB64 MBEDTLS_CIPHER_BLOWFISH_CFB64 +#define POLARSSL_CIPHER_BLOWFISH_CTR MBEDTLS_CIPHER_BLOWFISH_CTR +#define POLARSSL_CIPHER_BLOWFISH_ECB MBEDTLS_CIPHER_BLOWFISH_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_CBC MBEDTLS_CIPHER_CAMELLIA_128_CBC +#define POLARSSL_CIPHER_CAMELLIA_128_CCM MBEDTLS_CIPHER_CAMELLIA_128_CCM +#define POLARSSL_CIPHER_CAMELLIA_128_CFB128 MBEDTLS_CIPHER_CAMELLIA_128_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_128_CTR MBEDTLS_CIPHER_CAMELLIA_128_CTR +#define POLARSSL_CIPHER_CAMELLIA_128_ECB MBEDTLS_CIPHER_CAMELLIA_128_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_GCM MBEDTLS_CIPHER_CAMELLIA_128_GCM +#define POLARSSL_CIPHER_CAMELLIA_192_CBC MBEDTLS_CIPHER_CAMELLIA_192_CBC +#define POLARSSL_CIPHER_CAMELLIA_192_CCM MBEDTLS_CIPHER_CAMELLIA_192_CCM +#define POLARSSL_CIPHER_CAMELLIA_192_CFB128 MBEDTLS_CIPHER_CAMELLIA_192_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_192_CTR MBEDTLS_CIPHER_CAMELLIA_192_CTR +#define POLARSSL_CIPHER_CAMELLIA_192_ECB MBEDTLS_CIPHER_CAMELLIA_192_ECB +#define POLARSSL_CIPHER_CAMELLIA_192_GCM MBEDTLS_CIPHER_CAMELLIA_192_GCM +#define POLARSSL_CIPHER_CAMELLIA_256_CBC MBEDTLS_CIPHER_CAMELLIA_256_CBC +#define POLARSSL_CIPHER_CAMELLIA_256_CCM MBEDTLS_CIPHER_CAMELLIA_256_CCM +#define POLARSSL_CIPHER_CAMELLIA_256_CFB128 MBEDTLS_CIPHER_CAMELLIA_256_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_256_CTR MBEDTLS_CIPHER_CAMELLIA_256_CTR +#define POLARSSL_CIPHER_CAMELLIA_256_ECB MBEDTLS_CIPHER_CAMELLIA_256_ECB +#define POLARSSL_CIPHER_CAMELLIA_256_GCM MBEDTLS_CIPHER_CAMELLIA_256_GCM +#define POLARSSL_CIPHER_DES_CBC MBEDTLS_CIPHER_DES_CBC +#define POLARSSL_CIPHER_DES_ECB MBEDTLS_CIPHER_DES_ECB +#define POLARSSL_CIPHER_DES_EDE3_CBC MBEDTLS_CIPHER_DES_EDE3_CBC +#define POLARSSL_CIPHER_DES_EDE3_ECB MBEDTLS_CIPHER_DES_EDE3_ECB +#define POLARSSL_CIPHER_DES_EDE_CBC MBEDTLS_CIPHER_DES_EDE_CBC +#define POLARSSL_CIPHER_DES_EDE_ECB MBEDTLS_CIPHER_DES_EDE_ECB +#define POLARSSL_CIPHER_H MBEDTLS_CIPHER_H +#define POLARSSL_CIPHER_ID_3DES MBEDTLS_CIPHER_ID_3DES +#define POLARSSL_CIPHER_ID_AES MBEDTLS_CIPHER_ID_AES +#define POLARSSL_CIPHER_ID_ARC4 MBEDTLS_CIPHER_ID_ARC4 +#define POLARSSL_CIPHER_ID_BLOWFISH MBEDTLS_CIPHER_ID_BLOWFISH +#define POLARSSL_CIPHER_ID_CAMELLIA MBEDTLS_CIPHER_ID_CAMELLIA +#define POLARSSL_CIPHER_ID_DES MBEDTLS_CIPHER_ID_DES +#define POLARSSL_CIPHER_ID_NONE MBEDTLS_CIPHER_ID_NONE +#define POLARSSL_CIPHER_ID_NULL MBEDTLS_CIPHER_ID_NULL +#define POLARSSL_CIPHER_MODE_AEAD MBEDTLS_CIPHER_MODE_AEAD +#define POLARSSL_CIPHER_MODE_STREAM MBEDTLS_CIPHER_MODE_STREAM +#define POLARSSL_CIPHER_MODE_WITH_PADDING MBEDTLS_CIPHER_MODE_WITH_PADDING +#define POLARSSL_CIPHER_NONE MBEDTLS_CIPHER_NONE +#define POLARSSL_CIPHER_NULL MBEDTLS_CIPHER_NULL +#define POLARSSL_CIPHER_VARIABLE_IV_LEN MBEDTLS_CIPHER_VARIABLE_IV_LEN +#define POLARSSL_CIPHER_VARIABLE_KEY_LEN MBEDTLS_CIPHER_VARIABLE_KEY_LEN +#define POLARSSL_CIPHER_WRAP_H MBEDTLS_CIPHER_WRAP_H +#define POLARSSL_CONFIG_H MBEDTLS_CONFIG_H +#define POLARSSL_CTR_DRBG_H MBEDTLS_CTR_DRBG_H +#define POLARSSL_DEBUG_H MBEDTLS_DEBUG_H +#define POLARSSL_DEBUG_LOG_FULL MBEDTLS_DEBUG_LOG_FULL +#define POLARSSL_DEBUG_LOG_RAW MBEDTLS_DEBUG_LOG_RAW +#define POLARSSL_DECRYPT MBEDTLS_DECRYPT +#define POLARSSL_DES_H MBEDTLS_DES_H +#define POLARSSL_DHM_H MBEDTLS_DHM_H +#define POLARSSL_DHM_RFC2409_MODP_1024_G MBEDTLS_DHM_RFC2409_MODP_1024_G +#define POLARSSL_DHM_RFC2409_MODP_1024_P MBEDTLS_DHM_RFC2409_MODP_1024_P +#define POLARSSL_DHM_RFC3526_MODP_2048_G MBEDTLS_DHM_RFC3526_MODP_2048_G +#define POLARSSL_DHM_RFC3526_MODP_2048_P MBEDTLS_DHM_RFC3526_MODP_2048_P +#define POLARSSL_DHM_RFC3526_MODP_3072_G MBEDTLS_DHM_RFC3526_MODP_3072_G +#define POLARSSL_DHM_RFC3526_MODP_3072_P MBEDTLS_DHM_RFC3526_MODP_3072_P +#define POLARSSL_DHM_RFC5114_MODP_1024_G MBEDTLS_DHM_RFC5114_MODP_1024_G +#define POLARSSL_DHM_RFC5114_MODP_1024_P MBEDTLS_DHM_RFC5114_MODP_1024_P +#define POLARSSL_DHM_RFC5114_MODP_2048_G MBEDTLS_DHM_RFC5114_MODP_2048_G +#define POLARSSL_DHM_RFC5114_MODP_2048_P MBEDTLS_DHM_RFC5114_MODP_2048_P +#define POLARSSL_ECDH_H MBEDTLS_ECDH_H +#define POLARSSL_ECDH_OURS MBEDTLS_ECDH_OURS +#define POLARSSL_ECDH_THEIRS MBEDTLS_ECDH_THEIRS +#define POLARSSL_ECDSA_H MBEDTLS_ECDSA_H +#define POLARSSL_ECP_DP_BP256R1 MBEDTLS_ECP_DP_BP256R1 +#define POLARSSL_ECP_DP_BP384R1 MBEDTLS_ECP_DP_BP384R1 +#define POLARSSL_ECP_DP_BP512R1 MBEDTLS_ECP_DP_BP512R1 +#define POLARSSL_ECP_DP_M255 MBEDTLS_ECP_DP_CURVE25519 +#define POLARSSL_ECP_DP_MAX MBEDTLS_ECP_DP_MAX +#define POLARSSL_ECP_DP_NONE MBEDTLS_ECP_DP_NONE +#define POLARSSL_ECP_DP_SECP192K1 MBEDTLS_ECP_DP_SECP192K1 +#define POLARSSL_ECP_DP_SECP192R1 MBEDTLS_ECP_DP_SECP192R1 +#define POLARSSL_ECP_DP_SECP224K1 MBEDTLS_ECP_DP_SECP224K1 +#define POLARSSL_ECP_DP_SECP224R1 MBEDTLS_ECP_DP_SECP224R1 +#define POLARSSL_ECP_DP_SECP256K1 MBEDTLS_ECP_DP_SECP256K1 +#define POLARSSL_ECP_DP_SECP256R1 MBEDTLS_ECP_DP_SECP256R1 +#define POLARSSL_ECP_DP_SECP384R1 MBEDTLS_ECP_DP_SECP384R1 +#define POLARSSL_ECP_DP_SECP521R1 MBEDTLS_ECP_DP_SECP521R1 +#define POLARSSL_ECP_H MBEDTLS_ECP_H +#define POLARSSL_ECP_MAX_BYTES MBEDTLS_ECP_MAX_BYTES +#define POLARSSL_ECP_MAX_PT_LEN MBEDTLS_ECP_MAX_PT_LEN +#define POLARSSL_ECP_PF_COMPRESSED MBEDTLS_ECP_PF_COMPRESSED +#define POLARSSL_ECP_PF_UNCOMPRESSED MBEDTLS_ECP_PF_UNCOMPRESSED +#define POLARSSL_ECP_TLS_NAMED_CURVE MBEDTLS_ECP_TLS_NAMED_CURVE +#define POLARSSL_ENCRYPT MBEDTLS_ENCRYPT +#define POLARSSL_ENTROPY_H MBEDTLS_ENTROPY_H +#define POLARSSL_ENTROPY_POLL_H MBEDTLS_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_SHA256_ACCUMULATOR MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#define POLARSSL_ENTROPY_SHA512_ACCUMULATOR MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#define POLARSSL_ERROR_H MBEDTLS_ERROR_H +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH MBEDTLS_ERR_AES_INVALID_KEY_LENGTH +#define POLARSSL_ERR_ASN1_BUF_TOO_SMALL MBEDTLS_ERR_ASN1_BUF_TOO_SMALL +#define POLARSSL_ERR_ASN1_INVALID_DATA MBEDTLS_ERR_ASN1_INVALID_DATA +#define POLARSSL_ERR_ASN1_INVALID_LENGTH MBEDTLS_ERR_ASN1_INVALID_LENGTH +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH MBEDTLS_ERR_ASN1_LENGTH_MISMATCH +#define POLARSSL_ERR_ASN1_MALLOC_FAILED MBEDTLS_ERR_ASN1_ALLOC_FAILED +#define POLARSSL_ERR_ASN1_OUT_OF_DATA MBEDTLS_ERR_ASN1_OUT_OF_DATA +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG MBEDTLS_ERR_ASN1_UNEXPECTED_TAG +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER MBEDTLS_ERR_BASE64_INVALID_CHARACTER +#define POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CCM_AUTH_FAILED MBEDTLS_ERR_CCM_AUTH_FAILED +#define POLARSSL_ERR_CCM_BAD_INPUT MBEDTLS_ERR_CCM_BAD_INPUT +#define POLARSSL_ERR_CIPHER_ALLOC_FAILED MBEDTLS_ERR_CIPHER_ALLOC_FAILED +#define POLARSSL_ERR_CIPHER_AUTH_FAILED MBEDTLS_ERR_CIPHER_AUTH_FAILED +#define POLARSSL_ERR_CIPHER_BAD_INPUT_DATA MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA +#define POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED +#define POLARSSL_ERR_CIPHER_INVALID_PADDING MBEDTLS_ERR_CIPHER_INVALID_PADDING +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA MBEDTLS_ERR_DHM_BAD_INPUT_DATA +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED MBEDTLS_ERR_DHM_CALC_SECRET_FAILED +#define POLARSSL_ERR_DHM_FILE_IO_ERROR MBEDTLS_ERR_DHM_FILE_IO_ERROR +#define POLARSSL_ERR_DHM_INVALID_FORMAT MBEDTLS_ERR_DHM_INVALID_FORMAT +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED +#define POLARSSL_ERR_DHM_MALLOC_FAILED MBEDTLS_ERR_DHM_ALLOC_FAILED +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED MBEDTLS_ERR_DHM_READ_PARAMS_FAILED +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED +#define POLARSSL_ERR_ECP_BAD_INPUT_DATA MBEDTLS_ERR_ECP_BAD_INPUT_DATA +#define POLARSSL_ERR_ECP_BUFFER_TOO_SMALL MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL +#define POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_ECP_INVALID_KEY MBEDTLS_ERR_ECP_INVALID_KEY +#define POLARSSL_ERR_ECP_MALLOC_FAILED MBEDTLS_ERR_ECP_ALLOC_FAILED +#define POLARSSL_ERR_ECP_RANDOM_FAILED MBEDTLS_ERR_ECP_RANDOM_FAILED +#define POLARSSL_ERR_ECP_SIG_LEN_MISMATCH MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH +#define POLARSSL_ERR_ECP_VERIFY_FAILED MBEDTLS_ERR_ECP_VERIFY_FAILED +#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES MBEDTLS_ERR_ENTROPY_MAX_SOURCES +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_GCM_AUTH_FAILED MBEDTLS_ERR_GCM_AUTH_FAILED +#define POLARSSL_ERR_GCM_BAD_INPUT MBEDTLS_ERR_GCM_BAD_INPUT +#define POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_MD2_FILE_IO_ERROR MBEDTLS_ERR_MD2_FILE_IO_ERROR +#define POLARSSL_ERR_MD4_FILE_IO_ERROR MBEDTLS_ERR_MD4_FILE_IO_ERROR +#define POLARSSL_ERR_MD5_FILE_IO_ERROR MBEDTLS_ERR_MD5_FILE_IO_ERROR +#define POLARSSL_ERR_MD_ALLOC_FAILED MBEDTLS_ERR_MD_ALLOC_FAILED +#define POLARSSL_ERR_MD_BAD_INPUT_DATA MBEDTLS_ERR_MD_BAD_INPUT_DATA +#define POLARSSL_ERR_MD_FEATURE_UNAVAILABLE MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_MD_FILE_IO_ERROR MBEDTLS_ERR_MD_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA MBEDTLS_ERR_MPI_BAD_INPUT_DATA +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO MBEDTLS_ERR_MPI_DIVISION_BY_ZERO +#define POLARSSL_ERR_MPI_FILE_IO_ERROR MBEDTLS_ERR_MPI_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_INVALID_CHARACTER MBEDTLS_ERR_MPI_INVALID_CHARACTER +#define POLARSSL_ERR_MPI_MALLOC_FAILED MBEDTLS_ERR_MPI_ALLOC_FAILED +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE MBEDTLS_ERR_MPI_NEGATIVE_VALUE +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +#define POLARSSL_ERR_NET_ACCEPT_FAILED MBEDTLS_ERR_NET_ACCEPT_FAILED +#define POLARSSL_ERR_NET_BIND_FAILED MBEDTLS_ERR_NET_BIND_FAILED +#define POLARSSL_ERR_NET_CONNECT_FAILED MBEDTLS_ERR_NET_CONNECT_FAILED +#define POLARSSL_ERR_NET_CONN_RESET MBEDTLS_ERR_NET_CONN_RESET +#define POLARSSL_ERR_NET_LISTEN_FAILED MBEDTLS_ERR_NET_LISTEN_FAILED +#define POLARSSL_ERR_NET_RECV_FAILED MBEDTLS_ERR_NET_RECV_FAILED +#define POLARSSL_ERR_NET_SEND_FAILED MBEDTLS_ERR_NET_SEND_FAILED +#define POLARSSL_ERR_NET_SOCKET_FAILED MBEDTLS_ERR_NET_SOCKET_FAILED +#define POLARSSL_ERR_NET_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT +#define POLARSSL_ERR_NET_UNKNOWN_HOST MBEDTLS_ERR_NET_UNKNOWN_HOST +#define POLARSSL_ERR_NET_WANT_READ MBEDTLS_ERR_SSL_WANT_READ +#define POLARSSL_ERR_NET_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE +#define POLARSSL_ERR_OID_BUF_TOO_SMALL MBEDTLS_ERR_OID_BUF_TOO_SMALL +#define POLARSSL_ERR_OID_NOT_FOUND MBEDTLS_ERR_OID_NOT_FOUND +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED +#define POLARSSL_ERR_PBKDF2_BAD_INPUT_DATA MBEDTLS_ERR_PBKDF2_BAD_INPUT_DATA +#define POLARSSL_ERR_PEM_BAD_INPUT_DATA MBEDTLS_ERR_PEM_BAD_INPUT_DATA +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PEM_INVALID_DATA MBEDTLS_ERR_PEM_INVALID_DATA +#define POLARSSL_ERR_PEM_INVALID_ENC_IV MBEDTLS_ERR_PEM_INVALID_ENC_IV +#define POLARSSL_ERR_PEM_MALLOC_FAILED MBEDTLS_ERR_PEM_ALLOC_FAILED +#define POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH MBEDTLS_ERR_PEM_PASSWORD_MISMATCH +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED MBEDTLS_ERR_PEM_PASSWORD_REQUIRED +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG +#define POLARSSL_ERR_PKCS12_BAD_INPUT_DATA MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH +#define POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS5_INVALID_FORMAT MBEDTLS_ERR_PKCS5_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_BAD_INPUT_DATA MBEDTLS_ERR_PK_BAD_INPUT_DATA +#define POLARSSL_ERR_PK_FEATURE_UNAVAILABLE MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PK_FILE_IO_ERROR MBEDTLS_ERR_PK_FILE_IO_ERROR +#define POLARSSL_ERR_PK_INVALID_ALG MBEDTLS_ERR_PK_INVALID_ALG +#define POLARSSL_ERR_PK_INVALID_PUBKEY MBEDTLS_ERR_PK_INVALID_PUBKEY +#define POLARSSL_ERR_PK_KEY_INVALID_FORMAT MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +#define POLARSSL_ERR_PK_KEY_INVALID_VERSION MBEDTLS_ERR_PK_KEY_INVALID_VERSION +#define POLARSSL_ERR_PK_MALLOC_FAILED MBEDTLS_ERR_PK_ALLOC_FAILED +#define POLARSSL_ERR_PK_PASSWORD_MISMATCH MBEDTLS_ERR_PK_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_PASSWORD_REQUIRED MBEDTLS_ERR_PK_PASSWORD_REQUIRED +#define POLARSSL_ERR_PK_SIG_LEN_MISMATCH MBEDTLS_ERR_PK_SIG_LEN_MISMATCH +#define POLARSSL_ERR_PK_TYPE_MISMATCH MBEDTLS_ERR_PK_TYPE_MISMATCH +#define POLARSSL_ERR_PK_UNKNOWN_NAMED_CURVE MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE +#define POLARSSL_ERR_PK_UNKNOWN_PK_ALG MBEDTLS_ERR_PK_UNKNOWN_PK_ALG +#define POLARSSL_ERR_RIPEMD160_FILE_IO_ERROR MBEDTLS_ERR_RIPEMD160_FILE_IO_ERROR +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA MBEDTLS_ERR_RSA_BAD_INPUT_DATA +#define POLARSSL_ERR_RSA_INVALID_PADDING MBEDTLS_ERR_RSA_INVALID_PADDING +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED MBEDTLS_ERR_RSA_KEY_CHECK_FAILED +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED MBEDTLS_ERR_RSA_KEY_GEN_FAILED +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE +#define POLARSSL_ERR_RSA_PRIVATE_FAILED MBEDTLS_ERR_RSA_PRIVATE_FAILED +#define POLARSSL_ERR_RSA_PUBLIC_FAILED MBEDTLS_ERR_RSA_PUBLIC_FAILED +#define POLARSSL_ERR_RSA_RNG_FAILED MBEDTLS_ERR_RSA_RNG_FAILED +#define POLARSSL_ERR_RSA_VERIFY_FAILED MBEDTLS_ERR_RSA_VERIFY_FAILED +#define POLARSSL_ERR_SHA1_FILE_IO_ERROR MBEDTLS_ERR_SHA1_FILE_IO_ERROR +#define POLARSSL_ERR_SHA256_FILE_IO_ERROR MBEDTLS_ERR_SHA256_FILE_IO_ERROR +#define POLARSSL_ERR_SHA512_FILE_IO_ERROR MBEDTLS_ERR_SHA512_FILE_IO_ERROR +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY +#define POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP +#define POLARSSL_ERR_SSL_BAD_HS_FINISHED MBEDTLS_ERR_SSL_BAD_HS_FINISHED +#define POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET +#define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_INPUT_DATA MBEDTLS_ERR_SSL_BAD_INPUT_DATA +#define POLARSSL_ERR_SSL_BUFFER_TOO_SMALL MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL +#define POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE +#define POLARSSL_ERR_SSL_COMPRESSION_FAILED MBEDTLS_ERR_SSL_COMPRESSION_FAILED +#define POLARSSL_ERR_SSL_CONN_EOF MBEDTLS_ERR_SSL_CONN_EOF +#define POLARSSL_ERR_SSL_COUNTER_WRAPPING MBEDTLS_ERR_SSL_COUNTER_WRAPPING +#define POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE +#define POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED +#define POLARSSL_ERR_SSL_HW_ACCEL_FAILED MBEDTLS_ERR_SSL_HW_ACCEL_FAILED +#define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH +#define POLARSSL_ERR_SSL_INTERNAL_ERROR MBEDTLS_ERR_SSL_INTERNAL_ERROR +#define POLARSSL_ERR_SSL_INVALID_MAC MBEDTLS_ERR_SSL_INVALID_MAC +#define POLARSSL_ERR_SSL_INVALID_RECORD MBEDTLS_ERR_SSL_INVALID_RECORD +#define POLARSSL_ERR_SSL_MALLOC_FAILED MBEDTLS_ERR_SSL_ALLOC_FAILED +#define POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN +#define POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE +#define POLARSSL_ERR_SSL_NO_RNG MBEDTLS_ERR_SSL_NO_RNG +#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE +#define POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY +#define POLARSSL_ERR_SSL_PEER_VERIFY_FAILED MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED +#define POLARSSL_ERR_SSL_PK_TYPE_MISMATCH MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH +#define POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED +#define POLARSSL_ERR_SSL_SESSION_TICKET_EXPIRED MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED +#define POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE +#define POLARSSL_ERR_SSL_UNKNOWN_CIPHER MBEDTLS_ERR_SSL_UNKNOWN_CIPHER +#define POLARSSL_ERR_SSL_UNKNOWN_IDENTITY MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY +#define POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO +#define POLARSSL_ERR_THREADING_BAD_INPUT_DATA MBEDTLS_ERR_THREADING_BAD_INPUT_DATA +#define POLARSSL_ERR_THREADING_FEATURE_UNAVAILABLE MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_THREADING_MUTEX_ERROR MBEDTLS_ERR_THREADING_MUTEX_ERROR +#define POLARSSL_ERR_X509_BAD_INPUT_DATA MBEDTLS_ERR_X509_BAD_INPUT_DATA +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED MBEDTLS_ERR_X509_CERT_VERIFY_FAILED +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_X509_FILE_IO_ERROR MBEDTLS_ERR_X509_FILE_IO_ERROR +#define POLARSSL_ERR_X509_INVALID_ALG MBEDTLS_ERR_X509_INVALID_ALG +#define POLARSSL_ERR_X509_INVALID_DATE MBEDTLS_ERR_X509_INVALID_DATE +#define POLARSSL_ERR_X509_INVALID_EXTENSIONS MBEDTLS_ERR_X509_INVALID_EXTENSIONS +#define POLARSSL_ERR_X509_INVALID_FORMAT MBEDTLS_ERR_X509_INVALID_FORMAT +#define POLARSSL_ERR_X509_INVALID_NAME MBEDTLS_ERR_X509_INVALID_NAME +#define POLARSSL_ERR_X509_INVALID_SERIAL MBEDTLS_ERR_X509_INVALID_SERIAL +#define POLARSSL_ERR_X509_INVALID_SIGNATURE MBEDTLS_ERR_X509_INVALID_SIGNATURE +#define POLARSSL_ERR_X509_INVALID_VERSION MBEDTLS_ERR_X509_INVALID_VERSION +#define POLARSSL_ERR_X509_MALLOC_FAILED MBEDTLS_ERR_X509_ALLOC_FAILED +#define POLARSSL_ERR_X509_SIG_MISMATCH MBEDTLS_ERR_X509_SIG_MISMATCH +#define POLARSSL_ERR_X509_UNKNOWN_OID MBEDTLS_ERR_X509_UNKNOWN_OID +#define POLARSSL_ERR_X509_UNKNOWN_SIG_ALG MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG +#define POLARSSL_ERR_X509_UNKNOWN_VERSION MBEDTLS_ERR_X509_UNKNOWN_VERSION +#define POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH +#define POLARSSL_GCM_H MBEDTLS_GCM_H +#define POLARSSL_HAVEGE_H MBEDTLS_HAVEGE_H +#define POLARSSL_HAVE_INT32 MBEDTLS_HAVE_INT32 +#define POLARSSL_HAVE_INT64 MBEDTLS_HAVE_INT64 +#define POLARSSL_HAVE_UDBL MBEDTLS_HAVE_UDBL +#define POLARSSL_HAVE_X86 MBEDTLS_HAVE_X86 +#define POLARSSL_HAVE_X86_64 MBEDTLS_HAVE_X86_64 +#define POLARSSL_HMAC_DRBG_H MBEDTLS_HMAC_DRBG_H +#define POLARSSL_HMAC_DRBG_PR_OFF MBEDTLS_HMAC_DRBG_PR_OFF +#define POLARSSL_HMAC_DRBG_PR_ON MBEDTLS_HMAC_DRBG_PR_ON +#define POLARSSL_KEY_EXCHANGE_DHE_PSK MBEDTLS_KEY_EXCHANGE_DHE_PSK +#define POLARSSL_KEY_EXCHANGE_DHE_RSA MBEDTLS_KEY_EXCHANGE_DHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK MBEDTLS_KEY_EXCHANGE_ECDHE_PSK +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA MBEDTLS_KEY_EXCHANGE_ECDHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA MBEDTLS_KEY_EXCHANGE_ECDH_RSA +#define POLARSSL_KEY_EXCHANGE_NONE MBEDTLS_KEY_EXCHANGE_NONE +#define POLARSSL_KEY_EXCHANGE_PSK MBEDTLS_KEY_EXCHANGE_PSK +#define POLARSSL_KEY_EXCHANGE_RSA MBEDTLS_KEY_EXCHANGE_RSA +#define POLARSSL_KEY_EXCHANGE_RSA_PSK MBEDTLS_KEY_EXCHANGE_RSA_PSK +#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#define POLARSSL_KEY_LENGTH_DES MBEDTLS_KEY_LENGTH_DES +#define POLARSSL_KEY_LENGTH_DES_EDE MBEDTLS_KEY_LENGTH_DES_EDE +#define POLARSSL_KEY_LENGTH_DES_EDE3 MBEDTLS_KEY_LENGTH_DES_EDE3 +#define POLARSSL_KEY_LENGTH_NONE MBEDTLS_KEY_LENGTH_NONE +#define POLARSSL_MAX_BLOCK_LENGTH MBEDTLS_MAX_BLOCK_LENGTH +#define POLARSSL_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH +#define POLARSSL_MD2_H MBEDTLS_MD2_H +#define POLARSSL_MD4_H MBEDTLS_MD4_H +#define POLARSSL_MD5_H MBEDTLS_MD5_H +#define POLARSSL_MD_H MBEDTLS_MD_H +#define POLARSSL_MD_MAX_SIZE MBEDTLS_MD_MAX_SIZE +#define POLARSSL_MD_MD2 MBEDTLS_MD_MD2 +#define POLARSSL_MD_MD4 MBEDTLS_MD_MD4 +#define POLARSSL_MD_MD5 MBEDTLS_MD_MD5 +#define POLARSSL_MD_NONE MBEDTLS_MD_NONE +#define POLARSSL_MD_RIPEMD160 MBEDTLS_MD_RIPEMD160 +#define POLARSSL_MD_SHA1 MBEDTLS_MD_SHA1 +#define POLARSSL_MD_SHA224 MBEDTLS_MD_SHA224 +#define POLARSSL_MD_SHA256 MBEDTLS_MD_SHA256 +#define POLARSSL_MD_SHA384 MBEDTLS_MD_SHA384 +#define POLARSSL_MD_SHA512 MBEDTLS_MD_SHA512 +#define POLARSSL_MD_WRAP_H MBEDTLS_MD_WRAP_H +#define POLARSSL_MEMORY_BUFFER_ALLOC_H MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define POLARSSL_MEMORY_H MBEDTLS_MEMORY_H +#define POLARSSL_MODE_CBC MBEDTLS_MODE_CBC +#define POLARSSL_MODE_CCM MBEDTLS_MODE_CCM +#define POLARSSL_MODE_CFB MBEDTLS_MODE_CFB +#define POLARSSL_MODE_CTR MBEDTLS_MODE_CTR +#define POLARSSL_MODE_ECB MBEDTLS_MODE_ECB +#define POLARSSL_MODE_GCM MBEDTLS_MODE_GCM +#define POLARSSL_MODE_NONE MBEDTLS_MODE_NONE +#define POLARSSL_MODE_OFB MBEDTLS_MODE_OFB +#define POLARSSL_MODE_STREAM MBEDTLS_MODE_STREAM +#define POLARSSL_MPI_MAX_BITS MBEDTLS_MPI_MAX_BITS +#define POLARSSL_MPI_MAX_BITS_SCALE100 MBEDTLS_MPI_MAX_BITS_SCALE100 +#define POLARSSL_MPI_MAX_LIMBS MBEDTLS_MPI_MAX_LIMBS +#define POLARSSL_MPI_RW_BUFFER_SIZE MBEDTLS_MPI_RW_BUFFER_SIZE +#define POLARSSL_NET_H MBEDTLS_NET_H +#define POLARSSL_NET_LISTEN_BACKLOG MBEDTLS_NET_LISTEN_BACKLOG +#define POLARSSL_OID_H MBEDTLS_OID_H +#define POLARSSL_OPERATION_NONE MBEDTLS_OPERATION_NONE +#define POLARSSL_PADDING_NONE MBEDTLS_PADDING_NONE +#define POLARSSL_PADDING_ONE_AND_ZEROS MBEDTLS_PADDING_ONE_AND_ZEROS +#define POLARSSL_PADDING_PKCS7 MBEDTLS_PADDING_PKCS7 +#define POLARSSL_PADDING_ZEROS MBEDTLS_PADDING_ZEROS +#define POLARSSL_PADDING_ZEROS_AND_LEN MBEDTLS_PADDING_ZEROS_AND_LEN +#define POLARSSL_PADLOCK_H MBEDTLS_PADLOCK_H +#define POLARSSL_PBKDF2_H MBEDTLS_PBKDF2_H +#define POLARSSL_PEM_H MBEDTLS_PEM_H +#define POLARSSL_PKCS11_H MBEDTLS_PKCS11_H +#define POLARSSL_PKCS12_H MBEDTLS_PKCS12_H +#define POLARSSL_PKCS5_H MBEDTLS_PKCS5_H +#define POLARSSL_PK_DEBUG_ECP MBEDTLS_PK_DEBUG_ECP +#define POLARSSL_PK_DEBUG_MAX_ITEMS MBEDTLS_PK_DEBUG_MAX_ITEMS +#define POLARSSL_PK_DEBUG_MPI MBEDTLS_PK_DEBUG_MPI +#define POLARSSL_PK_DEBUG_NONE MBEDTLS_PK_DEBUG_NONE +#define POLARSSL_PK_ECDSA MBEDTLS_PK_ECDSA +#define POLARSSL_PK_ECKEY MBEDTLS_PK_ECKEY +#define POLARSSL_PK_ECKEY_DH MBEDTLS_PK_ECKEY_DH +#define POLARSSL_PK_H MBEDTLS_PK_H +#define POLARSSL_PK_NONE MBEDTLS_PK_NONE +#define POLARSSL_PK_RSA MBEDTLS_PK_RSA +#define POLARSSL_PK_RSASSA_PSS MBEDTLS_PK_RSASSA_PSS +#define POLARSSL_PK_RSA_ALT MBEDTLS_PK_RSA_ALT +#define POLARSSL_PK_WRAP_H MBEDTLS_PK_WRAP_H +#define POLARSSL_PLATFORM_H MBEDTLS_PLATFORM_H +#define POLARSSL_PREMASTER_SIZE MBEDTLS_PREMASTER_SIZE +#define POLARSSL_RIPEMD160_H MBEDTLS_RIPEMD160_H +#define POLARSSL_RSA_H MBEDTLS_RSA_H +#define POLARSSL_SHA1_H MBEDTLS_SHA1_H +#define POLARSSL_SHA256_H MBEDTLS_SHA256_H +#define POLARSSL_SHA512_H MBEDTLS_SHA512_H +#define POLARSSL_SSL_CACHE_H MBEDTLS_SSL_CACHE_H +#define POLARSSL_SSL_CIPHERSUITES_H MBEDTLS_SSL_CIPHERSUITES_H +#define POLARSSL_SSL_COOKIE_H MBEDTLS_SSL_COOKIE_H +#define POLARSSL_SSL_H MBEDTLS_SSL_H +#define POLARSSL_THREADING_H MBEDTLS_THREADING_H +#define POLARSSL_THREADING_IMPL MBEDTLS_THREADING_IMPL +#define POLARSSL_TIMING_H MBEDTLS_TIMING_H +#define POLARSSL_VERSION_H MBEDTLS_VERSION_H +#define POLARSSL_VERSION_MAJOR MBEDTLS_VERSION_MAJOR +#define POLARSSL_VERSION_MINOR MBEDTLS_VERSION_MINOR +#define POLARSSL_VERSION_NUMBER MBEDTLS_VERSION_NUMBER +#define POLARSSL_VERSION_PATCH MBEDTLS_VERSION_PATCH +#define POLARSSL_VERSION_STRING MBEDTLS_VERSION_STRING +#define POLARSSL_VERSION_STRING_FULL MBEDTLS_VERSION_STRING_FULL +#define POLARSSL_X509_CRL_H MBEDTLS_X509_CRL_H +#define POLARSSL_X509_CRT_H MBEDTLS_X509_CRT_H +#define POLARSSL_X509_CSR_H MBEDTLS_X509_CSR_H +#define POLARSSL_X509_H MBEDTLS_X509_H +#define POLARSSL_XTEA_H MBEDTLS_XTEA_H +#define RSA_CRYPT MBEDTLS_RSA_CRYPT +#define RSA_PKCS_V15 MBEDTLS_RSA_PKCS_V15 +#define RSA_PKCS_V21 MBEDTLS_RSA_PKCS_V21 +#define RSA_PRIVATE MBEDTLS_RSA_PRIVATE +#define RSA_PUBLIC MBEDTLS_RSA_PUBLIC +#define RSA_SALT_LEN_ANY MBEDTLS_RSA_SALT_LEN_ANY +#define RSA_SIGN MBEDTLS_RSA_SIGN +#define SSL_ALERT_LEVEL_FATAL MBEDTLS_SSL_ALERT_LEVEL_FATAL +#define SSL_ALERT_LEVEL_WARNING MBEDTLS_SSL_ALERT_LEVEL_WARNING +#define SSL_ALERT_MSG_ACCESS_DENIED MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED +#define SSL_ALERT_MSG_BAD_CERT MBEDTLS_SSL_ALERT_MSG_BAD_CERT +#define SSL_ALERT_MSG_BAD_RECORD_MAC MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC +#define SSL_ALERT_MSG_CERT_EXPIRED MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED +#define SSL_ALERT_MSG_CERT_REVOKED MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED +#define SSL_ALERT_MSG_CERT_UNKNOWN MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN +#define SSL_ALERT_MSG_CLOSE_NOTIFY MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY +#define SSL_ALERT_MSG_DECODE_ERROR MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR +#define SSL_ALERT_MSG_DECOMPRESSION_FAILURE MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE +#define SSL_ALERT_MSG_DECRYPTION_FAILED MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED +#define SSL_ALERT_MSG_DECRYPT_ERROR MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR +#define SSL_ALERT_MSG_EXPORT_RESTRICTION MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION +#define SSL_ALERT_MSG_HANDSHAKE_FAILURE MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE +#define SSL_ALERT_MSG_ILLEGAL_PARAMETER MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER +#define SSL_ALERT_MSG_INAPROPRIATE_FALLBACK MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK +#define SSL_ALERT_MSG_INSUFFICIENT_SECURITY MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY +#define SSL_ALERT_MSG_INTERNAL_ERROR MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR +#define SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL +#define SSL_ALERT_MSG_NO_CERT MBEDTLS_SSL_ALERT_MSG_NO_CERT +#define SSL_ALERT_MSG_NO_RENEGOTIATION MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION +#define SSL_ALERT_MSG_PROTOCOL_VERSION MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION +#define SSL_ALERT_MSG_RECORD_OVERFLOW MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW +#define SSL_ALERT_MSG_UNEXPECTED_MESSAGE MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE +#define SSL_ALERT_MSG_UNKNOWN_CA MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA +#define SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY +#define SSL_ALERT_MSG_UNRECOGNIZED_NAME MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME +#define SSL_ALERT_MSG_UNSUPPORTED_CERT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT +#define SSL_ALERT_MSG_UNSUPPORTED_EXT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT +#define SSL_ALERT_MSG_USER_CANCELED MBEDTLS_SSL_ALERT_MSG_USER_CANCELED +#define SSL_ANTI_REPLAY_DISABLED MBEDTLS_SSL_ANTI_REPLAY_DISABLED +#define SSL_ANTI_REPLAY_ENABLED MBEDTLS_SSL_ANTI_REPLAY_ENABLED +#define SSL_ARC4_DISABLED MBEDTLS_SSL_ARC4_DISABLED +#define SSL_ARC4_ENABLED MBEDTLS_SSL_ARC4_ENABLED +#define SSL_BUFFER_LEN MBEDTLS_SSL_BUFFER_LEN +#define SSL_CACHE_DEFAULT_MAX_ENTRIES MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES +#define SSL_CACHE_DEFAULT_TIMEOUT MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT +#define SSL_CBC_RECORD_SPLITTING_DISABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED +#define SSL_CBC_RECORD_SPLITTING_ENABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED +#define SSL_CERTIFICATE_REQUEST MBEDTLS_SSL_CERTIFICATE_REQUEST +#define SSL_CERTIFICATE_VERIFY MBEDTLS_SSL_CERTIFICATE_VERIFY +#define SSL_CERT_TYPE_ECDSA_SIGN MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN +#define SSL_CERT_TYPE_RSA_SIGN MBEDTLS_SSL_CERT_TYPE_RSA_SIGN +#define SSL_CHANNEL_INBOUND MBEDTLS_SSL_CHANNEL_INBOUND +#define SSL_CHANNEL_OUTBOUND MBEDTLS_SSL_CHANNEL_OUTBOUND +#define SSL_CIPHERSUITES MBEDTLS_SSL_CIPHERSUITES +#define SSL_CLIENT_CERTIFICATE MBEDTLS_SSL_CLIENT_CERTIFICATE +#define SSL_CLIENT_CHANGE_CIPHER_SPEC MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC +#define SSL_CLIENT_FINISHED MBEDTLS_SSL_CLIENT_FINISHED +#define SSL_CLIENT_HELLO MBEDTLS_SSL_CLIENT_HELLO +#define SSL_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_CLIENT_KEY_EXCHANGE +#define SSL_COMPRESSION_ADD MBEDTLS_SSL_COMPRESSION_ADD +#define SSL_COMPRESS_DEFLATE MBEDTLS_SSL_COMPRESS_DEFLATE +#define SSL_COMPRESS_NULL MBEDTLS_SSL_COMPRESS_NULL +#define SSL_DEBUG_BUF MBEDTLS_SSL_DEBUG_BUF +#define SSL_DEBUG_CRT MBEDTLS_SSL_DEBUG_CRT +#define SSL_DEBUG_ECP MBEDTLS_SSL_DEBUG_ECP +#define SSL_DEBUG_MPI MBEDTLS_SSL_DEBUG_MPI +#define SSL_DEBUG_MSG MBEDTLS_SSL_DEBUG_MSG +#define SSL_DEBUG_RET MBEDTLS_SSL_DEBUG_RET +#define SSL_DEFAULT_TICKET_LIFETIME MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME +#define SSL_DTLS_TIMEOUT_DFL_MAX MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX +#define SSL_DTLS_TIMEOUT_DFL_MIN MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN +#define SSL_EMPTY_RENEGOTIATION_INFO MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO +#define SSL_ETM_DISABLED MBEDTLS_SSL_ETM_DISABLED +#define SSL_ETM_ENABLED MBEDTLS_SSL_ETM_ENABLED +#define SSL_EXTENDED_MS_DISABLED MBEDTLS_SSL_EXTENDED_MS_DISABLED +#define SSL_EXTENDED_MS_ENABLED MBEDTLS_SSL_EXTENDED_MS_ENABLED +#define SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#define SSL_FLUSH_BUFFERS MBEDTLS_SSL_FLUSH_BUFFERS +#define SSL_HANDSHAKE_OVER MBEDTLS_SSL_HANDSHAKE_OVER +#define SSL_HANDSHAKE_WRAPUP MBEDTLS_SSL_HANDSHAKE_WRAPUP +#define SSL_HASH_MD5 MBEDTLS_SSL_HASH_MD5 +#define SSL_HASH_NONE MBEDTLS_SSL_HASH_NONE +#define SSL_HASH_SHA1 MBEDTLS_SSL_HASH_SHA1 +#define SSL_HASH_SHA224 MBEDTLS_SSL_HASH_SHA224 +#define SSL_HASH_SHA256 MBEDTLS_SSL_HASH_SHA256 +#define SSL_HASH_SHA384 MBEDTLS_SSL_HASH_SHA384 +#define SSL_HASH_SHA512 MBEDTLS_SSL_HASH_SHA512 +#define SSL_HELLO_REQUEST MBEDTLS_SSL_HELLO_REQUEST +#define SSL_HS_CERTIFICATE MBEDTLS_SSL_HS_CERTIFICATE +#define SSL_HS_CERTIFICATE_REQUEST MBEDTLS_SSL_HS_CERTIFICATE_REQUEST +#define SSL_HS_CERTIFICATE_VERIFY MBEDTLS_SSL_HS_CERTIFICATE_VERIFY +#define SSL_HS_CLIENT_HELLO MBEDTLS_SSL_HS_CLIENT_HELLO +#define SSL_HS_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE +#define SSL_HS_FINISHED MBEDTLS_SSL_HS_FINISHED +#define SSL_HS_HELLO_REQUEST MBEDTLS_SSL_HS_HELLO_REQUEST +#define SSL_HS_HELLO_VERIFY_REQUEST MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST +#define SSL_HS_NEW_SESSION_TICKET MBEDTLS_SSL_HS_NEW_SESSION_TICKET +#define SSL_HS_SERVER_HELLO MBEDTLS_SSL_HS_SERVER_HELLO +#define SSL_HS_SERVER_HELLO_DONE MBEDTLS_SSL_HS_SERVER_HELLO_DONE +#define SSL_HS_SERVER_KEY_EXCHANGE MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE +#define SSL_INITIAL_HANDSHAKE MBEDTLS_SSL_INITIAL_HANDSHAKE +#define SSL_IS_CLIENT MBEDTLS_SSL_IS_CLIENT +#define SSL_IS_FALLBACK MBEDTLS_SSL_IS_FALLBACK +#define SSL_IS_NOT_FALLBACK MBEDTLS_SSL_IS_NOT_FALLBACK +#define SSL_IS_SERVER MBEDTLS_SSL_IS_SERVER +#define SSL_LEGACY_ALLOW_RENEGOTIATION MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION +#define SSL_LEGACY_BREAK_HANDSHAKE MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE +#define SSL_LEGACY_NO_RENEGOTIATION MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION +#define SSL_LEGACY_RENEGOTIATION MBEDTLS_SSL_LEGACY_RENEGOTIATION +#define SSL_MAC_ADD MBEDTLS_SSL_MAC_ADD +#define SSL_MAJOR_VERSION_3 MBEDTLS_SSL_MAJOR_VERSION_3 +#define SSL_MAX_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define SSL_MAX_FRAG_LEN_1024 MBEDTLS_SSL_MAX_FRAG_LEN_1024 +#define SSL_MAX_FRAG_LEN_2048 MBEDTLS_SSL_MAX_FRAG_LEN_2048 +#define SSL_MAX_FRAG_LEN_4096 MBEDTLS_SSL_MAX_FRAG_LEN_4096 +#define SSL_MAX_FRAG_LEN_512 MBEDTLS_SSL_MAX_FRAG_LEN_512 +#define SSL_MAX_FRAG_LEN_INVALID MBEDTLS_SSL_MAX_FRAG_LEN_INVALID +#define SSL_MAX_FRAG_LEN_NONE MBEDTLS_SSL_MAX_FRAG_LEN_NONE +#define SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAX_MAJOR_VERSION +#define SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MAX_MINOR_VERSION +#define SSL_MINOR_VERSION_0 MBEDTLS_SSL_MINOR_VERSION_0 +#define SSL_MINOR_VERSION_1 MBEDTLS_SSL_MINOR_VERSION_1 +#define SSL_MINOR_VERSION_2 MBEDTLS_SSL_MINOR_VERSION_2 +#define SSL_MINOR_VERSION_3 MBEDTLS_SSL_MINOR_VERSION_3 +#define SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MIN_MAJOR_VERSION +#define SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MIN_MINOR_VERSION +#define SSL_MSG_ALERT MBEDTLS_SSL_MSG_ALERT +#define SSL_MSG_APPLICATION_DATA MBEDTLS_SSL_MSG_APPLICATION_DATA +#define SSL_MSG_CHANGE_CIPHER_SPEC MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC +#define SSL_MSG_HANDSHAKE MBEDTLS_SSL_MSG_HANDSHAKE +#define SSL_PADDING_ADD MBEDTLS_SSL_PADDING_ADD +#define SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#define SSL_RENEGOTIATION_DISABLED MBEDTLS_SSL_RENEGOTIATION_DISABLED +#define SSL_RENEGOTIATION_DONE MBEDTLS_SSL_RENEGOTIATION_DONE +#define SSL_RENEGOTIATION_ENABLED MBEDTLS_SSL_RENEGOTIATION_ENABLED +#define SSL_RENEGOTIATION_NOT_ENFORCED MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED +#define SSL_RENEGOTIATION_PENDING MBEDTLS_SSL_RENEGOTIATION_PENDING +#define SSL_RENEGO_MAX_RECORDS_DEFAULT MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT +#define SSL_RETRANS_FINISHED MBEDTLS_SSL_RETRANS_FINISHED +#define SSL_RETRANS_PREPARING MBEDTLS_SSL_RETRANS_PREPARING +#define SSL_RETRANS_SENDING MBEDTLS_SSL_RETRANS_SENDING +#define SSL_RETRANS_WAITING MBEDTLS_SSL_RETRANS_WAITING +#define SSL_SECURE_RENEGOTIATION MBEDTLS_SSL_SECURE_RENEGOTIATION +#define SSL_SERVER_CERTIFICATE MBEDTLS_SSL_SERVER_CERTIFICATE +#define SSL_SERVER_CHANGE_CIPHER_SPEC MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC +#define SSL_SERVER_FINISHED MBEDTLS_SSL_SERVER_FINISHED +#define SSL_SERVER_HELLO MBEDTLS_SSL_SERVER_HELLO +#define SSL_SERVER_HELLO_DONE MBEDTLS_SSL_SERVER_HELLO_DONE +#define SSL_SERVER_HELLO_VERIFY_REQUEST_SENT MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT +#define SSL_SERVER_KEY_EXCHANGE MBEDTLS_SSL_SERVER_KEY_EXCHANGE +#define SSL_SERVER_NEW_SESSION_TICKET MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET +#define SSL_SESSION_TICKETS_DISABLED MBEDTLS_SSL_SESSION_TICKETS_DISABLED +#define SSL_SESSION_TICKETS_ENABLED MBEDTLS_SSL_SESSION_TICKETS_ENABLED +#define SSL_SIG_ANON MBEDTLS_SSL_SIG_ANON +#define SSL_SIG_ECDSA MBEDTLS_SSL_SIG_ECDSA +#define SSL_SIG_RSA MBEDTLS_SSL_SIG_RSA +#define SSL_TRANSPORT_DATAGRAM MBEDTLS_SSL_TRANSPORT_DATAGRAM +#define SSL_TRANSPORT_STREAM MBEDTLS_SSL_TRANSPORT_STREAM +#define SSL_TRUNCATED_HMAC_LEN MBEDTLS_SSL_TRUNCATED_HMAC_LEN +#define SSL_TRUNC_HMAC_DISABLED MBEDTLS_SSL_TRUNC_HMAC_DISABLED +#define SSL_TRUNC_HMAC_ENABLED MBEDTLS_SSL_TRUNC_HMAC_ENABLED +#define SSL_VERIFY_DATA_MAX_LEN MBEDTLS_SSL_VERIFY_DATA_MAX_LEN +#define SSL_VERIFY_NONE MBEDTLS_SSL_VERIFY_NONE +#define SSL_VERIFY_OPTIONAL MBEDTLS_SSL_VERIFY_OPTIONAL +#define SSL_VERIFY_REQUIRED MBEDTLS_SSL_VERIFY_REQUIRED +#define TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_AES_128_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM +#define TLS_DHE_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 +#define TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_AES_256_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM +#define TLS_DHE_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 +#define TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA +#define TLS_DHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 +#define TLS_DHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 +#define TLS_DHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA +#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_128_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM +#define TLS_DHE_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 +#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM +#define TLS_DHE_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 +#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA +#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA +#define TLS_ECDHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 +#define TLS_ECDHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 +#define TLS_ECDHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA +#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA +#define TLS_ECDHE_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA +#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA +#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA +#define TLS_ECDH_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA +#define TLS_EXT_ALPN MBEDTLS_TLS_EXT_ALPN +#define TLS_EXT_ENCRYPT_THEN_MAC MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC +#define TLS_EXT_EXTENDED_MASTER_SECRET MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET +#define TLS_EXT_MAX_FRAGMENT_LENGTH MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH +#define TLS_EXT_RENEGOTIATION_INFO MBEDTLS_TLS_EXT_RENEGOTIATION_INFO +#define TLS_EXT_SERVERNAME MBEDTLS_TLS_EXT_SERVERNAME +#define TLS_EXT_SERVERNAME_HOSTNAME MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME +#define TLS_EXT_SESSION_TICKET MBEDTLS_TLS_EXT_SESSION_TICKET +#define TLS_EXT_SIG_ALG MBEDTLS_TLS_EXT_SIG_ALG +#define TLS_EXT_SUPPORTED_ELLIPTIC_CURVES MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES +#define TLS_EXT_SUPPORTED_POINT_FORMATS MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS +#define TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT +#define TLS_EXT_TRUNCATED_HMAC MBEDTLS_TLS_EXT_TRUNCATED_HMAC +#define TLS_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_PSK_WITH_AES_128_CCM MBEDTLS_TLS_PSK_WITH_AES_128_CCM +#define TLS_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 +#define TLS_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA +#define TLS_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_PSK_WITH_AES_256_CCM MBEDTLS_TLS_PSK_WITH_AES_256_CCM +#define TLS_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 +#define TLS_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_PSK_WITH_NULL_SHA MBEDTLS_TLS_PSK_WITH_NULL_SHA +#define TLS_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_PSK_WITH_NULL_SHA256 +#define TLS_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_PSK_WITH_NULL_SHA384 +#define TLS_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_PSK_WITH_RC4_128_SHA +#define TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_NULL_SHA MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA +#define TLS_RSA_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 +#define TLS_RSA_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 +#define TLS_RSA_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA +#define TLS_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_WITH_AES_128_CCM MBEDTLS_TLS_RSA_WITH_AES_128_CCM +#define TLS_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 +#define TLS_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA +#define TLS_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_RSA_WITH_AES_256_CCM MBEDTLS_TLS_RSA_WITH_AES_256_CCM +#define TLS_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 +#define TLS_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA +#define TLS_RSA_WITH_NULL_MD5 MBEDTLS_TLS_RSA_WITH_NULL_MD5 +#define TLS_RSA_WITH_NULL_SHA MBEDTLS_TLS_RSA_WITH_NULL_SHA +#define TLS_RSA_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_WITH_NULL_SHA256 +#define TLS_RSA_WITH_RC4_128_MD5 MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 +#define TLS_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_WITH_RC4_128_SHA +#define UL64 MBEDTLS_UL64 +#define X509_CRT_VERSION_1 MBEDTLS_X509_CRT_VERSION_1 +#define X509_CRT_VERSION_2 MBEDTLS_X509_CRT_VERSION_2 +#define X509_CRT_VERSION_3 MBEDTLS_X509_CRT_VERSION_3 +#define X509_FORMAT_DER MBEDTLS_X509_FORMAT_DER +#define X509_FORMAT_PEM MBEDTLS_X509_FORMAT_PEM +#define X509_MAX_DN_NAME_SIZE MBEDTLS_X509_MAX_DN_NAME_SIZE +#define X509_RFC5280_MAX_SERIAL_LEN MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN +#define X509_RFC5280_UTC_TIME_LEN MBEDTLS_X509_RFC5280_UTC_TIME_LEN +#define XTEA_DECRYPT MBEDTLS_XTEA_DECRYPT +#define XTEA_ENCRYPT MBEDTLS_XTEA_ENCRYPT +#define _asn1_bitstring mbedtls_asn1_bitstring +#define _asn1_buf mbedtls_asn1_buf +#define _asn1_named_data mbedtls_asn1_named_data +#define _asn1_sequence mbedtls_asn1_sequence +#define _ssl_cache_context mbedtls_ssl_cache_context +#define _ssl_cache_entry mbedtls_ssl_cache_entry +#define _ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define _ssl_context mbedtls_ssl_context +#define _ssl_flight_item mbedtls_ssl_flight_item +#define _ssl_handshake_params mbedtls_ssl_handshake_params +#define _ssl_key_cert mbedtls_ssl_key_cert +#define _ssl_premaster_secret mbedtls_ssl_premaster_secret +#define _ssl_session mbedtls_ssl_session +#define _ssl_ticket_keys mbedtls_ssl_ticket_keys +#define _ssl_transform mbedtls_ssl_transform +#define _x509_crl mbedtls_x509_crl +#define _x509_crl_entry mbedtls_x509_crl_entry +#define _x509_crt mbedtls_x509_crt +#define _x509_csr mbedtls_x509_csr +#define _x509_time mbedtls_x509_time +#define _x509write_cert mbedtls_x509write_cert +#define _x509write_csr mbedtls_x509write_csr +#define aes_context mbedtls_aes_context +#define aes_crypt_cbc mbedtls_aes_crypt_cbc +#define aes_crypt_cfb128 mbedtls_aes_crypt_cfb128 +#define aes_crypt_cfb8 mbedtls_aes_crypt_cfb8 +#define aes_crypt_ctr mbedtls_aes_crypt_ctr +#define aes_crypt_ecb mbedtls_aes_crypt_ecb +#define aes_free mbedtls_aes_free +#define aes_init mbedtls_aes_init +#define aes_self_test mbedtls_aes_self_test +#define aes_setkey_dec mbedtls_aes_setkey_dec +#define aes_setkey_enc mbedtls_aes_setkey_enc +#define aesni_crypt_ecb mbedtls_aesni_crypt_ecb +#define aesni_gcm_mult mbedtls_aesni_gcm_mult +#define aesni_inverse_key mbedtls_aesni_inverse_key +#define aesni_setkey_enc mbedtls_aesni_setkey_enc +#define aesni_supports mbedtls_aesni_has_support +#define alarmed mbedtls_timing_alarmed +#define arc4_context mbedtls_arc4_context +#define arc4_crypt mbedtls_arc4_crypt +#define arc4_free mbedtls_arc4_free +#define arc4_init mbedtls_arc4_init +#define arc4_self_test mbedtls_arc4_self_test +#define arc4_setup mbedtls_arc4_setup +#define asn1_bitstring mbedtls_asn1_bitstring +#define asn1_buf mbedtls_asn1_buf +#define asn1_find_named_data mbedtls_asn1_find_named_data +#define asn1_free_named_data mbedtls_asn1_free_named_data +#define asn1_free_named_data_list mbedtls_asn1_free_named_data_list +#define asn1_get_alg mbedtls_asn1_get_alg +#define asn1_get_alg_null mbedtls_asn1_get_alg_null +#define asn1_get_bitstring mbedtls_asn1_get_bitstring +#define asn1_get_bitstring_null mbedtls_asn1_get_bitstring_null +#define asn1_get_bool mbedtls_asn1_get_bool +#define asn1_get_int mbedtls_asn1_get_int +#define asn1_get_len mbedtls_asn1_get_len +#define asn1_get_mpi mbedtls_asn1_get_mpi +#define asn1_get_sequence_of mbedtls_asn1_get_sequence_of +#define asn1_get_tag mbedtls_asn1_get_tag +#define asn1_named_data mbedtls_asn1_named_data +#define asn1_sequence mbedtls_asn1_sequence +#define asn1_store_named_data mbedtls_asn1_store_named_data +#define asn1_write_algorithm_identifier mbedtls_asn1_write_algorithm_identifier +#define asn1_write_bitstring mbedtls_asn1_write_bitstring +#define asn1_write_bool mbedtls_asn1_write_bool +#define asn1_write_ia5_string mbedtls_asn1_write_ia5_string +#define asn1_write_int mbedtls_asn1_write_int +#define asn1_write_len mbedtls_asn1_write_len +#define asn1_write_mpi mbedtls_asn1_write_mpi +#define asn1_write_null mbedtls_asn1_write_null +#define asn1_write_octet_string mbedtls_asn1_write_octet_string +#define asn1_write_oid mbedtls_asn1_write_oid +#define asn1_write_printable_string mbedtls_asn1_write_printable_string +#define asn1_write_raw_buffer mbedtls_asn1_write_raw_buffer +#define asn1_write_tag mbedtls_asn1_write_tag +#define base64_decode mbedtls_base64_decode +#define base64_encode mbedtls_base64_encode +#define base64_self_test mbedtls_base64_self_test +#define blowfish_context mbedtls_blowfish_context +#define blowfish_crypt_cbc mbedtls_blowfish_crypt_cbc +#define blowfish_crypt_cfb64 mbedtls_blowfish_crypt_cfb64 +#define blowfish_crypt_ctr mbedtls_blowfish_crypt_ctr +#define blowfish_crypt_ecb mbedtls_blowfish_crypt_ecb +#define blowfish_free mbedtls_blowfish_free +#define blowfish_init mbedtls_blowfish_init +#define blowfish_setkey mbedtls_blowfish_setkey +#define camellia_context mbedtls_camellia_context +#define camellia_crypt_cbc mbedtls_camellia_crypt_cbc +#define camellia_crypt_cfb128 mbedtls_camellia_crypt_cfb128 +#define camellia_crypt_ctr mbedtls_camellia_crypt_ctr +#define camellia_crypt_ecb mbedtls_camellia_crypt_ecb +#define camellia_free mbedtls_camellia_free +#define camellia_init mbedtls_camellia_init +#define camellia_self_test mbedtls_camellia_self_test +#define camellia_setkey_dec mbedtls_camellia_setkey_dec +#define camellia_setkey_enc mbedtls_camellia_setkey_enc +#define ccm_auth_decrypt mbedtls_ccm_auth_decrypt +#define ccm_context mbedtls_ccm_context +#define ccm_encrypt_and_tag mbedtls_ccm_encrypt_and_tag +#define ccm_free mbedtls_ccm_free +#define ccm_init mbedtls_ccm_init +#define ccm_self_test mbedtls_ccm_self_test +#define cipher_auth_decrypt mbedtls_cipher_auth_decrypt +#define cipher_auth_encrypt mbedtls_cipher_auth_encrypt +#define cipher_base_t mbedtls_cipher_base_t +#define cipher_check_tag mbedtls_cipher_check_tag +#define cipher_context_t mbedtls_cipher_context_t +#define cipher_crypt mbedtls_cipher_crypt +#define cipher_definition_t mbedtls_cipher_definition_t +#define cipher_definitions mbedtls_cipher_definitions +#define cipher_finish mbedtls_cipher_finish +#define cipher_free mbedtls_cipher_free +#define cipher_free_ctx mbedtls_cipher_free_ctx +#define cipher_get_block_size mbedtls_cipher_get_block_size +#define cipher_get_cipher_mode mbedtls_cipher_get_cipher_mode +#define cipher_get_iv_size mbedtls_cipher_get_iv_size +#define cipher_get_key_size mbedtls_cipher_get_key_bitlen +#define cipher_get_name mbedtls_cipher_get_name +#define cipher_get_operation mbedtls_cipher_get_operation +#define cipher_get_type mbedtls_cipher_get_type +#define cipher_id_t mbedtls_cipher_id_t +#define cipher_info_from_string mbedtls_cipher_info_from_string +#define cipher_info_from_type mbedtls_cipher_info_from_type +#define cipher_info_from_values mbedtls_cipher_info_from_values +#define cipher_info_t mbedtls_cipher_info_t +#define cipher_init mbedtls_cipher_init +#define cipher_init_ctx mbedtls_cipher_setup +#define cipher_list mbedtls_cipher_list +#define cipher_mode_t mbedtls_cipher_mode_t +#define cipher_padding_t mbedtls_cipher_padding_t +#define cipher_reset mbedtls_cipher_reset +#define cipher_self_test mbedtls_cipher_self_test +#define cipher_set_iv mbedtls_cipher_set_iv +#define cipher_set_padding_mode mbedtls_cipher_set_padding_mode +#define cipher_setkey mbedtls_cipher_setkey +#define cipher_type_t mbedtls_cipher_type_t +#define cipher_update mbedtls_cipher_update +#define cipher_update_ad mbedtls_cipher_update_ad +#define cipher_write_tag mbedtls_cipher_write_tag +#define ctr_drbg_context mbedtls_ctr_drbg_context +#define ctr_drbg_free mbedtls_ctr_drbg_free +#define ctr_drbg_init mbedtls_ctr_drbg_init +#define ctr_drbg_init_entropy_len mbedtls_ctr_drbg_init_entropy_len +#define ctr_drbg_random mbedtls_ctr_drbg_random +#define ctr_drbg_random_with_add mbedtls_ctr_drbg_random_with_add +#define ctr_drbg_reseed mbedtls_ctr_drbg_reseed +#define ctr_drbg_self_test mbedtls_ctr_drbg_self_test +#define ctr_drbg_set_entropy_len mbedtls_ctr_drbg_set_entropy_len +#define ctr_drbg_set_prediction_resistance mbedtls_ctr_drbg_set_prediction_resistance +#define ctr_drbg_set_reseed_interval mbedtls_ctr_drbg_set_reseed_interval +#define ctr_drbg_update mbedtls_ctr_drbg_update +#define ctr_drbg_update_seed_file mbedtls_ctr_drbg_update_seed_file +#define ctr_drbg_write_seed_file mbedtls_ctr_drbg_write_seed_file +#define debug_fmt mbedtls_debug_fmt +#define debug_print_buf mbedtls_debug_print_buf +#define debug_print_crt mbedtls_debug_print_crt +#define debug_print_ecp mbedtls_debug_print_ecp +#define debug_print_mpi mbedtls_debug_print_mpi +#define debug_print_msg mbedtls_debug_print_msg +#define debug_print_ret mbedtls_debug_print_ret +#define debug_set_log_mode mbedtls_debug_set_log_mode +#define debug_set_threshold mbedtls_debug_set_threshold +#define des3_context mbedtls_des3_context +#define des3_crypt_cbc mbedtls_des3_crypt_cbc +#define des3_crypt_ecb mbedtls_des3_crypt_ecb +#define des3_free mbedtls_des3_free +#define des3_init mbedtls_des3_init +#define des3_set2key_dec mbedtls_des3_set2key_dec +#define des3_set2key_enc mbedtls_des3_set2key_enc +#define des3_set3key_dec mbedtls_des3_set3key_dec +#define des3_set3key_enc mbedtls_des3_set3key_enc +#define des_context mbedtls_des_context +#define des_crypt_cbc mbedtls_des_crypt_cbc +#define des_crypt_ecb mbedtls_des_crypt_ecb +#define des_free mbedtls_des_free +#define des_init mbedtls_des_init +#define des_key_check_key_parity mbedtls_des_key_check_key_parity +#define des_key_check_weak mbedtls_des_key_check_weak +#define des_key_set_parity mbedtls_des_key_set_parity +#define des_self_test mbedtls_des_self_test +#define des_setkey_dec mbedtls_des_setkey_dec +#define des_setkey_enc mbedtls_des_setkey_enc +#define dhm_calc_secret mbedtls_dhm_calc_secret +#define dhm_context mbedtls_dhm_context +#define dhm_free mbedtls_dhm_free +#define dhm_init mbedtls_dhm_init +#define dhm_make_params mbedtls_dhm_make_params +#define dhm_make_public mbedtls_dhm_make_public +#define dhm_parse_dhm mbedtls_dhm_parse_dhm +#define dhm_parse_dhmfile mbedtls_dhm_parse_dhmfile +#define dhm_read_params mbedtls_dhm_read_params +#define dhm_read_public mbedtls_dhm_read_public +#define dhm_self_test mbedtls_dhm_self_test +#define ecdh_calc_secret mbedtls_ecdh_calc_secret +#define ecdh_compute_shared mbedtls_ecdh_compute_shared +#define ecdh_context mbedtls_ecdh_context +#define ecdh_free mbedtls_ecdh_free +#define ecdh_gen_public mbedtls_ecdh_gen_public +#define ecdh_get_params mbedtls_ecdh_get_params +#define ecdh_init mbedtls_ecdh_init +#define ecdh_make_params mbedtls_ecdh_make_params +#define ecdh_make_public mbedtls_ecdh_make_public +#define ecdh_read_params mbedtls_ecdh_read_params +#define ecdh_read_public mbedtls_ecdh_read_public +#define ecdh_self_test mbedtls_ecdh_self_test +#define ecdh_side mbedtls_ecdh_side +#define ecdsa_context mbedtls_ecdsa_context +#define ecdsa_free mbedtls_ecdsa_free +#define ecdsa_from_keypair mbedtls_ecdsa_from_keypair +#define ecdsa_genkey mbedtls_ecdsa_genkey +#define ecdsa_info mbedtls_ecdsa_info +#define ecdsa_init mbedtls_ecdsa_init +#define ecdsa_read_signature mbedtls_ecdsa_read_signature +#define ecdsa_self_test mbedtls_ecdsa_self_test +#define ecdsa_sign mbedtls_ecdsa_sign +#define ecdsa_sign_det mbedtls_ecdsa_sign_det +#define ecdsa_verify mbedtls_ecdsa_verify +#define ecdsa_write_signature mbedtls_ecdsa_write_signature +#define ecdsa_write_signature_det mbedtls_ecdsa_write_signature_det +#define eckey_info mbedtls_eckey_info +#define eckeydh_info mbedtls_eckeydh_info +#define ecp_add mbedtls_ecp_add +#define ecp_check_privkey mbedtls_ecp_check_privkey +#define ecp_check_pub_priv mbedtls_ecp_check_pub_priv +#define ecp_check_pubkey mbedtls_ecp_check_pubkey +#define ecp_copy mbedtls_ecp_copy +#define ecp_curve_info mbedtls_ecp_curve_info +#define ecp_curve_info_from_grp_id mbedtls_ecp_curve_info_from_grp_id +#define ecp_curve_info_from_name mbedtls_ecp_curve_info_from_name +#define ecp_curve_info_from_tls_id mbedtls_ecp_curve_info_from_tls_id +#define ecp_curve_list mbedtls_ecp_curve_list +#define ecp_gen_key mbedtls_ecp_gen_key +#define ecp_gen_keypair mbedtls_ecp_gen_keypair +#define ecp_group mbedtls_ecp_group +#define ecp_group_copy mbedtls_ecp_group_copy +#define ecp_group_free mbedtls_ecp_group_free +#define ecp_group_id mbedtls_ecp_group_id +#define ecp_group_init mbedtls_ecp_group_init +#define ecp_group_read_string mbedtls_ecp_group_read_string +#define ecp_grp_id_list mbedtls_ecp_grp_id_list +#define ecp_is_zero mbedtls_ecp_is_zero +#define ecp_keypair mbedtls_ecp_keypair +#define ecp_keypair_free mbedtls_ecp_keypair_free +#define ecp_keypair_init mbedtls_ecp_keypair_init +#define ecp_mul mbedtls_ecp_mul +#define ecp_point mbedtls_ecp_point +#define ecp_point_free mbedtls_ecp_point_free +#define ecp_point_init mbedtls_ecp_point_init +#define ecp_point_read_binary mbedtls_ecp_point_read_binary +#define ecp_point_read_string mbedtls_ecp_point_read_string +#define ecp_point_write_binary mbedtls_ecp_point_write_binary +#define ecp_self_test mbedtls_ecp_self_test +#define ecp_set_zero mbedtls_ecp_set_zero +#define ecp_sub mbedtls_ecp_sub +#define ecp_tls_read_group mbedtls_ecp_tls_read_group +#define ecp_tls_read_point mbedtls_ecp_tls_read_point +#define ecp_tls_write_group mbedtls_ecp_tls_write_group +#define ecp_tls_write_point mbedtls_ecp_tls_write_point +#define ecp_use_known_dp mbedtls_ecp_group_load +#define entropy_add_source mbedtls_entropy_add_source +#define entropy_context mbedtls_entropy_context +#define entropy_free mbedtls_entropy_free +#define entropy_func mbedtls_entropy_func +#define entropy_gather mbedtls_entropy_gather +#define entropy_init mbedtls_entropy_init +#define entropy_self_test mbedtls_entropy_self_test +#define entropy_update_manual mbedtls_entropy_update_manual +#define entropy_update_seed_file mbedtls_entropy_update_seed_file +#define entropy_write_seed_file mbedtls_entropy_write_seed_file +#define error_strerror mbedtls_strerror +#define f_source_ptr mbedtls_entropy_f_source_ptr +#define gcm_auth_decrypt mbedtls_gcm_auth_decrypt +#define gcm_context mbedtls_gcm_context +#define gcm_crypt_and_tag mbedtls_gcm_crypt_and_tag +#define gcm_finish mbedtls_gcm_finish +#define gcm_free mbedtls_gcm_free +#define gcm_init mbedtls_gcm_init +#define gcm_self_test mbedtls_gcm_self_test +#define gcm_starts mbedtls_gcm_starts +#define gcm_update mbedtls_gcm_update +#define get_timer mbedtls_timing_get_timer +#define hardclock mbedtls_timing_hardclock +#define hardclock_poll mbedtls_hardclock_poll +#define havege_free mbedtls_havege_free +#define havege_init mbedtls_havege_init +#define havege_poll mbedtls_havege_poll +#define havege_random mbedtls_havege_random +#define havege_state mbedtls_havege_state +#define hmac_drbg_context mbedtls_hmac_drbg_context +#define hmac_drbg_free mbedtls_hmac_drbg_free +#define hmac_drbg_init mbedtls_hmac_drbg_init +#define hmac_drbg_init_buf mbedtls_hmac_drbg_init_buf +#define hmac_drbg_random mbedtls_hmac_drbg_random +#define hmac_drbg_random_with_add mbedtls_hmac_drbg_random_with_add +#define hmac_drbg_reseed mbedtls_hmac_drbg_reseed +#define hmac_drbg_self_test mbedtls_hmac_drbg_self_test +#define hmac_drbg_set_entropy_len mbedtls_hmac_drbg_set_entropy_len +#define hmac_drbg_set_prediction_resistance mbedtls_hmac_drbg_set_prediction_resistance +#define hmac_drbg_set_reseed_interval mbedtls_hmac_drbg_set_reseed_interval +#define hmac_drbg_update mbedtls_hmac_drbg_update +#define hmac_drbg_update_seed_file mbedtls_hmac_drbg_update_seed_file +#define hmac_drbg_write_seed_file mbedtls_hmac_drbg_write_seed_file +#define hr_time mbedtls_timing_hr_time +#define key_exchange_type_t mbedtls_key_exchange_type_t +#define md mbedtls_md +#define md2 mbedtls_md2 +#define md2_context mbedtls_md2_context +#define md2_file mbedtls_md2_file +#define md2_finish mbedtls_md2_finish +#define md2_free mbedtls_md2_free +#define md2_hmac mbedtls_md2_hmac +#define md2_hmac_finish mbedtls_md2_hmac_finish +#define md2_hmac_reset mbedtls_md2_hmac_reset +#define md2_hmac_starts mbedtls_md2_hmac_starts +#define md2_hmac_update mbedtls_md2_hmac_update +#define md2_info mbedtls_md2_info +#define md2_init mbedtls_md2_init +#define md2_process mbedtls_md2_process +#define md2_self_test mbedtls_md2_self_test +#define md2_starts mbedtls_md2_starts +#define md2_update mbedtls_md2_update +#define md4 mbedtls_md4 +#define md4_context mbedtls_md4_context +#define md4_file mbedtls_md4_file +#define md4_finish mbedtls_md4_finish +#define md4_free mbedtls_md4_free +#define md4_hmac mbedtls_md4_hmac +#define md4_hmac_finish mbedtls_md4_hmac_finish +#define md4_hmac_reset mbedtls_md4_hmac_reset +#define md4_hmac_starts mbedtls_md4_hmac_starts +#define md4_hmac_update mbedtls_md4_hmac_update +#define md4_info mbedtls_md4_info +#define md4_init mbedtls_md4_init +#define md4_process mbedtls_md4_process +#define md4_self_test mbedtls_md4_self_test +#define md4_starts mbedtls_md4_starts +#define md4_update mbedtls_md4_update +#define md5 mbedtls_md5 +#define md5_context mbedtls_md5_context +#define md5_file mbedtls_md5_file +#define md5_finish mbedtls_md5_finish +#define md5_free mbedtls_md5_free +#define md5_hmac mbedtls_md5_hmac +#define md5_hmac_finish mbedtls_md5_hmac_finish +#define md5_hmac_reset mbedtls_md5_hmac_reset +#define md5_hmac_starts mbedtls_md5_hmac_starts +#define md5_hmac_update mbedtls_md5_hmac_update +#define md5_info mbedtls_md5_info +#define md5_init mbedtls_md5_init +#define md5_process mbedtls_md5_process +#define md5_self_test mbedtls_md5_self_test +#define md5_starts mbedtls_md5_starts +#define md5_update mbedtls_md5_update +#define md_context_t mbedtls_md_context_t +#define md_file mbedtls_md_file +#define md_finish mbedtls_md_finish +#define md_free mbedtls_md_free +#define md_free_ctx mbedtls_md_free_ctx +#define md_get_name mbedtls_md_get_name +#define md_get_size mbedtls_md_get_size +#define md_get_type mbedtls_md_get_type +#define md_hmac mbedtls_md_hmac +#define md_hmac_finish mbedtls_md_hmac_finish +#define md_hmac_reset mbedtls_md_hmac_reset +#define md_hmac_starts mbedtls_md_hmac_starts +#define md_hmac_update mbedtls_md_hmac_update +#define md_info_from_string mbedtls_md_info_from_string +#define md_info_from_type mbedtls_md_info_from_type +#define md_info_t mbedtls_md_info_t +#define md_init mbedtls_md_init +#define md_init_ctx mbedtls_md_init_ctx +#define md_list mbedtls_md_list +#define md_process mbedtls_md_process +#define md_starts mbedtls_md_starts +#define md_type_t mbedtls_md_type_t +#define md_update mbedtls_md_update +#define memory_buffer_alloc_cur_get mbedtls_memory_buffer_alloc_cur_get +#define memory_buffer_alloc_free mbedtls_memory_buffer_alloc_free +#define memory_buffer_alloc_init mbedtls_memory_buffer_alloc_init +#define memory_buffer_alloc_max_get mbedtls_memory_buffer_alloc_max_get +#define memory_buffer_alloc_max_reset mbedtls_memory_buffer_alloc_max_reset +#define memory_buffer_alloc_self_test mbedtls_memory_buffer_alloc_self_test +#define memory_buffer_alloc_status mbedtls_memory_buffer_alloc_status +#define memory_buffer_alloc_verify mbedtls_memory_buffer_alloc_verify +#define memory_buffer_set_verify mbedtls_memory_buffer_set_verify +#define memory_set_own mbedtls_memory_set_own +#define mpi mbedtls_mpi +#define mpi_add_abs mbedtls_mpi_add_abs +#define mpi_add_int mbedtls_mpi_add_int +#define mpi_add_mpi mbedtls_mpi_add_mpi +#define mpi_cmp_abs mbedtls_mpi_cmp_abs +#define mpi_cmp_int mbedtls_mpi_cmp_int +#define mpi_cmp_mpi mbedtls_mpi_cmp_mpi +#define mpi_copy mbedtls_mpi_copy +#define mpi_div_int mbedtls_mpi_div_int +#define mpi_div_mpi mbedtls_mpi_div_mpi +#define mpi_exp_mod mbedtls_mpi_exp_mod +#define mpi_fill_random mbedtls_mpi_fill_random +#define mpi_free mbedtls_mpi_free +#define mpi_gcd mbedtls_mpi_gcd +#define mpi_gen_prime mbedtls_mpi_gen_prime +#define mpi_get_bit mbedtls_mpi_get_bit +#define mpi_grow mbedtls_mpi_grow +#define mpi_init mbedtls_mpi_init +#define mpi_inv_mod mbedtls_mpi_inv_mod +#define mpi_is_prime mbedtls_mpi_is_prime +#define mpi_lsb mbedtls_mpi_lsb +#define mpi_lset mbedtls_mpi_lset +#define mpi_mod_int mbedtls_mpi_mod_int +#define mpi_mod_mpi mbedtls_mpi_mod_mpi +#define mpi_msb mbedtls_mpi_bitlen +#define mpi_mul_int mbedtls_mpi_mul_int +#define mpi_mul_mpi mbedtls_mpi_mul_mpi +#define mpi_read_binary mbedtls_mpi_read_binary +#define mpi_read_file mbedtls_mpi_read_file +#define mpi_read_string mbedtls_mpi_read_string +#define mpi_safe_cond_assign mbedtls_mpi_safe_cond_assign +#define mpi_safe_cond_swap mbedtls_mpi_safe_cond_swap +#define mpi_self_test mbedtls_mpi_self_test +#define mpi_set_bit mbedtls_mpi_set_bit +#define mpi_shift_l mbedtls_mpi_shift_l +#define mpi_shift_r mbedtls_mpi_shift_r +#define mpi_shrink mbedtls_mpi_shrink +#define mpi_size mbedtls_mpi_size +#define mpi_sub_abs mbedtls_mpi_sub_abs +#define mpi_sub_int mbedtls_mpi_sub_int +#define mpi_sub_mpi mbedtls_mpi_sub_mpi +#define mpi_swap mbedtls_mpi_swap +#define mpi_write_binary mbedtls_mpi_write_binary +#define mpi_write_file mbedtls_mpi_write_file +#define mpi_write_string mbedtls_mpi_write_string +#define net_accept mbedtls_net_accept +#define net_bind mbedtls_net_bind +#define net_close mbedtls_net_free +#define net_connect mbedtls_net_connect +#define net_recv mbedtls_net_recv +#define net_recv_timeout mbedtls_net_recv_timeout +#define net_send mbedtls_net_send +#define net_set_block mbedtls_net_set_block +#define net_set_nonblock mbedtls_net_set_nonblock +#define net_usleep mbedtls_net_usleep +#define oid_descriptor_t mbedtls_oid_descriptor_t +#define oid_get_attr_short_name mbedtls_oid_get_attr_short_name +#define oid_get_cipher_alg mbedtls_oid_get_cipher_alg +#define oid_get_ec_grp mbedtls_oid_get_ec_grp +#define oid_get_extended_key_usage mbedtls_oid_get_extended_key_usage +#define oid_get_md_alg mbedtls_oid_get_md_alg +#define oid_get_numeric_string mbedtls_oid_get_numeric_string +#define oid_get_oid_by_ec_grp mbedtls_oid_get_oid_by_ec_grp +#define oid_get_oid_by_md mbedtls_oid_get_oid_by_md +#define oid_get_oid_by_pk_alg mbedtls_oid_get_oid_by_pk_alg +#define oid_get_oid_by_sig_alg mbedtls_oid_get_oid_by_sig_alg +#define oid_get_pk_alg mbedtls_oid_get_pk_alg +#define oid_get_pkcs12_pbe_alg mbedtls_oid_get_pkcs12_pbe_alg +#define oid_get_sig_alg mbedtls_oid_get_sig_alg +#define oid_get_sig_alg_desc mbedtls_oid_get_sig_alg_desc +#define oid_get_x509_ext_type mbedtls_oid_get_x509_ext_type +#define operation_t mbedtls_operation_t +#define padlock_supports mbedtls_padlock_has_support +#define padlock_xcryptcbc mbedtls_padlock_xcryptcbc +#define padlock_xcryptecb mbedtls_padlock_xcryptecb +#define pbkdf2_hmac mbedtls_pbkdf2_hmac +#define pbkdf2_self_test mbedtls_pbkdf2_self_test +#define pem_context mbedtls_pem_context +#define pem_free mbedtls_pem_free +#define pem_init mbedtls_pem_init +#define pem_read_buffer mbedtls_pem_read_buffer +#define pem_write_buffer mbedtls_pem_write_buffer +#define pk_can_do mbedtls_pk_can_do +#define pk_check_pair mbedtls_pk_check_pair +#define pk_context mbedtls_pk_context +#define pk_debug mbedtls_pk_debug +#define pk_debug_item mbedtls_pk_debug_item +#define pk_debug_type mbedtls_pk_debug_type +#define pk_decrypt mbedtls_pk_decrypt +#define pk_ec mbedtls_pk_ec +#define pk_encrypt mbedtls_pk_encrypt +#define pk_free mbedtls_pk_free +#define pk_get_len mbedtls_pk_get_len +#define pk_get_name mbedtls_pk_get_name +#define pk_get_size mbedtls_pk_get_bitlen +#define pk_get_type mbedtls_pk_get_type +#define pk_info_from_type mbedtls_pk_info_from_type +#define pk_info_t mbedtls_pk_info_t +#define pk_init mbedtls_pk_init +#define pk_init_ctx mbedtls_pk_setup +#define pk_init_ctx_rsa_alt mbedtls_pk_setup_rsa_alt +#define pk_load_file mbedtls_pk_load_file +#define pk_parse_key mbedtls_pk_parse_key +#define pk_parse_keyfile mbedtls_pk_parse_keyfile +#define pk_parse_public_key mbedtls_pk_parse_public_key +#define pk_parse_public_keyfile mbedtls_pk_parse_public_keyfile +#define pk_parse_subpubkey mbedtls_pk_parse_subpubkey +#define pk_rsa mbedtls_pk_rsa +#define pk_rsa_alt_decrypt_func mbedtls_pk_rsa_alt_decrypt_func +#define pk_rsa_alt_key_len_func mbedtls_pk_rsa_alt_key_len_func +#define pk_rsa_alt_sign_func mbedtls_pk_rsa_alt_sign_func +#define pk_rsassa_pss_options mbedtls_pk_rsassa_pss_options +#define pk_sign mbedtls_pk_sign +#define pk_type_t mbedtls_pk_type_t +#define pk_verify mbedtls_pk_verify +#define pk_verify_ext mbedtls_pk_verify_ext +#define pk_write_key_der mbedtls_pk_write_key_der +#define pk_write_key_pem mbedtls_pk_write_key_pem +#define pk_write_pubkey mbedtls_pk_write_pubkey +#define pk_write_pubkey_der mbedtls_pk_write_pubkey_der +#define pk_write_pubkey_pem mbedtls_pk_write_pubkey_pem +#define pkcs11_context mbedtls_pkcs11_context +#define pkcs11_decrypt mbedtls_pkcs11_decrypt +#define pkcs11_priv_key_free mbedtls_pkcs11_priv_key_free +#define pkcs11_priv_key_init mbedtls_pkcs11_priv_key_bind +#define pkcs11_sign mbedtls_pkcs11_sign +#define pkcs11_x509_cert_init mbedtls_pkcs11_x509_cert_bind +#define pkcs12_derivation mbedtls_pkcs12_derivation +#define pkcs12_pbe mbedtls_pkcs12_pbe +#define pkcs12_pbe_sha1_rc4_128 mbedtls_pkcs12_pbe_sha1_rc4_128 +#define pkcs5_pbes2 mbedtls_pkcs5_pbes2 +#define pkcs5_pbkdf2_hmac mbedtls_pkcs5_pbkdf2_hmac +#define pkcs5_self_test mbedtls_pkcs5_self_test +#define platform_entropy_poll mbedtls_platform_entropy_poll +#define platform_set_exit mbedtls_platform_set_exit +#define platform_set_fprintf mbedtls_platform_set_fprintf +#define platform_set_malloc_free mbedtls_platform_set_malloc_free +#define platform_set_printf mbedtls_platform_set_printf +#define platform_set_snprintf mbedtls_platform_set_snprintf +#define polarssl_exit mbedtls_exit +#define polarssl_fprintf mbedtls_fprintf +#define polarssl_free mbedtls_free +#define polarssl_malloc mbedtls_malloc +#define polarssl_mutex_free mbedtls_mutex_free +#define polarssl_mutex_init mbedtls_mutex_init +#define polarssl_mutex_lock mbedtls_mutex_lock +#define polarssl_mutex_unlock mbedtls_mutex_unlock +#define polarssl_printf mbedtls_printf +#define polarssl_snprintf mbedtls_snprintf +#define polarssl_strerror mbedtls_strerror +#define ripemd160 mbedtls_ripemd160 +#define ripemd160_context mbedtls_ripemd160_context +#define ripemd160_file mbedtls_ripemd160_file +#define ripemd160_finish mbedtls_ripemd160_finish +#define ripemd160_free mbedtls_ripemd160_free +#define ripemd160_hmac mbedtls_ripemd160_hmac +#define ripemd160_hmac_finish mbedtls_ripemd160_hmac_finish +#define ripemd160_hmac_reset mbedtls_ripemd160_hmac_reset +#define ripemd160_hmac_starts mbedtls_ripemd160_hmac_starts +#define ripemd160_hmac_update mbedtls_ripemd160_hmac_update +#define ripemd160_info mbedtls_ripemd160_info +#define ripemd160_init mbedtls_ripemd160_init +#define ripemd160_process mbedtls_ripemd160_process +#define ripemd160_self_test mbedtls_ripemd160_self_test +#define ripemd160_starts mbedtls_ripemd160_starts +#define ripemd160_update mbedtls_ripemd160_update +#define rsa_alt_context mbedtls_rsa_alt_context +#define rsa_alt_info mbedtls_rsa_alt_info +#define rsa_check_privkey mbedtls_rsa_check_privkey +#define rsa_check_pub_priv mbedtls_rsa_check_pub_priv +#define rsa_check_pubkey mbedtls_rsa_check_pubkey +#define rsa_context mbedtls_rsa_context +#define rsa_copy mbedtls_rsa_copy +#define rsa_decrypt_func mbedtls_rsa_decrypt_func +#define rsa_free mbedtls_rsa_free +#define rsa_gen_key mbedtls_rsa_gen_key +#define rsa_info mbedtls_rsa_info +#define rsa_init mbedtls_rsa_init +#define rsa_key_len_func mbedtls_rsa_key_len_func +#define rsa_pkcs1_decrypt mbedtls_rsa_pkcs1_decrypt +#define rsa_pkcs1_encrypt mbedtls_rsa_pkcs1_encrypt +#define rsa_pkcs1_sign mbedtls_rsa_pkcs1_sign +#define rsa_pkcs1_verify mbedtls_rsa_pkcs1_verify +#define rsa_private mbedtls_rsa_private +#define rsa_public mbedtls_rsa_public +#define rsa_rsaes_oaep_decrypt mbedtls_rsa_rsaes_oaep_decrypt +#define rsa_rsaes_oaep_encrypt mbedtls_rsa_rsaes_oaep_encrypt +#define rsa_rsaes_pkcs1_v15_decrypt mbedtls_rsa_rsaes_pkcs1_v15_decrypt +#define rsa_rsaes_pkcs1_v15_encrypt mbedtls_rsa_rsaes_pkcs1_v15_encrypt +#define rsa_rsassa_pkcs1_v15_sign mbedtls_rsa_rsassa_pkcs1_v15_sign +#define rsa_rsassa_pkcs1_v15_verify mbedtls_rsa_rsassa_pkcs1_v15_verify +#define rsa_rsassa_pss_sign mbedtls_rsa_rsassa_pss_sign +#define rsa_rsassa_pss_verify mbedtls_rsa_rsassa_pss_verify +#define rsa_rsassa_pss_verify_ext mbedtls_rsa_rsassa_pss_verify_ext +#define rsa_self_test mbedtls_rsa_self_test +#define rsa_set_padding mbedtls_rsa_set_padding +#define rsa_sign_func mbedtls_rsa_sign_func +#define safer_memcmp mbedtls_ssl_safer_memcmp +#define set_alarm mbedtls_set_alarm +#define sha1 mbedtls_sha1 +#define sha1_context mbedtls_sha1_context +#define sha1_file mbedtls_sha1_file +#define sha1_finish mbedtls_sha1_finish +#define sha1_free mbedtls_sha1_free +#define sha1_hmac mbedtls_sha1_hmac +#define sha1_hmac_finish mbedtls_sha1_hmac_finish +#define sha1_hmac_reset mbedtls_sha1_hmac_reset +#define sha1_hmac_starts mbedtls_sha1_hmac_starts +#define sha1_hmac_update mbedtls_sha1_hmac_update +#define sha1_info mbedtls_sha1_info +#define sha1_init mbedtls_sha1_init +#define sha1_process mbedtls_sha1_process +#define sha1_self_test mbedtls_sha1_self_test +#define sha1_starts mbedtls_sha1_starts +#define sha1_update mbedtls_sha1_update +#define sha224_info mbedtls_sha224_info +#define sha256 mbedtls_sha256 +#define sha256_context mbedtls_sha256_context +#define sha256_file mbedtls_sha256_file +#define sha256_finish mbedtls_sha256_finish +#define sha256_free mbedtls_sha256_free +#define sha256_hmac mbedtls_sha256_hmac +#define sha256_hmac_finish mbedtls_sha256_hmac_finish +#define sha256_hmac_reset mbedtls_sha256_hmac_reset +#define sha256_hmac_starts mbedtls_sha256_hmac_starts +#define sha256_hmac_update mbedtls_sha256_hmac_update +#define sha256_info mbedtls_sha256_info +#define sha256_init mbedtls_sha256_init +#define sha256_process mbedtls_sha256_process +#define sha256_self_test mbedtls_sha256_self_test +#define sha256_starts mbedtls_sha256_starts +#define sha256_update mbedtls_sha256_update +#define sha384_info mbedtls_sha384_info +#define sha512 mbedtls_sha512 +#define sha512_context mbedtls_sha512_context +#define sha512_file mbedtls_sha512_file +#define sha512_finish mbedtls_sha512_finish +#define sha512_free mbedtls_sha512_free +#define sha512_hmac mbedtls_sha512_hmac +#define sha512_hmac_finish mbedtls_sha512_hmac_finish +#define sha512_hmac_reset mbedtls_sha512_hmac_reset +#define sha512_hmac_starts mbedtls_sha512_hmac_starts +#define sha512_hmac_update mbedtls_sha512_hmac_update +#define sha512_info mbedtls_sha512_info +#define sha512_init mbedtls_sha512_init +#define sha512_process mbedtls_sha512_process +#define sha512_self_test mbedtls_sha512_self_test +#define sha512_starts mbedtls_sha512_starts +#define sha512_update mbedtls_sha512_update +#define source_state mbedtls_entropy_source_state +#define ssl_cache_context mbedtls_ssl_cache_context +#define ssl_cache_entry mbedtls_ssl_cache_entry +#define ssl_cache_free mbedtls_ssl_cache_free +#define ssl_cache_get mbedtls_ssl_cache_get +#define ssl_cache_init mbedtls_ssl_cache_init +#define ssl_cache_set mbedtls_ssl_cache_set +#define ssl_cache_set_max_entries mbedtls_ssl_cache_set_max_entries +#define ssl_cache_set_timeout mbedtls_ssl_cache_set_timeout +#define ssl_check_cert_usage mbedtls_ssl_check_cert_usage +#define ssl_ciphersuite_from_id mbedtls_ssl_ciphersuite_from_id +#define ssl_ciphersuite_from_string mbedtls_ssl_ciphersuite_from_string +#define ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define ssl_ciphersuite_uses_ec mbedtls_ssl_ciphersuite_uses_ec +#define ssl_ciphersuite_uses_psk mbedtls_ssl_ciphersuite_uses_psk +#define ssl_close_notify mbedtls_ssl_close_notify +#define ssl_context mbedtls_ssl_context +#define ssl_cookie_check mbedtls_ssl_cookie_check +#define ssl_cookie_check_t mbedtls_ssl_cookie_check_t +#define ssl_cookie_ctx mbedtls_ssl_cookie_ctx +#define ssl_cookie_free mbedtls_ssl_cookie_free +#define ssl_cookie_init mbedtls_ssl_cookie_init +#define ssl_cookie_set_timeout mbedtls_ssl_cookie_set_timeout +#define ssl_cookie_setup mbedtls_ssl_cookie_setup +#define ssl_cookie_write mbedtls_ssl_cookie_write +#define ssl_cookie_write_t mbedtls_ssl_cookie_write_t +#define ssl_curve_is_acceptable mbedtls_ssl_curve_is_acceptable +#define ssl_derive_keys mbedtls_ssl_derive_keys +#define ssl_dtls_replay_check mbedtls_ssl_dtls_replay_check +#define ssl_dtls_replay_update mbedtls_ssl_dtls_replay_update +#define ssl_fetch_input mbedtls_ssl_fetch_input +#define ssl_flight_item mbedtls_ssl_flight_item +#define ssl_flush_output mbedtls_ssl_flush_output +#define ssl_free mbedtls_ssl_free +#define ssl_get_alpn_protocol mbedtls_ssl_get_alpn_protocol +#define ssl_get_bytes_avail mbedtls_ssl_get_bytes_avail +#define ssl_get_ciphersuite mbedtls_ssl_get_ciphersuite +#define ssl_get_ciphersuite_id mbedtls_ssl_get_ciphersuite_id +#define ssl_get_ciphersuite_name mbedtls_ssl_get_ciphersuite_name +#define ssl_get_ciphersuite_sig_pk_alg mbedtls_ssl_get_ciphersuite_sig_pk_alg +#define ssl_get_peer_cert mbedtls_ssl_get_peer_cert +#define ssl_get_record_expansion mbedtls_ssl_get_record_expansion +#define ssl_get_session mbedtls_ssl_get_session +#define ssl_get_verify_result mbedtls_ssl_get_verify_result +#define ssl_get_version mbedtls_ssl_get_version +#define ssl_handshake mbedtls_ssl_handshake +#define ssl_handshake_client_step mbedtls_ssl_handshake_client_step +#define ssl_handshake_free mbedtls_ssl_handshake_free +#define ssl_handshake_params mbedtls_ssl_handshake_params +#define ssl_handshake_server_step mbedtls_ssl_handshake_server_step +#define ssl_handshake_step mbedtls_ssl_handshake_step +#define ssl_handshake_wrapup mbedtls_ssl_handshake_wrapup +#define ssl_hdr_len mbedtls_ssl_hdr_len +#define ssl_hs_hdr_len mbedtls_ssl_hs_hdr_len +#define ssl_hw_record_activate mbedtls_ssl_hw_record_activate +#define ssl_hw_record_finish mbedtls_ssl_hw_record_finish +#define ssl_hw_record_init mbedtls_ssl_hw_record_init +#define ssl_hw_record_read mbedtls_ssl_hw_record_read +#define ssl_hw_record_reset mbedtls_ssl_hw_record_reset +#define ssl_hw_record_write mbedtls_ssl_hw_record_write +#define ssl_init mbedtls_ssl_init +#define ssl_key_cert mbedtls_ssl_key_cert +#define ssl_legacy_renegotiation mbedtls_ssl_conf_legacy_renegotiation +#define ssl_list_ciphersuites mbedtls_ssl_list_ciphersuites +#define ssl_md_alg_from_hash mbedtls_ssl_md_alg_from_hash +#define ssl_optimize_checksum mbedtls_ssl_optimize_checksum +#define ssl_own_cert mbedtls_ssl_own_cert +#define ssl_own_key mbedtls_ssl_own_key +#define ssl_parse_certificate mbedtls_ssl_parse_certificate +#define ssl_parse_change_cipher_spec mbedtls_ssl_parse_change_cipher_spec +#define ssl_parse_finished mbedtls_ssl_parse_finished +#define ssl_pk_alg_from_sig mbedtls_ssl_pk_alg_from_sig +#define ssl_pkcs11_decrypt mbedtls_ssl_pkcs11_decrypt +#define ssl_pkcs11_key_len mbedtls_ssl_pkcs11_key_len +#define ssl_pkcs11_sign mbedtls_ssl_pkcs11_sign +#define ssl_psk_derive_premaster mbedtls_ssl_psk_derive_premaster +#define ssl_read mbedtls_ssl_read +#define ssl_read_record mbedtls_ssl_read_record +#define ssl_read_version mbedtls_ssl_read_version +#define ssl_recv_flight_completed mbedtls_ssl_recv_flight_completed +#define ssl_renegotiate mbedtls_ssl_renegotiate +#define ssl_resend mbedtls_ssl_resend +#define ssl_reset_checksum mbedtls_ssl_reset_checksum +#define ssl_send_alert_message mbedtls_ssl_send_alert_message +#define ssl_send_fatal_handshake_failure mbedtls_ssl_send_fatal_handshake_failure +#define ssl_send_flight_completed mbedtls_ssl_send_flight_completed +#define ssl_session mbedtls_ssl_session +#define ssl_session_free mbedtls_ssl_session_free +#define ssl_session_init mbedtls_ssl_session_init +#define ssl_session_reset mbedtls_ssl_session_reset +#define ssl_set_alpn_protocols mbedtls_ssl_conf_alpn_protocols +#define ssl_set_arc4_support mbedtls_ssl_conf_arc4_support +#define ssl_set_authmode mbedtls_ssl_conf_authmode +#define ssl_set_bio mbedtls_ssl_set_bio +#define ssl_set_bio mbedtls_ssl_set_bio_timeout +#define ssl_set_ca_chain mbedtls_ssl_conf_ca_chain +#define ssl_set_cbc_record_splitting mbedtls_ssl_conf_cbc_record_splitting +#define ssl_set_ciphersuites mbedtls_ssl_conf_ciphersuites +#define ssl_set_ciphersuites_for_version mbedtls_ssl_conf_ciphersuites_for_version +#define ssl_set_client_transport_id mbedtls_ssl_set_client_transport_id +#define ssl_set_curves mbedtls_ssl_conf_curves +#define ssl_set_dbg mbedtls_ssl_conf_dbg +#define ssl_set_dh_param mbedtls_ssl_conf_dh_param +#define ssl_set_dh_param_ctx mbedtls_ssl_conf_dh_param_ctx +#define ssl_set_dtls_anti_replay mbedtls_ssl_conf_dtls_anti_replay +#define ssl_set_dtls_badmac_limit mbedtls_ssl_conf_dtls_badmac_limit +#define ssl_set_dtls_cookies mbedtls_ssl_conf_dtls_cookies +#define ssl_set_encrypt_then_mac mbedtls_ssl_conf_encrypt_then_mac +#define ssl_set_endpoint mbedtls_ssl_conf_endpoint +#define ssl_set_extended_master_secret mbedtls_ssl_conf_extended_master_secret +#define ssl_set_fallback mbedtls_ssl_conf_fallback +#define ssl_set_handshake_timeout mbedtls_ssl_conf_handshake_timeout +#define ssl_set_hostname mbedtls_ssl_set_hostname +#define ssl_set_max_frag_len mbedtls_ssl_conf_max_frag_len +#define ssl_set_max_version mbedtls_ssl_conf_max_version +#define ssl_set_min_version mbedtls_ssl_conf_min_version +#define ssl_set_own_cert mbedtls_ssl_conf_own_cert +#define ssl_set_own_cert_alt mbedtls_ssl_set_own_cert_alt +#define ssl_set_own_cert_rsa mbedtls_ssl_set_own_cert_rsa +#define ssl_set_psk mbedtls_ssl_conf_psk +#define ssl_set_psk_cb mbedtls_ssl_conf_psk_cb +#define ssl_set_renegotiation mbedtls_ssl_conf_renegotiation +#define ssl_set_renegotiation_enforced mbedtls_ssl_conf_renegotiation_enforced +#define ssl_set_renegotiation_period mbedtls_ssl_conf_renegotiation_period +#define ssl_set_rng mbedtls_ssl_conf_rng +#define ssl_set_session mbedtls_ssl_set_session +#define ssl_set_session_cache mbedtls_ssl_conf_session_cache +#define ssl_set_session_ticket_lifetime mbedtls_ssl_conf_session_ticket_lifetime +#define ssl_set_session_tickets mbedtls_ssl_conf_session_tickets +#define ssl_set_sni mbedtls_ssl_conf_sni +#define ssl_set_transport mbedtls_ssl_conf_transport +#define ssl_set_truncated_hmac mbedtls_ssl_conf_truncated_hmac +#define ssl_set_verify mbedtls_ssl_conf_verify +#define ssl_sig_from_pk mbedtls_ssl_sig_from_pk +#define ssl_states mbedtls_ssl_states +#define ssl_ticket_keys mbedtls_ssl_ticket_keys +#define ssl_transform mbedtls_ssl_transform +#define ssl_transform_free mbedtls_ssl_transform_free +#define ssl_write mbedtls_ssl_write +#define ssl_write_certificate mbedtls_ssl_write_certificate +#define ssl_write_change_cipher_spec mbedtls_ssl_write_change_cipher_spec +#define ssl_write_finished mbedtls_ssl_write_finished +#define ssl_write_record mbedtls_ssl_write_record +#define ssl_write_version mbedtls_ssl_write_version +#define supported_ciphers mbedtls_cipher_supported +#define t_sint mbedtls_mpi_sint +#define t_udbl mbedtls_t_udbl +#define t_uint mbedtls_mpi_uint +#define test_ca_crt mbedtls_test_ca_crt +#define test_ca_crt_ec mbedtls_test_ca_crt_ec +#define test_ca_crt_rsa mbedtls_test_ca_crt_rsa +#define test_ca_key mbedtls_test_ca_key +#define test_ca_key_ec mbedtls_test_ca_key_ec +#define test_ca_key_rsa mbedtls_test_ca_key_rsa +#define test_ca_list mbedtls_test_cas_pem +#define test_ca_pwd mbedtls_test_ca_pwd +#define test_ca_pwd_ec mbedtls_test_ca_pwd_ec +#define test_ca_pwd_rsa mbedtls_test_ca_pwd_rsa +#define test_cli_crt mbedtls_test_cli_crt +#define test_cli_crt_ec mbedtls_test_cli_crt_ec +#define test_cli_crt_rsa mbedtls_test_cli_crt_rsa +#define test_cli_key mbedtls_test_cli_key +#define test_cli_key_ec mbedtls_test_cli_key_ec +#define test_cli_key_rsa mbedtls_test_cli_key_rsa +#define test_dhm_params mbedtls_test_dhm_params +#define test_srv_crt mbedtls_test_srv_crt +#define test_srv_crt_ec mbedtls_test_srv_crt_ec +#define test_srv_crt_rsa mbedtls_test_srv_crt_rsa +#define test_srv_key mbedtls_test_srv_key +#define test_srv_key_ec mbedtls_test_srv_key_ec +#define test_srv_key_rsa mbedtls_test_srv_key_rsa +#define threading_mutex_t mbedtls_threading_mutex_t +#define threading_set_alt mbedtls_threading_set_alt +#define timing_self_test mbedtls_timing_self_test +#define version_check_feature mbedtls_version_check_feature +#define version_get_number mbedtls_version_get_number +#define version_get_string mbedtls_version_get_string +#define version_get_string_full mbedtls_version_get_string_full +#define x509_bitstring mbedtls_x509_bitstring +#define x509_buf mbedtls_x509_buf +#define x509_crl mbedtls_x509_crl +#define x509_crl_entry mbedtls_x509_crl_entry +#define x509_crl_free mbedtls_x509_crl_free +#define x509_crl_info mbedtls_x509_crl_info +#define x509_crl_init mbedtls_x509_crl_init +#define x509_crl_parse mbedtls_x509_crl_parse +#define x509_crl_parse_der mbedtls_x509_crl_parse_der +#define x509_crl_parse_file mbedtls_x509_crl_parse_file +#define x509_crt mbedtls_x509_crt +#define x509_crt_check_extended_key_usage mbedtls_x509_crt_check_extended_key_usage +#define x509_crt_check_key_usage mbedtls_x509_crt_check_key_usage +#define x509_crt_free mbedtls_x509_crt_free +#define x509_crt_info mbedtls_x509_crt_info +#define x509_crt_init mbedtls_x509_crt_init +#define x509_crt_parse mbedtls_x509_crt_parse +#define x509_crt_parse_der mbedtls_x509_crt_parse_der +#define x509_crt_parse_file mbedtls_x509_crt_parse_file +#define x509_crt_parse_path mbedtls_x509_crt_parse_path +#define x509_crt_revoked mbedtls_x509_crt_is_revoked +#define x509_crt_verify mbedtls_x509_crt_verify +#define x509_csr mbedtls_x509_csr +#define x509_csr_free mbedtls_x509_csr_free +#define x509_csr_info mbedtls_x509_csr_info +#define x509_csr_init mbedtls_x509_csr_init +#define x509_csr_parse mbedtls_x509_csr_parse +#define x509_csr_parse_der mbedtls_x509_csr_parse_der +#define x509_csr_parse_file mbedtls_x509_csr_parse_file +#define x509_dn_gets mbedtls_x509_dn_gets +#define x509_get_alg mbedtls_x509_get_alg +#define x509_get_alg_null mbedtls_x509_get_alg_null +#define x509_get_ext mbedtls_x509_get_ext +#define x509_get_name mbedtls_x509_get_name +#define x509_get_rsassa_pss_params mbedtls_x509_get_rsassa_pss_params +#define x509_get_serial mbedtls_x509_get_serial +#define x509_get_sig mbedtls_x509_get_sig +#define x509_get_sig_alg mbedtls_x509_get_sig_alg +#define x509_get_time mbedtls_x509_get_time +#define x509_key_size_helper mbedtls_x509_key_size_helper +#define x509_name mbedtls_x509_name +#define x509_oid_get_description mbedtls_x509_oid_get_description +#define x509_oid_get_numeric_string mbedtls_x509_oid_get_numeric_string +#define x509_self_test mbedtls_x509_self_test +#define x509_sequence mbedtls_x509_sequence +#define x509_serial_gets mbedtls_x509_serial_gets +#define x509_set_extension mbedtls_x509_set_extension +#define x509_sig_alg_gets mbedtls_x509_sig_alg_gets +#define x509_string_to_names mbedtls_x509_string_to_names +#define x509_time mbedtls_x509_time +#define x509_time_expired mbedtls_x509_time_is_past +#define x509_time_future mbedtls_x509_time_is_future +#define x509_write_extensions mbedtls_x509_write_extensions +#define x509_write_names mbedtls_x509_write_names +#define x509_write_sig mbedtls_x509_write_sig +#define x509write_cert mbedtls_x509write_cert +#define x509write_crt_der mbedtls_x509write_crt_der +#define x509write_crt_free mbedtls_x509write_crt_free +#define x509write_crt_init mbedtls_x509write_crt_init +#define x509write_crt_pem mbedtls_x509write_crt_pem +#define x509write_crt_set_authority_key_identifier mbedtls_x509write_crt_set_authority_key_identifier +#define x509write_crt_set_basic_constraints mbedtls_x509write_crt_set_basic_constraints +#define x509write_crt_set_extension mbedtls_x509write_crt_set_extension +#define x509write_crt_set_issuer_key mbedtls_x509write_crt_set_issuer_key +#define x509write_crt_set_issuer_name mbedtls_x509write_crt_set_issuer_name +#define x509write_crt_set_key_usage mbedtls_x509write_crt_set_key_usage +#define x509write_crt_set_md_alg mbedtls_x509write_crt_set_md_alg +#define x509write_crt_set_ns_cert_type mbedtls_x509write_crt_set_ns_cert_type +#define x509write_crt_set_serial mbedtls_x509write_crt_set_serial +#define x509write_crt_set_subject_key mbedtls_x509write_crt_set_subject_key +#define x509write_crt_set_subject_key_identifier mbedtls_x509write_crt_set_subject_key_identifier +#define x509write_crt_set_subject_name mbedtls_x509write_crt_set_subject_name +#define x509write_crt_set_validity mbedtls_x509write_crt_set_validity +#define x509write_crt_set_version mbedtls_x509write_crt_set_version +#define x509write_csr mbedtls_x509write_csr +#define x509write_csr_der mbedtls_x509write_csr_der +#define x509write_csr_free mbedtls_x509write_csr_free +#define x509write_csr_init mbedtls_x509write_csr_init +#define x509write_csr_pem mbedtls_x509write_csr_pem +#define x509write_csr_set_extension mbedtls_x509write_csr_set_extension +#define x509write_csr_set_key mbedtls_x509write_csr_set_key +#define x509write_csr_set_key_usage mbedtls_x509write_csr_set_key_usage +#define x509write_csr_set_md_alg mbedtls_x509write_csr_set_md_alg +#define x509write_csr_set_ns_cert_type mbedtls_x509write_csr_set_ns_cert_type +#define x509write_csr_set_subject_name mbedtls_x509write_csr_set_subject_name +#define xtea_context mbedtls_xtea_context +#define xtea_crypt_cbc mbedtls_xtea_crypt_cbc +#define xtea_crypt_ecb mbedtls_xtea_crypt_ecb +#define xtea_free mbedtls_xtea_free +#define xtea_init mbedtls_xtea_init +#define xtea_self_test mbedtls_xtea_self_test +#define xtea_setup mbedtls_xtea_setup + +#endif /* compat-1.3.h */ +#endif /* MBEDTLS_DEPRECATED_REMOVED */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config.h new file mode 100644 index 0000000000..d1db0d825a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config.h @@ -0,0 +1,2511 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto or hash module (e.g. + * platform specific assembly optimized implementations). Keep in mind that + * the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +//#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_AEAD_RANDOM_IV + * + * Generate a random IV rather than using the record sequence number as a + * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). + * + * Using the sequence number is generally recommended. + * + * Uncomment this macro to always use random IVs with AEAD ciphersuites. + */ +//#define MBEDTLS_SSL_AEAD_RANDOM_IV + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/mbedtls_md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/mbedtls_md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * + * This module provides TCP/IP networking routines. + */ +#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/mbedtls_ripemd160.c + * Caller: library/mbedtls_md.c + * + */ +#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha512.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/mbedtls_x509_crl.c + * Caller: library/mbedtls_x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/mbedtls_x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ + +/* \} name SECTION: Module configuration options */ + +#if defined(TARGET_LIKE_MBED) +#include "mbedtls/target_config.h" +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config_esp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config_esp.h new file mode 100644 index 0000000000..969728bcf9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/config_esp.h @@ -0,0 +1,2524 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#include "c_types.h" + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Comment if your system does not support time functions + */ +//#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +//#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto or hash module (e.g. + * platform specific assembly optimized implementations). Keep in mind that + * the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +//#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +//#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +//#define MBEDTLS_CIPHER_PADDING_PKCS7 +//#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +//#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +//#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +//#define MBEDTLS_ECP_DP_BP256R1_ENABLED +//#define MBEDTLS_ECP_DP_BP384R1_ENABLED +//#define MBEDTLS_ECP_DP_BP512R1_ENABLED +//#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +//#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +//#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +//#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +//#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_AEAD_RANDOM_IV + * + * Generate a random IV rather than using the record sequence number as a + * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). + * + * Using the sequence number is generally recommended. + * + * Uncomment this macro to always use random IVs with AEAD ciphersuites. + */ +//#define MBEDTLS_SSL_AEAD_RANDOM_IV + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +//#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +//#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +//#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + */ +//#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +//#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +//#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +//#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +//#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +//#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +//#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +//#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +//#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +//#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +//#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +//#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +//#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +//#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +//#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +//#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +//#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +//#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +//#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +//#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +//#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +//#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +//#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +//#define MBEDTLS_GCM_C //764 Byte + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +//#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/mbedtls_md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/mbedtls_md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * + * This module provides TCP/IP networking routines. + */ +//#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +//#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +//#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +//#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/mbedtls_ripemd160.c + * Caller: library/mbedtls_md.c + * + */ +//#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha512.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +//#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +//#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +//#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/mbedtls_x509_crl.c + * Caller: library/mbedtls_x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/mbedtls_x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +extern unsigned int max_content_len; +#define MBEDTLS_SSL_MAX_CONTENT_LEN max_content_len /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * \def ESP8266_PLATFORM + * + * Enable the ESP8266 PLATFORM. + * + * Module: library/ssl_tls.c + * Caller: + */ +#define ESP8266_PLATFORM + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ + +/* \} name SECTION: Module configuration options */ + +#if defined(TARGET_LIKE_MBED) +#include "mbedtls/target_config.h" +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ctr_drbg.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ctr_drbg.h new file mode 100644 index 0000000000..059d3c5c9a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ctr_drbg.h @@ -0,0 +1,290 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CTR_DRBG_H +#define MBEDTLS_CTR_DRBG_H + +#include "aes.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) +#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) + /**< The seed length (counter + AES key) */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +#else +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +#endif +#endif + +#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each + (re)seed */ + int reseed_interval; /*!< reseed interval */ + + mbedtls_aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief CTR_DRBG context initialization + * Makes the context ready for mbedtls_ctr_drbg_seed() or + * mbedtls_ctr_drbg_free(). + * + * \param ctx CTR_DRBG context to be initialized + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief CTR_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to make this instantiation as unique as possible. + * + * \param ctx CTR_DRBG context to be seeded + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Clear CTR_CRBG context data + * + * \param ctx CTR_DRBG context to clear + */ +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx CTR_DRBG context + * \param resistance MBEDTLS_CTR_DRBG_PR_ON or MBEDTLS_CTR_DRBG_PR_OFF + */ +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each (re)seed + * (Default: MBEDTLS_CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + * + * \note If add_len is greater than MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, + * only the first MBEDTLS_CTR_DRBG_MAX_SEED_INPUT bytes are used, + * the remaining ones are silently discarded. + */ +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ctr_drbg_self_test( int verbose ); + +/* Internal functions (do not call directly) */ +int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *, + int (*)(void *, unsigned char *, size_t), void *, + const unsigned char *, size_t, size_t ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/debug.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/debug.h new file mode 100644 index 0000000000..d859dd5f6d --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/debug.h @@ -0,0 +1,125 @@ +/** + * \file debug.h + * + * \brief Debug functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DEBUG_H +#define MBEDTLS_DEBUG_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#define MBEDTLS_DEBUG_STRIP_PARENS( ... ) __VA_ARGS__ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) \ + mbedtls_debug_print_msg( ssl, level, __FILE__, __LINE__, \ + MBEDTLS_DEBUG_STRIP_PARENS args ) + +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) \ + mbedtls_debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ) + +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) \ + mbedtls_debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ) + +#if defined(MBEDTLS_BIGNUM_C) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) \ + mbedtls_debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_ECP_C) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) \ + mbedtls_debug_print_ecp( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) \ + mbedtls_debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ) +#endif + +#else /* MBEDTLS_DEBUG_C */ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif /* MBEDTLS_DEBUG_C */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set the level threshold to handle globally. Messages that have a + * level over the threshold value are ignored. + * (Default value: 0 (No debug)) + * + * \param threshold maximum level of messages to pass on + */ +void mbedtls_debug_set_threshold( int threshold ); + +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ); + +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ); + +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ); + +#if defined(MBEDTLS_BIGNUM_C) +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ); +#endif + +#if defined(MBEDTLS_ECP_C) +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/des.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/des.h new file mode 100644 index 0000000000..5ca2ecf2e0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/des.h @@ -0,0 +1,306 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DES_H +#define MBEDTLS_DES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_DES_ENCRYPT 1 +#define MBEDTLS_DES_DECRYPT 0 + +#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define MBEDTLS_DES_KEY_SIZE 8 + +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + uint32_t sk[32]; /*!< DES subkeys */ +} +mbedtls_des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +mbedtls_des3_context; + +/** + * \brief Initialize DES context + * + * \param ctx DES context to be initialized + */ +void mbedtls_des_init( mbedtls_des_context *ctx ); + +/** + * \brief Clear DES context + * + * \param ctx DES context to be cleared + */ +void mbedtls_des_free( mbedtls_des_context *ctx ); + +/** + * \brief Initialize Triple-DES context + * + * \param ctx DES3 context to be initialized + */ +void mbedtls_des3_init( mbedtls_des3_context *ctx ); + +/** + * \brief Clear Triple-DES context + * + * \param ctx DES3 context to be cleared + */ +void mbedtls_des3_free( mbedtls_des3_context *ctx ); + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx 3DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief Internal function for key expansion. + * (Only exposed to allow overriding it, + * see MBEDTLS_DES_SETKEY_ALT) + * + * \param SK Round keys + * \param key Base key + */ +void mbedtls_des_setkey( uint32_t SK[32], + const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/dhm.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/dhm.h new file mode 100644 index 0000000000..cd056d1b4e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/dhm.h @@ -0,0 +1,305 @@ +/** + * \file dhm.h + * + * \brief Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DHM_H +#define MBEDTLS_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define MBEDTLS_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Making of the public value failed. */ +#define MBEDTLS_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ +#define MBEDTLS_ERR_DHM_INVALID_FORMAT -0x3380 /**< The ASN.1 data is not formatted correctly. */ +#define MBEDTLS_ERR_DHM_ALLOC_FAILED -0x3400 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_DHM_FILE_IO_ERROR -0x3480 /**< Read/write of file failed. */ + +/** + * RFC 3526 defines a number of standardized Diffie-Hellman groups + * for IKE. + * RFC 5114 defines a number of standardized Diffie-Hellman groups + * that can be used. + * + * Some are included here for convenience. + * + * Included are: + * RFC 3526 3. 2048-bit MODP Group + * RFC 3526 4. 3072-bit MODP Group + * RFC 3526 5. 4096-bit MODP Group + * RFC 5114 2.2. 2048-bit MODP Group with 224-bit Prime Order Subgroup + */ +#define MBEDTLS_DHM_RFC3526_MODP_2048_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_2048_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ + "FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_G "02" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_P \ + "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1" \ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" \ + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212" \ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" \ + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708" \ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" \ + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D" \ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" \ + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763" \ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" \ + "CF9DE5384E71B81C0AC4DFFE0C10E64F" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_G \ + "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"\ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA"\ + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"\ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A"\ + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"\ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF"\ + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"\ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381"\ + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"\ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179"\ + "81BC087F2A7065B384B890D3191F2BFA" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mbedtls_mpi P; /*!< prime modulus */ + mbedtls_mpi G; /*!< generator */ + mbedtls_mpi X; /*!< secret value */ + mbedtls_mpi GX; /*!< self = G^X mod P */ + mbedtls_mpi GY; /*!< peer = G^Y mod P */ + mbedtls_mpi K; /*!< key = GY^X mod P */ + mbedtls_mpi RP; /*!< cached R^2 mod P */ + mbedtls_mpi Vi; /*!< blinding value */ + mbedtls_mpi Vf; /*!< un-blinding value */ + mbedtls_mpi pX; /*!< previous X */ +} +mbedtls_dhm_context; + +/** + * \brief Initialize DHM context + * + * \param ctx DHM context to be initialized + */ +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mbedtls_mpi_read_string or mbedtls_mpi_read_binary). + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen must be equal to ctx->P.len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param output_size size of the destination buffer + * \param olen on exit, holds the actual number of bytes written + * \param f_rng RNG function, for blinding purposes + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + * + * \note If non-NULL, f_rng is used to blind the input as + * countermeasure against timing attacks. Blinding is + * automatically used if and only if our secret value X is + * re-used and costs nothing otherwise, so it is recommended + * to always pass a non-NULL f_rng argument. + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Free and clear the components of a DHM key + * + * \param ctx DHM context to free and clear + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); + +#if defined(MBEDTLS_ASN1_PARSE_C) +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters in PEM or DER format + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* dhm.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdh.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdh.h new file mode 100644 index 0000000000..625a281923 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdh.h @@ -0,0 +1,214 @@ +/** + * \file ecdh.h + * + * \brief Elliptic curve Diffie-Hellman + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECDH_H +#define MBEDTLS_ECDH_H + +#include "ecp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * When importing from an EC key, select if it is our key or the peer's key + */ +typedef enum +{ + MBEDTLS_ECDH_OURS, + MBEDTLS_ECDH_THEIRS, +} mbedtls_ecdh_side; + +/** + * \brief ECDH context structure + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< elliptic curve used */ + mbedtls_mpi d; /*!< our secret value (private key) */ + mbedtls_ecp_point Q; /*!< our public value (public key) */ + mbedtls_ecp_point Qp; /*!< peer's public value (public key) */ + mbedtls_mpi z; /*!< shared secret */ + int point_format; /*!< format for point export in TLS messages */ + mbedtls_ecp_point Vi; /*!< blinding value (for later) */ + mbedtls_ecp_point Vf; /*!< un-blinding value (for later) */ + mbedtls_mpi _d; /*!< previous d (for later) */ +} +mbedtls_ecdh_context; + +/** + * \brief Generate a public key. + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param d Destination MPI (secret exponent, aka private key) + * \param Q Destination point (public key) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Compute shared secret + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param z Destination MPI (shared secret) + * \param Q Public key from other party + * \param d Our secret exponent (private key) + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note If f_rng is not NULL, it is used to implement + * countermeasures against potential elaborate timing + * attacks, see \c mbedtls_ecp_mul() for details. + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); + +/** + * \brief Generate a public key and a TLS ServerKeyExchange payload. + * (First function used by a TLS server for ECDHE.) + * + * \param ctx ECDH context + * \param olen number of chars written + * \param buf destination buffer + * \param blen length of buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->grp has already been + * properly set (for example using mbedtls_ecp_group_load). + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Parse and procress a TLS ServerKeyExhange payload. + * (First function used by a TLS client for ECDHE.) + * + * \param ctx ECDH context + * \param buf pointer to start of input buffer + * \param end one past end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, const unsigned char *end ); + +/** + * \brief Setup an ECDH context from an EC key. + * (Used by clients and servers in place of the + * ServerKeyEchange for static ECDH: import ECDH parameters + * from a certificate's EC key information.) + * + * \param ctx ECDH constext to set + * \param key EC key to use + * \param side Is it our key (1) or the peer's key (0) ? + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ); + +/** + * \brief Generate a public key and a TLS ClientKeyExchange payload. + * (Second function used by a TLS client for ECDH(E).) + * + * \param ctx ECDH context + * \param olen number of bytes actually written + * \param buf destination buffer + * \param blen size of destination buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Parse and process a TLS ClientKeyExchange payload. + * (Second function used by a TLS server for ECDH(E).) + * + * \param ctx ECDH context + * \param buf start of input buffer + * \param blen length of input buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); + +/** + * \brief Derive and export the shared secret. + * (Last function used by both TLS client en servers.) + * + * \param ctx ECDH context + * \param olen number of bytes written + * \param buf destination buffer + * \param blen buffer length + * \param f_rng RNG function, see notes for \c mbedtls_ecdh_compute_shared() + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdh.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdsa.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdsa.h new file mode 100644 index 0000000000..52827d8d1a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecdsa.h @@ -0,0 +1,248 @@ +/** + * \file ecdsa.h + * + * \brief Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECDSA_H +#define MBEDTLS_ECDSA_H + +#include "ecp.h" +#include "md.h" + +/* + * RFC 4492 page 20: + * + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * Size is at most + * 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s, + * twice that + 1 (tag) + 2 (len) for the sequence + * (assuming ECP_MAX_BYTES is less than 126 for r and s, + * and less than 124 (total len <= 255) for the sequence) + */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif +/** Maximum size of an ECDSA signature in bytes */ +#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) + +/** + * \brief ECDSA context structure + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Compute ECDSA signature of a previously hashed message + * + * \note The deterministic version is usually prefered. + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief Compute ECDSA signature of a previously hashed message, + * deterministic version (RFC 6979). + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param md_alg MD algorithm used to hash the message + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief Verify ECDSA signature of a previously hashed message + * + * \param grp ECP group + * \param buf Message hash + * \param blen Length of buf + * \param Q Public key to use for verification + * \param r First integer of the signature + * \param s Second integer of the signature + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s); + +/** + * \brief Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * (Not thread-safe to use same context in multiple threads) + * + * \note The deterministice version (RFC 6979) is used if + * MBEDTLS_ECDSA_DETERMINISTIC is defined. + * + * \param ctx ECDSA context + * \param md_alg Algorithm that was used to hash the message + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * Deterministic version, RFC 6979. + * (Not thread-safe to use same context in multiple threads) + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in 2.0.0 + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param md_alg MD algorithm used to hash the message + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief Read and verify an ECDSA signature + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Size of hash + * \param sig Signature to read and verify + * \param slen Size of sig + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, + * MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than siglen, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ); + +/** + * \brief Generate an ECDSA keypair on the given curve + * + * \param ctx ECDSA context in which the keypair should be stored + * \param gid Group (elliptic curve) to use. One of the various + * MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Set an ECDSA context from an EC key pair + * + * \param ctx ECDSA context to set + * \param key EC key to use + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); + +/** + * \brief Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdsa.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecjpake.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecjpake.h new file mode 100644 index 0000000000..b7b61604d0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecjpake.h @@ -0,0 +1,238 @@ +/** + * \file ecjpake.h + * + * \brief Elliptic curve J-PAKE + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECJPAKE_H +#define MBEDTLS_ECJPAKE_H + +/* + * J-PAKE is a password-authenticated key exchange that allows deriving a + * strong shared secret from a (potentially low entropy) pre-shared + * passphrase, with forward secrecy and mutual authentication. + * https://en.wikipedia.org/wiki/Password_Authenticated_Key_Exchange_by_Juggling + * + * This file implements the Elliptic Curve variant of J-PAKE, + * as defined in Chapter 7.4 of the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + * + * As the J-PAKE algorithm is inherently symmetric, so is our API. + * Each party needs to send its first round message, in any order, to the + * other party, then each sends its second round message, in any order. + * The payloads are serialized in a way suitable for use in TLS, but could + * also be use outside TLS. + */ + +#include "ecp.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Roles in the EC J-PAKE exchange + */ +typedef enum { + MBEDTLS_ECJPAKE_CLIENT = 0, /**< Client */ + MBEDTLS_ECJPAKE_SERVER, /**< Server */ +} mbedtls_ecjpake_role; + +/** + * EC J-PAKE context structure. + * + * J-PAKE is a symmetric protocol, except for the identifiers used in + * Zero-Knowledge Proofs, and the serialization of the second message + * (KeyExchange) as defined by the Thread spec. + * + * In order to benefit from this symmetry, we choose a different naming + * convetion from the Thread v1.0 spec. Correspondance is indicated in the + * description as a pair C: client name, S: server name + */ +typedef struct +{ + const mbedtls_md_info_t *md_info; /**< Hash to use */ + mbedtls_ecp_group grp; /**< Elliptic curve */ + mbedtls_ecjpake_role role; /**< Are we client or server? */ + int point_format; /**< Format for point export */ + + mbedtls_ecp_point Xm1; /**< My public key 1 C: X1, S: X3 */ + mbedtls_ecp_point Xm2; /**< My public key 2 C: X2, S: X4 */ + mbedtls_ecp_point Xp1; /**< Peer public key 1 C: X3, S: X1 */ + mbedtls_ecp_point Xp2; /**< Peer public key 2 C: X4, S: X2 */ + mbedtls_ecp_point Xp; /**< Peer public key C: Xs, S: Xc */ + + mbedtls_mpi xm1; /**< My private key 1 C: x1, S: x3 */ + mbedtls_mpi xm2; /**< My private key 2 C: x2, S: x4 */ + + mbedtls_mpi s; /**< Pre-shared secret (passphrase) */ +} mbedtls_ecjpake_context; + +/** + * \brief Initialize a context + * (just makes it ready for setup() or free()). + * + * \param ctx context to initialize + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ); + +/** + * \brief Set up a context for use + * + * \note Currently the only values for hash/curve allowed by the + * standard are MBEDTLS_MD_SHA256/MBEDTLS_ECP_DP_SECP256R1. + * + * \param ctx context to set up + * \param role Our role: client or server + * \param hash hash function to use (MBEDTLS_MD_XXX) + * \param curve elliptic curve identifier (MBEDTLS_ECP_DP_XXX) + * \param secret pre-shared secret (passphrase) + * \param len length of the shared secret + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ); + +/* + * \brief Check if a context is ready for use + * + * \param ctx Context to check + * + * \return 0 if the context is ready for use, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ); + +/** + * \brief Generate and write the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes) + * + * \param ctx Context to use + * \param buf Pointer to extension contents + * \param len Extension length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Generate and write the second round message + * (TLS: contents of the Client/ServerKeyExchange) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the second round message + * (TLS: contents of the Client/ServerKeyExchange) + * + * \param ctx Context to use + * \param buf Pointer to the message + * \param len Message length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Derive the shared secret + * (TLS: Pre-Master Secret) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Free a context's content + * + * \param ctx context to free + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecjpake_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ecjpake.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecp.h new file mode 100644 index 0000000000..5246c789d3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ecp.h @@ -0,0 +1,669 @@ +/** + * \file ecp.h + * + * \brief Elliptic curves over GF(p) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECP_H +#define MBEDTLS_ECP_H + +#include "bignum.h" + +/* + * ECP error codes + */ +#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< Requested curve not available. */ +#define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */ +#define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as (ephemeral) key, failed. */ +#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */ +#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< Signature is valid but shorter than the user-supplied length. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain parameters (curve, subgroup and generator) identifiers. + * + * Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only well-known domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, + MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ + MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ + MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */ + MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ +} mbedtls_ecp_group_id; + +/** + * Number of supported curves (plus one for NONE). + * + * (Montgomery curves excluded for now.) + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/** + * Curve information for use by other modules + */ +typedef struct +{ + mbedtls_ecp_group_id grp_id; /*!< Internal identifier */ + uint16_t tls_id; /*!< TLS NamedCurve identifier */ + uint16_t bit_size; /*!< Curve size in bits */ + const char *name; /*!< Human-friendly name */ +} mbedtls_ecp_curve_info; + +/** + * \brief ECP point structure (jacobian coordinates) + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or Z == 1. (Other + * values of Z are used by internal functions only.) + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, X and Y are its standard (affine) coordinates. + */ +typedef struct +{ + mbedtls_mpi X; /*!< the point's X coordinate */ + mbedtls_mpi Y; /*!< the point's Y coordinate */ + mbedtls_mpi Z; /*!< the point's Z coordinate */ +} +mbedtls_ecp_point; + +/** + * \brief ECP group structure + * + * We consider two types of curves equations: + * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) + * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (Curve25519 + draft) + * In both cases, a generator G for a prime-order subgroup is fixed. In the + * short weierstrass, this subgroup is actually the whole curve, and its + * cardinal is denoted by N. + * + * In the case of Short Weierstrass curves, our code requires that N is an odd + * prime. (Use odd in mbedtls_ecp_mul() and prime in mbedtls_ecdsa_sign() for blinding.) + * + * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is + * the quantity actually used in the formulas. Also, nbits is not the size of N + * but the required size for private keys. + * + * If modp is NULL, reduction modulo P is done using a generic algorithm. + * Otherwise, it must point to a function that takes an mbedtls_mpi in the range + * 0..2^(2*pbits)-1 and transforms it in-place in an integer of little more + * than pbits, so that the integer may be efficiently brought in the 0..P-1 + * range by a few additions or substractions. It must return 0 on success and + * non-zero on failure. + */ +typedef struct +{ + mbedtls_ecp_group_id id; /*!< internal group identifier */ + mbedtls_mpi P; /*!< prime modulus of the base field */ + mbedtls_mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + mbedtls_mpi B; /*!< 1. B in the equation, or 2. unused */ + mbedtls_ecp_point G; /*!< generator of the (sub)group used */ + mbedtls_mpi N; /*!< 1. the order of G, or 2. unused */ + size_t pbits; /*!< number of bits in P */ + size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ + unsigned int h; /*!< internal: 1 if the constants are static */ + int (*modp)(mbedtls_mpi *); /*!< function for fast reduction mod P */ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< unused */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< unused */ + void *t_data; /*!< unused */ + mbedtls_ecp_point *T; /*!< pre-computed points for ecp_mul_comb() */ + size_t T_size; /*!< number for pre-computed points */ +} +mbedtls_ecp_group; + +/** + * \brief ECP key pair structure + * + * A generic key pair that could be used for ECDSA, fixed ECDH, etc. + * + * \note Members purposefully in the same order as struc mbedtls_ecdsa_context. + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_MAX_BITS) +/** + * Maximum size of the groups (that is, of N and P) + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#endif + +#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) +#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 ) + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: 6. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade memory for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * The cost is increasing EC peak memory usage by a factor roughly 2. + * + * Change this value to 0 to reduce peak memory usage. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/* \} name SECTION: Module settings */ + +/* + * Point formats, from RFC 4492's enum ECPointFormat + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format */ + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< ECCurveType's named_curve */ + +/** + * \brief Get the list of supported curves in order of preferrence + * (full information) + * + * \return A statically allocated array, the last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief Get the list of supported curves in order of preferrence + * (grp_id only) + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief Get curve information from an internal group identifier + * + * \param grp_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief Get curve information from a TLS NamedCurve value + * + * \param tls_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief Get curve information from a human-readable name + * + * \param name The name + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief Initialize a point (as zero) + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief Initialize a group (to something meaningless) + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief Initialize a key pair (as an invalid one) + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief Free the components of a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief Free the components of an ECP group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief Free the components of a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +/** + * \brief Copy the contents of point Q into P + * + * \param P Destination point + * \param Q Source point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief Copy the contents of a group object + * + * \param dst Destination group + * \param src Source group + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); + +/** + * \brief Set a point to zero + * + * \param pt Destination point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Tell if a point is zero + * + * \param pt Point to test + * + * \return 1 if point is zero, 0 otherwise + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Compare two points + * + * \note This assumes the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P First point to compare + * \param Q Second point to compare + * + * \return 0 if the points are equal, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief Import a non-zero point from two ASCII strings + * + * \param P Destination point + * \param radix Input numeric base + * \param x First affine coordinate as a null-terminated string + * \param y Second affine coordinate as a null-terminated string + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief Export a point into unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to export + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param olen Length of the actual output + * \param buf Output buffer + * \param buflen Length of the output buffer + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ); + +/** + * \brief Import a point from unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to import + * \param buf Input buffer + * \param ilen Actual length of input + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + * \note This function does NOT check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() for + * that. + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief Import a point from a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Destination point + * \param buf $(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after the ECPoint on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief Export a point as a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Point to export + * \param format Export format + * \param olen length of data written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Set a group using well-known domain parameters + * + * \param grp Destination group + * \param index Index in the list of well-known domain parameters + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups + * + * \note Index should be a value of RFC 4492's enum NamedCurve, + * usually in the form of a MBEDTLS_ECP_DP_XXX macro. + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id index ); + +/** + * \brief Set a group from a TLS ECParameters record + * + * \param grp Destination group + * \param buf &(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after ECParameters on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); + +/** + * \brief Write the TLS ECParameters record for a group + * + * \param grp ECP group used + * \param olen Number of bytes actually written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Multiplication by an integer: R = m * P + * (Not thread-safe to use same group in multiple threads) + * + * \note In order to prevent timing attacks, this function + * executes the exact same sequence of (base field) + * operations for any valid m. It avoids any if-branch or + * array index depending on the value of m. + * + * \note If f_rng is not NULL, it is used to randomize intermediate + * results in order to prevent potential timing attacks + * targeting these results. It is recommended to always + * provide a non-NULL f_rng (the overhead is negligible). + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply + * \param P Point to multiply + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m is not a valid privkey + * or P is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Multiplication and addition of two points by integers: + * R = m * P + n * Q + * (Not thread-safe to use same group in multiple threads) + * + * \note In contrast to mbedtls_ecp_mul(), this function does not guarantee + * a constant execution flow and timing. + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply P + * \param P Point to multiply by m + * \param n Integer by which to multiply Q + * \param Q Point to be multiplied by n + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m or n is not a valid privkey + * or P or Q is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); + +/** + * \brief Check that a point is a valid public key on this curve + * + * \param grp Curve/group the point should belong to + * \param pt Point to check + * + * \return 0 if point is a valid public key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note This function only checks the point is non-zero, has valid + * coordinates and lies on the curve, but not that it is + * indeed a multiple of G. This is additional check is more + * expensive, isn't required by standards, and shouldn't be + * necessary if the group used has a small cofactor. In + * particular, it is useless for the NIST groups which all + * have a cofactor of 1. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); + +/** + * \brief Check that an mbedtls_mpi is a valid private key for this curve + * + * \param grp Group used + * \param d Integer to check + * + * \return 0 if point is a valid private key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); + +/** + * \brief Generate a keypair with configurable base point + * + * \param grp ECP group + * \param G Chosen base point + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp ECP group + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp_id ECP group identifier + * \param key Destination keypair + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check a public-private key pair + * + * \param pub Keypair structure holding a public key + * \param prv Keypair structure holding a private (plus public) key + * + * \return 0 if successful (keys are valid and match), or + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA, or + * a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX code. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecp_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ecp.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy.h new file mode 100644 index 0000000000..00de9a6e5e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy.h @@ -0,0 +1,252 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_H +#define MBEDTLS_ENTROPY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#include "sha512.h" +#define MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#else +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#include "sha256.h" +#endif +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#if defined(MBEDTLS_HAVEGE_C) +#include "havege.h" +#endif + +#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D /**< No strong sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F /**< Read/write error in file. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ENTROPY_MAX_SOURCES) +#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#endif + +#if !defined(MBEDTLS_ENTROPY_MAX_GATHER) +#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif + +/* \} name SECTION: Module settings */ + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) +#define MBEDTLS_ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ +#else +#define MBEDTLS_ENTROPY_BLOCK_SIZE 32 /**< Block size of entropy accumulator (SHA-256) */ +#endif + +#define MBEDTLS_ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define MBEDTLS_ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_MAX_SOURCES + +#define MBEDTLS_ENTROPY_SOURCE_STRONG 1 /**< Entropy source is strong */ +#define MBEDTLS_ENTROPY_SOURCE_WEAK 0 /**< Entropy source is weak */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, size_t len, + size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct +{ + mbedtls_entropy_f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received in bytes */ + size_t threshold; /**< Minimum bytes required before release */ + int strong; /**< Is the source strong? */ +} +mbedtls_entropy_source_state; + +/** + * \brief Entropy context structure + */ +typedef struct +{ +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_context accumulator; +#else + mbedtls_sha256_context accumulator; +#endif + int source_count; + mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES]; +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state havege_data; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +} +mbedtls_entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ); + +/** + * \brief Free the data in the context + * + * \param ctx Entropy context to free + */ +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with mbedtls_entropy_func() ) (in bytes) + * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or + * MBEDTSL_ENTROPY_SOURCE_WEAK. + * At least one strong source needs to be added. + * Weaker sources (such as the cycle counter) can be used as + * a complement. + * + * \return 0 if successful or MBEDTLS_ERR_ENTROPY_MAX_SOURCES + */ +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator + * (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Number of bytes desired, must be at most MBEDTLS_ENTROPY_BLOCK_SIZE + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than MBEDTLS_ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy_poll.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy_poll.h new file mode 100644 index 0000000000..dc11911341 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/entropy_poll.h @@ -0,0 +1,89 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_POLL_H +#define MBEDTLS_ENTROPY_POLL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources, in bytes + */ +#define MBEDTLS_ENTROPY_MIN_PLATFORM 32 /**< Minimum for platform source */ +#define MBEDTLS_ENTROPY_MIN_HAVEGE 32 /**< Minimum for HAVEGE */ +#define MBEDTLS_ENTROPY_MIN_HARDCLOCK 4 /**< Minimum for mbedtls_timing_hardclock() */ +#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Minimum for the hardware source */ + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_TIMING_C) +/** + * \brief mbedtls_timing_hardclock-based entropy poll callback + */ +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Entropy poll callback for a hardware source + * + * \warning This is not provided by mbed TLS! + * See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h. + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_hardware_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/error.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/error.h new file mode 100644 index 0000000000..5e549f6b6a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/error.h @@ -0,0 +1,107 @@ +/** + * \file error.h + * + * \brief Error to string translation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ERROR_H +#define MBEDTLS_ERROR_H + +#include + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bits signed integers to support all platforms (-0x0001 - -0x7FFF). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Unused (sign bit) + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 7 bits - Low level module errors + * + * For historical reasons, low-level error codes are divided in even and odd, + * even codes were assigned first, and -1 is reserved for other errors. + * + * Low-level module errors (0x0002-0x007E, 0x0003-0x007F) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * GCM 2 0x0012-0x0014 + * BLOWFISH 2 0x0016-0x0018 + * THREADING 3 0x001A-0x001E + * AES 2 0x0020-0x0022 + * CAMELLIA 2 0x0024-0x0026 + * XTEA 1 0x0028-0x0028 + * BASE64 2 0x002A-0x002C + * OID 1 0x002E-0x002E 0x000B-0x000B + * PADLOCK 1 0x0030-0x0030 + * DES 1 0x0032-0x0032 + * CTR_DBRG 4 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 0x003D-0x003F + * NET 11 0x0042-0x0052 0x0043-0x0045 + * ASN1 7 0x0060-0x006C + * PBKDF2 1 0x007C-0x007C + * HMAC_DRBG 4 0x0003-0x0009 + * CCM 2 0x000D-0x000F + * + * High-level module nr (3 bits - 0x0...-0x7...) + * Name ID Nr of Errors + * PEM 1 9 + * PKCS#12 1 4 (Started from top) + * X509 2 19 + * PKCS5 2 4 (Started from top) + * DHM 3 9 + * PK 3 14 (Started from top) + * RSA 4 9 + * ECP 4 8 (Started from top) + * MD 5 4 + * CIPHER 6 6 + * SSL 6 17 (Started from top) + * SSL 7 31 + * + * Module dependent error code (5 bits 0x.00.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a mbed TLS error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void mbedtls_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/gcm.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/gcm.h new file mode 100644 index 0000000000..6743ac9a5f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/gcm.h @@ -0,0 +1,220 @@ +/** + * \file gcm.h + * + * \brief Galois/Counter mode for 128-bit block ciphers + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_GCM_H +#define MBEDTLS_GCM_H + +#include "cipher.h" + +#include + +#define MBEDTLS_GCM_ENCRYPT 1 +#define MBEDTLS_GCM_DECRYPT 0 + +#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ +#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief GCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx;/*!< cipher context used */ + uint64_t HL[16]; /*!< Precalculated HTable */ + uint64_t HH[16]; /*!< Precalculated HTable */ + uint64_t len; /*!< Total data length */ + uint64_t add_len; /*!< Total add length */ + unsigned char base_ectr[16];/*!< First ECTR for tag */ + unsigned char y[16]; /*!< Y working value */ + unsigned char buf[16]; /*!< buf working value */ + int mode; /*!< Encrypt or Decrypt */ +} +mbedtls_gcm_context; + +/** + * \brief Initialize GCM context (just makes references valid) + * Makes the context ready for mbedtls_gcm_setkey() or + * mbedtls_gcm_free(). + * + * \param ctx GCM context to initialize + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); + +/** + * \brief GCM initialization (encryption) + * + * \param ctx GCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief GCM buffer encryption/decryption using a block cipher + * + * \note On encryption, the output buffer can be the same as the input buffer. + * On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag_len length of the tag to generate + * \param tag buffer for holding the tag + * + * \return 0 if successful + */ +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ); + +/** + * \brief GCM buffer authenticated decryption using a block cipher + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_GCM_AUTH_FAILED if tag does not match + */ +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM stream start function + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data (or NULL if length is 0) + * \param add_len length of additional data + * + * \return 0 if successful + */ +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ); + +/** + * \brief Generic GCM update function. Encrypts/decrypts using the + * given GCM context. Expects input to be a multiple of 16 + * bytes! Only the last call before mbedtls_gcm_finish() can be less + * than 16 bytes! + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM finalisation function. Wraps up the GCM stream + * and generates the tag. The tag can have a maximum length of + * 16 bytes. + * + * \param ctx GCM context + * \param tag buffer for holding the tag (may be NULL if tag_len is 0) + * \param tag_len length of the tag to generate + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ); + +/** + * \brief Free a GCM context and underlying cipher sub-context + * + * \param ctx GCM context to free + */ +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_gcm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* gcm.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/havege.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/havege.h new file mode 100644 index 0000000000..dac5d31138 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/havege.h @@ -0,0 +1,74 @@ +/** + * \file havege.h + * + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HAVEGE_H +#define MBEDTLS_HAVEGE_H + +#include + +#define MBEDTLS_HAVEGE_COLLECT_SIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + int PT1, PT2, offset[2]; + int pool[MBEDTLS_HAVEGE_COLLECT_SIZE]; + int WALK[8192]; +} +mbedtls_havege_state; + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ); + +/** + * \brief Clear HAVEGE state + * + * \param hs HAVEGE state to be cleared + */ +void mbedtls_havege_free( mbedtls_havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param p_rng A HAVEGE state + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 + */ +int mbedtls_havege_random( void *p_rng, unsigned char *output, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/hmac_drbg.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/hmac_drbg.h new file mode 100644 index 0000000000..e010558028 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/hmac_drbg.h @@ -0,0 +1,299 @@ +/** + * \file hmac_drbg.h + * + * \brief HMAC_DRBG (NIST SP 800-90A) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HMAC_DRBG_H +#define MBEDTLS_HMAC_DRBG_H + +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/* + * Error codes + */ +#define MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG -0x0003 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG -0x0005 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR -0x0007 /**< Read/write error in file. */ +#define MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED -0x0009 /**< The entropy source failed. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) +#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_REQUEST) +#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_HMAC_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_HMAC_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HMAC_DRBG context. + */ +typedef struct +{ + /* Working state: the key K is not stored explicitely, + * but is implied by the HMAC context */ + mbedtls_md_context_t md_ctx; /*!< HMAC context (inc. K) */ + unsigned char V[MBEDTLS_MD_MAX_SIZE]; /*!< V in the spec */ + int reseed_counter; /*!< reseed counter */ + + /* Administrative state */ + size_t entropy_len; /*!< entropy bytes grabbed on each (re)seed */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + int reseed_interval; /*!< reseed interval */ + + /* Callbacks */ + int (*f_entropy)(void *, unsigned char *, size_t); /*!< entropy function */ + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_hmac_drbg_context; + +/** + * \brief HMAC_DRBG context initialization + * Makes the context ready for mbedtls_hmac_drbg_seed(), + * mbedtls_hmac_drbg_seed_buf() or + * mbedtls_hmac_drbg_free(). + * + * \param ctx HMAC_DRBG context to be initialized + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ); + +/** + * \brief HMAC_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * \param ctx HMAC_DRBG context to be seeded + * \param md_info MD algorithm to use for HMAC_DRBG + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \note The "security strength" as defined by NIST is set to: + * 128 bits if md_alg is SHA-1, + * 192 bits if md_alg is SHA-224, + * 256 bits if md_alg is SHA-256 or higher. + * Note that SHA-256 is just as efficient as SHA-224. + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Initilisation of simpified HMAC_DRBG (never reseeds). + * (For use with deterministic ECDSA.) + * + * \param ctx HMAC_DRBG context to be initialised + * \param md_info MD algorithm to use for HMAC_DRBG + * \param data Concatenation of entropy string and additional data + * \param data_len Length of data in bytes + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED. + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx HMAC_DRBG context + * \param resistance MBEDTLS_HMAC_DRBG_PR_ON or MBEDTLS_HMAC_DRBG_PR_OFF + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each reseed + * (Default: given by the security strength, which + * depends on the hash used, see \c mbedtls_hmac_drbg_init() ) + * + * \param ctx HMAC_DRBG context + * \param len Amount of entropy to grab, in bytes + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) + * + * \param ctx HMAC_DRBG context + * \param interval Reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, + int interval ); + +/** + * \brief HMAC_DRBG update state + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief HMAC_DRBG reseeding (extracts data from entropy source) + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief HMAC_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (can be NULL) + * \param add_len Length of additional data (can be 0) + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG, or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG. + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, + size_t add_len ); + +/** + * \brief HMAC_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param out_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ); + +/** + * \brief Free an HMAC_DRBG context + * + * \param ctx HMAC_DRBG context to free. + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG + */ +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_hmac_drbg_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* hmac_drbg.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/mbedtls_debug.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/mbedtls_debug.h new file mode 100644 index 0000000000..30b902ea9a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/mbedtls_debug.h @@ -0,0 +1,13 @@ +#ifndef _MBEDTLS_DEBUG_H_ +#define _MBEDTLS_DEBUG_H_ + +#include "osapi.h" + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) os_printf args; +#define MBEDTLS_SSL_DEBUG_RET( level, ... ) os_printf (__VA_ARGS__); +#define MBEDTLS_SSL_DEBUG_BUF( level, ... ) os_printf (__VA_ARGS__); +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md.h new file mode 100644 index 0000000000..703e781101 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md.h @@ -0,0 +1,353 @@ +/** + * \file md.h + * + * \brief Generic message digest wrapper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_H +#define MBEDTLS_MD_H + +#include + +#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_MD_NONE=0, + MBEDTLS_MD_MD2, + MBEDTLS_MD_MD4, + MBEDTLS_MD_MD5, + MBEDTLS_MD_SHA1, + MBEDTLS_MD_SHA224, + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_SHA512, + MBEDTLS_MD_RIPEMD160, +} mbedtls_md_type_t; + +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */ +#else +#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */ +#endif + +/** + * Opaque struct defined in md_internal.h + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const mbedtls_md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; + + /** HMAC part of the context */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief Initialize a md_context (as NONE) + * This should always be called first. + * Prepares the context for mbedtls_md_setup() or mbedtls_md_free(). + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief Free and clear the internal structures of ctx. + * Can be called at any time after mbedtls_md_init(). + * Mandatory once mbedtls_md_setup() has been called. + */ +void mbedtls_md_free( mbedtls_md_context_t *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \deprecated Superseded by mbedtls_md_setup() in 2.0.0 + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * \param hmac 0 to save some memory if HMAC will not be used, + * non-zero is HMAC is going to be used with this context. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief Clone the state of an MD context + * + * \note The two contexts must have been setup to the same type + * (cloning from SHA-256 to SHA-512 make no sense). + * + * \warning Only clones the MD state, not the HMAC state! (for now) + * + * \param dst The destination context + * \param src The context to be cloned + * + * \return \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output in bytes. + */ +int mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief Prepare the context to digest a new message. + * Generally called after mbedtls_md_setup() or mbedtls_md_finish(). + * Followed by mbedtls_md_update(). + * + * \param ctx generic message digest context. + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * Called between mbedtls_md_starts() and mbedtls_md_finish(). + * May be called repeatedly. + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * Called after mbedtls_md_update(). + * Usually followed by mbedtls_md_free() or mbedtls_md_starts(). + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, + * MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed, + * MBEDTLS_ERR_MD_BAD_INPUT_DATA if md_info was NULL. + */ +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, + unsigned char *output ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Set HMAC key and prepare to authenticate a new message. + * Usually called after mbedtls_md_setup() or mbedtls_md_hmac_finish(). + * + * \param ctx HMAC context + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief Generic HMAC process buffer. + * Called between mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * and mbedtls_md_hmac_finish(). + * May be called repeatedly. + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief Output HMAC. + * Called after mbedtls_md_hmac_update(). + * Usually followed my mbedtls_md_hmac_reset(), mbedtls_md_hmac_starts(), + * or mbedtls_md_free(). + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_md_hmac_finish() and before mbedtls_md_hmac_update(). + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +/* Internal use */ +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md2.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md2.h new file mode 100644 index 0000000000..0f93fbf427 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md2.h @@ -0,0 +1,136 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD2_H +#define MBEDTLS_MD2_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if !defined(MBEDTLS_MD2_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + size_t left; /*!< amount of data in buffer */ +} +mbedtls_md2_context; + +/** + * \brief Initialize MD2 context + * + * \param ctx MD2 context to be initialized + */ +void mbedtls_md2_init( mbedtls_md2_context *ctx ); + +/** + * \brief Clear MD2 context + * + * \param ctx MD2 context to be cleared + */ +void mbedtls_md2_free( mbedtls_md2_context *ctx ); + +/** + * \brief Clone (the state of) an MD2 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ); + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md2_starts( mbedtls_md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD2_ALT */ +#include "md2_alt.h" +#endif /* MBEDTLS_MD2_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md2_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md2_process( mbedtls_md2_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md2.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md4.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md4.h new file mode 100644 index 0000000000..45214d41d9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md4.h @@ -0,0 +1,136 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD4_H +#define MBEDTLS_MD4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_MD4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md4_context; + +/** + * \brief Initialize MD4 context + * + * \param ctx MD4 context to be initialized + */ +void mbedtls_md4_init( mbedtls_md4_context *ctx ); + +/** + * \brief Clear MD4 context + * + * \param ctx MD4 context to be cleared + */ +void mbedtls_md4_free( mbedtls_md4_context *ctx ); + +/** + * \brief Clone (the state of) an MD4 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ); + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md4_starts( mbedtls_md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD4_ALT */ +#include "md4_alt.h" +#endif /* MBEDTLS_MD4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md4_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md4_process( mbedtls_md4_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md4.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md5.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md5.h new file mode 100644 index 0000000000..5a64061aa0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md5.h @@ -0,0 +1,136 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD5_H +#define MBEDTLS_MD5_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md5_context; + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + */ +void mbedtls_md5_init( mbedtls_md5_context *ctx ); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + */ +void mbedtls_md5_free( mbedtls_md5_context *ctx ); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md5_starts( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ); + +/* Internal use */ +void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md5.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md_internal.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md_internal.h new file mode 100644 index 0000000000..e2441bbc49 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/md_internal.h @@ -0,0 +1,114 @@ +/** + * \file md_internal.h + * + * \brief Message digest wrappers. + * + * \warning This in an internal header. Do not include directly. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_WRAP_H +#define MBEDTLS_MD_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Message digest information. + * Allows message digest functions to be called in a generic way. + */ +struct mbedtls_md_info_t +{ + /** Digest identifier */ + mbedtls_md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function in bytes */ + int size; + + /** Block length of the digest function in bytes */ + int block_size; + + /** Digest initialisation function */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Clone state from a context */ + void (*clone_func)( void *dst, const void *src ); + + /** Internal use only */ + void (*process_func)( void *ctx, const unsigned char *input ); +}; + +#if defined(MBEDTLS_MD2_C) +extern const mbedtls_md_info_t mbedtls_md2_info; +#endif +#if defined(MBEDTLS_MD4_C) +extern const mbedtls_md_info_t mbedtls_md4_info; +#endif +#if defined(MBEDTLS_MD5_C) +extern const mbedtls_md_info_t mbedtls_md5_info; +#endif +#if defined(MBEDTLS_RIPEMD160_C) +extern const mbedtls_md_info_t mbedtls_ripemd160_info; +#endif +#if defined(MBEDTLS_SHA1_C) +extern const mbedtls_md_info_t mbedtls_sha1_info; +#endif +#if defined(MBEDTLS_SHA256_C) +extern const mbedtls_md_info_t mbedtls_sha224_info; +extern const mbedtls_md_info_t mbedtls_sha256_info; +#endif +#if defined(MBEDTLS_SHA512_C) +extern const mbedtls_md_info_t mbedtls_sha384_info; +extern const mbedtls_md_info_t mbedtls_sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_WRAP_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/memory_buffer_alloc.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/memory_buffer_alloc.h new file mode 100644 index 0000000000..661bc08dcc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/memory_buffer_alloc.h @@ -0,0 +1,146 @@ +/** + * \file memory_buffer_alloc.h + * + * \brief Buffer-based memory allocator + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define MBEDTLS_MEMORY_BUFFER_ALLOC_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_MEMORY_ALIGN_MULTIPLE) +#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_MEMORY_VERIFY_NONE 0 +#define MBEDTLS_MEMORY_VERIFY_ALLOC (1 << 0) +#define MBEDTLS_MEMORY_VERIFY_FREE (1 << 1) +#define MBEDTLS_MEMORY_VERIFY_ALWAYS (MBEDTLS_MEMORY_VERIFY_ALLOC | MBEDTLS_MEMORY_VERIFY_FREE) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize use of stack-based memory allocator. + * The stack-based allocator does memory management inside the + * presented buffer and does not call calloc() and free(). + * It sets the global mbedtls_calloc() and mbedtls_free() pointers + * to its own functions. + * (Provided mbedtls_calloc() and mbedtls_free() are thread-safe if + * MBEDTLS_THREADING_C is defined) + * + * \note This code is not optimized and provides a straight-forward + * implementation of a stack-based memory allocator. + * + * \param buf buffer to use as heap + * \param len size of the buffer + */ +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ); + +/** + * \brief Free the mutex for thread-safety and clear remaining memory + */ +void mbedtls_memory_buffer_alloc_free( void ); + +/** + * \brief Determine when the allocator should automatically verify the state + * of the entire chain of headers / meta-data. + * (Default: MBEDTLS_MEMORY_VERIFY_NONE) + * + * \param verify One of MBEDTLS_MEMORY_VERIFY_NONE, MBEDTLS_MEMORY_VERIFY_ALLOC, + * MBEDTLS_MEMORY_VERIFY_FREE or MBEDTLS_MEMORY_VERIFY_ALWAYS + */ +void mbedtls_memory_buffer_set_verify( int verify ); + +#if defined(MBEDTLS_MEMORY_DEBUG) +/** + * \brief Print out the status of the allocated memory (primarily for use + * after a program should have de-allocated all memory) + * Prints out a list of 'still allocated' blocks and their stack + * trace if MBEDTLS_MEMORY_BACKTRACE is defined. + */ +void mbedtls_memory_buffer_alloc_status( void ); + +/** + * \brief Get the peak heap usage so far + * + * \param max_used Peak number of bytes reauested by the application + * \param max_blocks Peak number of blocks reauested by the application + */ +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ); + +/** + * \brief Reset peak statistics + */ +void mbedtls_memory_buffer_alloc_max_reset( void ); + +/** + * \brief Get the current heap usage + * + * \param cur_used Number of bytes reauested by the application + * \param cur_blocks Number of blocks reauested by the application + */ +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ); +#endif /* MBEDTLS_MEMORY_DEBUG */ + +/** + * \brief Verifies that all headers in the memory buffer are correct + * and contain sane values. Helps debug buffer-overflow errors. + * + * Prints out first failure if MBEDTLS_MEMORY_DEBUG is defined. + * Prints out full header information if MBEDTLS_MEMORY_DEBUG + * is defined. (Includes stack trace information for each block if + * MBEDTLS_MEMORY_BACKTRACE is defined as well). + * + * \return 0 if verified, 1 otherwise + */ +int mbedtls_memory_buffer_alloc_verify( void ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_memory_buffer_alloc_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* memory_buffer_alloc.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/net.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/net.h new file mode 100644 index 0000000000..8c6534cfb8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/net.h @@ -0,0 +1,225 @@ +/** + * \file net.h + * + * \brief Network communication functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_NET_H +#define MBEDTLS_NET_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#include +#include + +#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /**< Failed to get an IP address for the given hostname. */ +#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /**< Buffer is too small to hold the data. */ +#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /**< The context is invalid, eg because it was free()ed. */ + +#define MBEDTLS_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ + +#define MBEDTLS_NET_PROTO_TCP 0 /**< The TCP transport protocol */ +#define MBEDTLS_NET_PROTO_UDP 1 /**< The UDP transport protocol */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wrapper type for sockets. + * + * Currently backed by just a file descriptor, but might be more in the future + * (eg two file descriptors for combined IPv4 + IPv6 support, or additional + * structures for hand-made UDP demultiplexing). + */ +typedef struct +{ + int fd; /**< The underlying file descriptor */ +} +mbedtls_net_context; + +/** + * \brief Initialize a context + * Just makes the context ready to be used or freed safely. + * + * \param ctx Context to initialize + */ +void mbedtls_net_init( mbedtls_net_context *ctx ); + +/** + * \brief Initiate a connection with host:port in the given protocol + * + * \param ctx Socket to use + * \param host Host to connect to + * \param port Port to connect to + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_UNKNOWN_HOST, + * MBEDTLS_ERR_NET_CONNECT_FAILED + * + * \note Sets the socket in connected mode even with UDP. + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ); + +/** + * \brief Create a receiving socket on bind_ip:port in the chosen + * protocol. If bind_ip == NULL, all interfaces are bound. + * + * \param ctx Socket to use + * \param bind_ip IP to bind to, can be NULL + * \param port Port number to use + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_BIND_FAILED, + * MBEDTLS_ERR_NET_LISTEN_FAILED + * + * \note Regardless of the protocol, opens the sockets and binds it. + * In addition, make the socket listening if protocol is TCP. + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ); + +/** + * \brief Accept a connection from a remote client + * + * \param bind_ctx Relevant socket + * \param client_ctx Will contain the connected client socket + * \param client_ip Will contain the client IP address + * \param buf_size Size of the client_ip buffer + * \param ip_len Will receive the size of the client IP written + * + * \return 0 if successful, or + * MBEDTLS_ERR_NET_ACCEPT_FAILED, or + * MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small, + * MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to + * non-blocking and accept() would block. + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ); + +/** + * \brief Set the socket blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ); + +/** + * \brief Set the socket non-blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ); + +/** + * \brief Portable usleep helper + * + * \param usec Amount of microseconds to sleep + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void mbedtls_net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * + * \return the number of bytes received, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_READ indicates read() would block. + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ); + +/** + * \brief Write at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to read from + * \param len The length of the buffer + * + * \return the number of bytes sent, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_WRITE indicates write() would block. + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ); + +/** + * \brief Read at most 'len' characters, blocking for at most + * 'timeout' seconds. If no error occurs, the actual amount + * read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * \param timeout Maximum number of milliseconds to wait for data + * 0 means no timeout (wait forever) + * + * \return the number of bytes received, + * or a non-zero error code: + * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note This function will block (until data becomes available or + * timeout is reached) even if the socket is set to + * non-blocking. Handling timeouts with non-blocking reads + * requires a different strategy. + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ); + +/** + * \brief Gracefully shutdown the connection and free associated data + * + * \param ctx The context to free + */ +void mbedtls_net_free( mbedtls_net_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* net.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/oid.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/oid.h new file mode 100644 index 0000000000..fcecdafdca --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/oid.h @@ -0,0 +1,570 @@ +/** + * \file oid.h + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_OID_H +#define MBEDTLS_OID_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#include + +#if defined(MBEDTLS_CIPHER_C) +#include "cipher.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "md.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "x509.h" +#endif + +#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */ +#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */ + +/* + * Top level OID tuples + */ +#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */ +#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */ +#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */ +#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */ + +/* + * ISO Member bodies OID parts + */ +#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */ +#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */ +#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */ +#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */ +#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_ANSI_X9_62 + +/* + * ISO Identified organization OID parts + */ +#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */ +#define MBEDTLS_OID_ORG_OIW "\x0e" +#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03" +#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02" +#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a" +#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */ +#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM +#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */ +#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST + +/* + * ISO ITU OID parts + */ +#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */ +#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */ + +#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */ +#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */ + +#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */ +#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */ + +/* ISO arc for standard certificate and CRL extensions */ +#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\x05\x05\x07" + +/* + * Arc for standard naming attributes + */ +#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */ +#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */ +#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */ +#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */ +#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */ +#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */ +#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */ +#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */ +#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */ +#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */ +#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */ +#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */ +#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */ +#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */ +#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */ +#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */ +#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */ +#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */ + +#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */ + +/* + * OIDs for standard certificate extensions + */ +#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * Netscape certificate extensions + */ +#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01" +#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01" +#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02" +#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03" +#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04" +#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07" +#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08" +#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C" +#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D" +#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02" +#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05" + +/* + * OIDs for CRL extensions + */ +#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10" +#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +/* + * PKCS definition OIDs + */ + +#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */ +#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */ +#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */ +#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */ +#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */ + +/* + * PKCS#1 OIDs + */ +#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */ +#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */ +#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */ +#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */ +#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */ +#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */ +#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */ +#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */ +#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */ + +#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */ + +/* RFC 4055 */ +#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */ +#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */ + +/* + * Digest algorithms + */ +#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_GOV "\x03\x04\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_GOV "\x03\x04\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_GOV "\x03\x04\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_GOV "\x03\x04\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ + +#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ + +/* + * Encryption algorithms + */ +#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */ +#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */ + +/* + * PKCS#5 OIDs + */ +#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */ +#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */ +#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */ + +/* + * PKCS#5 PBES1 algorithms + */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */ + +/* + * PKCS#8 OIDs + */ +#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */ + +/* + * PKCS#12 PBE OIDs + */ +#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */ + +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */ + +/* + * EC key algorithms from RFC 5480 + */ + +/* id-ecPublicKey OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */ +#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01" + +/* id-ecDH OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) + * schemes(1) ecdh(12) } */ +#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c" + +/* + * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + */ + +/* secp192r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */ +#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01" + +/* secp224r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 33 } */ +#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21" + +/* secp256r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */ +#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07" + +/* secp384r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 34 } */ +#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22" + +/* secp521r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 35 } */ +#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23" + +/* secp192k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 31 } */ +#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f" + +/* secp224k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 32 } */ +#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20" + +/* secp256k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 10 } */ +#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a" + +/* RFC 5639 4.1 + * ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1) + * identified-organization(3) teletrust(36) algorithm(3) signature- + * algorithm(3) ecSign(2) 8} + * ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1} + * versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */ +#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01" + +/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */ +#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07" + +/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */ +#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B" + +/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */ +#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D" + +/* + * SEC1 C.1 + * + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + * id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)} + */ +#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01" +#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01" + +/* + * ECDSA signature identifiers, from RFC 5480 + */ +#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */ +#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */ + +/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01" + +/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01" + +/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 2 } */ +#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02" + +/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 3 } */ +#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03" + +/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 4 } */ +#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Base OID descriptor structure + */ +typedef struct { + const char *asn1; /*!< OID ASN.1 representation */ + size_t asn1_len; /*!< length of asn1 */ + const char *name; /*!< official name (e.g. from RFC) */ + const char *description; /*!< human friendly description */ +} mbedtls_oid_descriptor_t; + +/** + * \brief Translate an ASN.1 OID into its numeric representation + * (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549") + * + * \param buf buffer to put representation in + * \param size size of the buffer + * \param oid OID to translate + * + * \return Length of the string written (excluding final NULL) or + * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error + */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid ); + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/** + * \brief Translate an X.509 extension OID into local values + * + * \param oid OID to use + * \param ext_type place to store the extension type + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ); +#endif + +/** + * \brief Translate an X.509 attribute type OID into the short name + * (e.g. the OID for an X520 Common Name into "CN") + * + * \param oid OID to use + * \param short_name place to store the string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name ); + +/** + * \brief Translate PublicKeyAlgorithm OID into pk_type + * + * \param oid OID to use + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate pk_type into PublicKeyAlgorithm OID + * + * \param pk_alg Public key type to look for + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg, + const char **oid, size_t *olen ); + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Translate NamedCurve OID into an EC group identifier + * + * \param oid OID to use + * \param grp_id place to store group id + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id ); + +/** + * \brief Translate EC group identifier into NamedCurve OID + * + * \param grp_id EC group identifier + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id, + const char **oid, size_t *olen ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) +/** + * \brief Translate SignatureAlgorithm OID into md_type and pk_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate SignatureAlgorithm OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type and pk_type into SignatureAlgorithm OID + * + * \param md_alg message digest algorithm + * \param pk_alg public key algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const char **oid, size_t *olen ); + +/** + * \brief Translate hash algorithm OID into md_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg ); +#endif /* MBEDTLS_MD_C */ + +/** + * \brief Translate Extended Key Usage OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type into hash algorithm OID + * + * \param md_alg message digest algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_C) +/** + * \brief Translate encryption algorithm OID into cipher_type + * + * \param oid OID to use + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_PKCS12_C) +/** + * \brief Translate PKCS#12 PBE algorithm OID into md_type and + * cipher_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg, + mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_PKCS12_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* oid.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/padlock.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/padlock.h new file mode 100644 index 0000000000..2045a5ab64 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/padlock.h @@ -0,0 +1,107 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some + * processors + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PADLOCK_H +#define MBEDTLS_PADLOCK_H + +#include "aes.h" + +#define MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define MBEDTLS_HAVE_ASAN +#endif +#endif + +/* Some versions of ASan result in errors about not enough registers */ +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) && \ + !defined(MBEDTLS_HAVE_ASAN) + +#ifndef MBEDTLS_HAVE_X86 +#define MBEDTLS_HAVE_X86 +#endif + +#include + +#define MBEDTLS_PADLOCK_RNG 0x000C +#define MBEDTLS_PADLOCK_ACE 0x00C0 +#define MBEDTLS_PADLOCK_PHE 0x0C00 +#define MBEDTLS_PADLOCK_PMM 0x3000 + +#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \param feature The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_padlock_has_support( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pem.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pem.h new file mode 100644 index 0000000000..54dc02d7cd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pem.h @@ -0,0 +1,129 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PEM_H +#define MBEDTLS_PEM_H + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT -0x1080 /**< No PEM header or footer found. */ +#define MBEDTLS_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define MBEDTLS_ERR_PEM_ALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define MBEDTLS_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +#define MBEDTLS_ERR_PEM_BAD_INPUT_DATA -0x1480 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/** + * \brief PEM context structure + */ +typedef struct +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +mbedtls_pem_context; + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void mbedtls_pem_init( mbedtls_pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in (must be nul-terminated) + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used (set after header is + * correctly read, so unless you get + * MBEDTLS_ERR_PEM_BAD_INPUT_DATA or + * MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is + * the length to skip) + * + * \note Attempts to check password correctness by verifying if + * the decrypted text starts with an ASN.1 sequence of + * appropriate length + * + * \return 0 on success, or a specific PEM error code + */ +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void mbedtls_pem_free( mbedtls_pem_context *ctx ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a buffer of PEM information from a DER encoded + * buffer. + * + * \param header header string to write + * \param footer footer string to write + * \param der_data DER data to write + * \param der_len length of the DER data + * \param buf buffer to write to + * \param buf_len length of output buffer + * \param olen total length written / required (if buf_len is not enough) + * + * \return 0 on success, or a specific PEM or BASE64 error code. On + * MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL olen is the required + * size. + */ +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ); +#endif /* MBEDTLS_PEM_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk.h new file mode 100644 index 0000000000..458bb512a9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk.h @@ -0,0 +1,615 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_H +#define MBEDTLS_PK_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "ecdsa.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ +#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ +#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ +#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The signature is valid but its length is less than expected. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Public key types + */ +typedef enum { + MBEDTLS_PK_NONE=0, + MBEDTLS_PK_RSA, + MBEDTLS_PK_ECKEY, + MBEDTLS_PK_ECKEY_DH, + MBEDTLS_PK_ECDSA, + MBEDTLS_PK_RSA_ALT, + MBEDTLS_PK_RSASSA_PSS, +} mbedtls_pk_type_t; + +/** + * \brief Options for RSASSA-PSS signature verification. + * See \c mbedtls_rsa_rsassa_pss_verify_ext() + */ +typedef struct +{ + mbedtls_md_type_t mgf1_hash_id; + int expected_salt_len; + +} mbedtls_pk_rsassa_pss_options; + +/** + * \brief Types for interfacing with the debug module + */ +typedef enum +{ + MBEDTLS_PK_DEBUG_NONE = 0, + MBEDTLS_PK_DEBUG_MPI, + MBEDTLS_PK_DEBUG_ECP, +} mbedtls_pk_debug_type; + +/** + * \brief Item to send to the debug module + */ +typedef struct +{ + mbedtls_pk_debug_type type; + const char *name; + void *value; +} mbedtls_pk_debug_item; + +/** Maximum number of item send for debugging, plus 1 */ +#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 + +/** + * \brief Public key information and operations + */ +typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; + +/** + * \brief Public key container + */ +typedef struct +{ + const mbedtls_pk_info_t * pk_info; /**< Public key informations */ + void * pk_ctx; /**< Underlying public key context */ +} mbedtls_pk_context; + +#if defined(MBEDTLS_RSA_C) +/** + * Quick access to an RSA context inside a PK context. + * + * \warning You must make sure the PK context actually holds an RSA context + * before using this function! + */ +static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) +{ + return( (mbedtls_rsa_context *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * Quick access to an EC context inside a PK context. + * + * \warning You must make sure the PK context actually holds an EC context + * before using this function! + */ +static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) +{ + return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Types for RSA-alt abstraction + */ +typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ); +typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ); +typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Return information associated with the given PK type + * + * \param pk_type PK type to search for. + * + * \return The PK info associated with the type or NULL if not found. + */ +const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); + +/** + * \brief Initialize a mbedtls_pk_context (as NONE) + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ); + +/** + * \brief Free a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ); + +/** + * \brief Initialize a PK context with the information given + * and allocates the type-specific PK subcontext. + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param info Information to use + * + * \return 0 on success, + * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, + * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. + * + * \note For contexts holding an RSA-alt key, use + * \c mbedtls_pk_setup_rsa_alt() instead. + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Initialize an RSA-alt context + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param key RSA key pointer + * \param decrypt_func Decryption function + * \param sign_func Signing function + * \param key_len_func Function returning key length in bytes + * + * \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the + * context wasn't already initialized as RSA_ALT. + * + * \note This function replaces \c mbedtls_pk_setup() for RSA-alt. + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Get the size in bits of the underlying key + * + * \param ctx Context to use + * + * \return Key size in bits, or 0 on error + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the length in bytes of the underlying key + * \param ctx Context to use + * + * \return Key length in bytes, or 0 on error + */ +static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) +{ + return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 ); +} + +/** + * \brief Tell if a context can do the operation given by type + * + * \param ctx Context to test + * \param type Target type + * + * \return 0 if context can't do the operations, + * 1 otherwise. + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); + +/** + * \brief Verify signature (including padding if relevant). + * + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than sig_len, + * or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) + * to verify RSASSA_PSS signatures. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Verify signature, with options. + * (Includes verification of the padding depending on type.) + * + * \param type Signature type (inc. possible padding type) to verify + * \param options Pointer to type-specific options, or NULL + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be + * used for this type of signatures, + * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than sig_len, + * or a specific error code. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + * + * \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point + * to a mbedtls_pk_rsassa_pss_options structure, + * otherwise it must be NULL. + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Make signature, including padding if relevant. + * + * \param ctx PK context to use - must hold a private key + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * There is no interface in the PK module to make RSASSA-PSS + * signatures yet. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0. + * For ECDSA, md_alg may never be MBEDTLS_MD_NONE. + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Decrypt message (including padding if relevant). + * + * \param ctx PK context to use - must hold a private key + * \param input Input to decrypt + * \param ilen Input size + * \param output Decrypted output + * \param olen Decrypted message length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Encrypt message (including padding if relevant). + * + * \param ctx PK context to use + * \param input Message to encrypt + * \param ilen Message size + * \param output Encrypted output + * \param olen Encrypted output length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check if a public-private pair of keys matches. + * + * \param pub Context holding a public key. + * \param prv Context holding a private (and public) key. + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + +/** + * \brief Export debug information + * + * \param ctx Context to use + * \param items Place to write debug items + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); + +/** + * \brief Access the type name + * + * \param ctx Context to use + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type + * + * \param ctx Context to use + * + * \return Type on success, or MBEDTLS_PK_NONE + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); + +#if defined(MBEDTLS_PK_PARSE_C) +/** \ingroup pk_module */ +/** + * \brief Parse a private key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup pk_module */ +/** + * \brief Parse a public key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup pk_module */ +/** + * \brief Load and parse a private key + * + * \param ctx key to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *password ); + +/** \ingroup pk_module */ +/** + * \brief Load and parse a public key + * + * \param ctx key to be initialized + * \param path filename to read the private key from + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a private key to a PKCS#1 or SEC1 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a public key to a SubjectPublicKeyInfo DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a public key to a PEM string + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a private key to a PKCS#1 or SEC1 PEM string + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * WARNING: Low-level functions. You probably do not want to use these unless + * you are certain you do ;) + */ + +#if defined(MBEDTLS_PK_PARSE_C) +/** + * \brief Parse a SubjectPublicKeyInfo DER structure + * + * \param p the position in the ASN.1 data + * \param end end of the buffer + * \param pk the key to fill + * + * \return 0 if successful, or a specific PK error code + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ); +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a subjectPublicKey to ASN.1 data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param key public key to write away + * + * \return the length written or a negative error code + */ +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ); +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +#if defined(MBEDTLS_FS_IO) +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk_internal.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk_internal.h new file mode 100644 index 0000000000..01d0f214bc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pk_internal.h @@ -0,0 +1,114 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_WRAP_H +#define MBEDTLS_PK_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +struct mbedtls_pk_info_t +{ + /** Public key type */ + mbedtls_pk_type_t type; + + /** Type name */ + const char *name; + + /** Get key size in bits */ + size_t (*get_bitlen)( const void * ); + + /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + int (*can_do)( mbedtls_pk_type_t type ); + + /** Verify signature */ + int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + + /** Make signature */ + int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Decrypt message */ + int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Encrypt message */ + int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Check public-private key pair */ + int (*check_pair_func)( const void *pub, const void *prv ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Interface with the debug module */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + +}; +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Container for RSA-alt */ +typedef struct +{ + void *key; + mbedtls_pk_rsa_alt_decrypt_func decrypt_func; + mbedtls_pk_rsa_alt_sign_func sign_func; + mbedtls_pk_rsa_alt_key_len_func key_len_func; +} mbedtls_rsa_alt_context; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const mbedtls_pk_info_t mbedtls_rsa_info; +#endif + +#if defined(MBEDTLS_ECP_C) +extern const mbedtls_pk_info_t mbedtls_eckey_info; +extern const mbedtls_pk_info_t mbedtls_eckeydh_info; +#endif + +#if defined(MBEDTLS_ECDSA_C) +extern const mbedtls_pk_info_t mbedtls_ecdsa_info; +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; +#endif + +#endif /* MBEDTLS_PK_WRAP_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs11.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs11.h new file mode 100644 index 0000000000..2e88928137 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs11.h @@ -0,0 +1,173 @@ +/** + * \file pkcs11.h + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS11_H +#define MBEDTLS_PKCS11_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS11_C) + +#include "x509_crt.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context for PKCS #11 private keys. + */ +typedef struct { + pkcs11h_certificate_t pkcs11h_cert; + int len; +} mbedtls_pkcs11_context; + +/** + * Initialize a mbedtls_pkcs11_context. + * (Just making memory references valid.) + */ +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ); + +/** + * Fill in a mbed TLS certificate, based on the given PKCS11 helper certificate. + * + * \param cert X.509 certificate to fill + * \param pkcs11h_cert PKCS #11 helper certificate + * + * \return 0 on success. + */ +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11h_cert ); + +/** + * Set up a mbedtls_pkcs11_context storing the given certificate. Note that the + * mbedtls_pkcs11_context will take over control of the certificate, freeing it when + * done. + * + * \param priv_key Private key structure to fill. + * \param pkcs11_cert PKCS #11 helper certificate + * + * \return 0 on success + */ +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ); + +/** + * Free the contents of the given private key context. Note that the structure + * itself is not freed. + * + * \param priv_key Private key structure to cleanup + */ +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ); + +/** + * \brief Do an RSA private key decrypt, then remove the message + * padding + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * SSL/TLS wrappers for PKCS#11 functions + */ +static inline int mbedtls_ssl_pkcs11_decrypt( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ) +{ + return mbedtls_pkcs11_decrypt( (mbedtls_pkcs11_context *) ctx, mode, olen, input, output, + output_max_len ); +} + +static inline int mbedtls_ssl_pkcs11_sign( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ) +{ + ((void) f_rng); + ((void) p_rng); + return mbedtls_pkcs11_sign( (mbedtls_pkcs11_context *) ctx, mode, md_alg, + hashlen, hash, sig ); +} + +static inline size_t mbedtls_ssl_pkcs11_key_len( void *ctx ) +{ + return ( (mbedtls_pkcs11_context *) ctx )->len; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PKCS11_C */ + +#endif /* MBEDTLS_PKCS11_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs12.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs12.h new file mode 100644 index 0000000000..9b2d904591 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs12.h @@ -0,0 +1,119 @@ +/** + * \file pkcs12.h + * + * \brief PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS12_H +#define MBEDTLS_PKCS12_H + +#include "md.h" +#include "cipher.h" +#include "asn1.h" + +#include + +#define MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA -0x1F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE -0x1F00 /**< Feature not available, e.g. unsupported encryption scheme. */ +#define MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT -0x1E80 /**< PBE ASN.1 data not as expected. */ +#define MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH -0x1E00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS12_DERIVE_KEY 1 /**< encryption/decryption key */ +#define MBEDTLS_PKCS12_DERIVE_IV 2 /**< initialization vector */ +#define MBEDTLS_PKCS12_DERIVE_MAC_KEY 3 /**< integrity / MAC key */ + +#define MBEDTLS_PKCS12_PBE_DECRYPT 0 +#define MBEDTLS_PKCS12_PBE_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for pbeWithSHAAnd128BitRC4 + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for cipher-based and mbedtls_md-based PBE's + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param cipher_type the cipher used + * \param md_type the mbedtls_md used + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief The PKCS#12 derivation function uses a password and a salt + * to produce pseudo-random bits for a particular "purpose". + * + * Depending on the given id, this function can produce an + * encryption/decryption key, an nitialization vector or an + * integrity key. + * + * \param data buffer to store the derived data in + * \param datalen length to fill + * \param pwd password to use (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param salt salt buffer to use + * \param saltlen length of the salt + * \param mbedtls_md mbedtls_md type to use during the derivation + * \param id id that describes the purpose (can be MBEDTLS_PKCS12_DERIVE_KEY, + * MBEDTLS_PKCS12_DERIVE_IV or MBEDTLS_PKCS12_DERIVE_MAC_KEY) + * \param iterations number of iterations + * + * \return 0 if successful, or a MD, BIGNUM type error. + */ +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t mbedtls_md, int id, int iterations ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs12.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs5.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs5.h new file mode 100644 index 0000000000..ec5cb9e744 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/pkcs5.h @@ -0,0 +1,94 @@ +/** + * \file pkcs5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS5_H +#define MBEDTLS_PKCS5_H + +#include "asn1.h" +#include "md.h" + +#include +#include + +#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA -0x2f80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 /**< Unexpected ASN.1 data. */ +#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 /**< Requested encryption or digest alg not available. */ +#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS5_DECRYPT 0 +#define MBEDTLS_PKCS5_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS#5 PBES2 function + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either MBEDTLS_PKCS5_DECRYPT or MBEDTLS_PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param pwdlen length of password + * \param data data to process + * \param datalen length of data + * \param output output buffer + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ); + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key in bytes + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/platform.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/platform.h new file mode 100644 index 0000000000..fbbefc4d55 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/platform.h @@ -0,0 +1,217 @@ +/** + * \file platform.h + * + * \brief mbed TLS Platform abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_H +#define MBEDTLS_PLATFORM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ +extern int ets_snprintf(char *buf, unsigned int size, const char *format, ...); +extern void *pvPortCalloc(unsigned int count, unsigned int size); +extern void vPortFree( void *pv ); +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#include +#include +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +#if defined(_WIN32) +#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */ +#else +#define MBEDTLS_PLATFORM_STD_SNPRINTF ets_snprintf /**< Default snprintf to use */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +#define MBEDTLS_PLATFORM_STD_CALLOC pvPortCalloc /**< Default allocator to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE vPortFree /**< Default free to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default free to use */ +#endif +#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) +#include MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + +/* \} name SECTION: Module settings */ + +/* + * The function pointers for calloc and free + */ +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \ + defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO +#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO +#else +/* For size_t */ +#include +extern void * (*mbedtls_calloc)( size_t n, size_t size ); +extern void (*mbedtls_free)( void *ptr ); + +/** + * \brief Set your own memory implementation function pointers + * + * \param calloc_func the calloc function implementation + * \param free_func the free function implementation + * + * \return 0 if successful + */ +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ); +#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */ +#else /* !MBEDTLS_PLATFORM_MEMORY */ +#define mbedtls_free vPortFree +#define mbedtls_calloc pvPortCalloc +#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */ + +/* + * The function pointers for fprintf + */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +/* We need FILE * */ +#include +extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... ); + +/** + * \brief Set your own fprintf function pointer + * + * \param fprintf_func the fprintf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *, + ... ) ); +#else +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) +#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO +#else +#define mbedtls_fprintf fprintf +#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +/* + * The function pointers for printf + */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +extern int (*mbedtls_printf)( const char *format, ... ); + +/** + * \brief Set your own printf function pointer + * + * \param printf_func the printf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ); +#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) +#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO +#else +#define mbedtls_printf os_printf +#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +/* + * The function pointers for snprintf + * + * The snprintf implementation should conform to C99: + * - it *must* always correctly zero-terminate the buffer + * (except when n == 0, then it must leave the buffer untouched) + * - however it is acceptable to return -1 instead of the required length when + * the destination buffer is too short. + */ +#if defined(_WIN32) +/* For Windows (inc. MSYS2), we provide our own fixed implementation */ +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ); +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... ); + +/** + * \brief Set your own snprintf function pointer + * + * \param snprintf_func the snprintf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, ... ) ); +#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO +#else +#define mbedtls_snprintf ets_snprintf +#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +/* + * The function pointers for exit + */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +extern void (*mbedtls_exit)( int status ); + +/** + * \brief Set your own exit function pointer + * + * \param exit_func the exit function implementation + * + * \return 0 + */ +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ); +#else +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) +#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO +#else +#define mbedtls_exit exit +#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */ +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +#ifdef __cplusplus +} +#endif + +#endif /* platform.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ripemd160.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ripemd160.h new file mode 100644 index 0000000000..7083fc8599 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ripemd160.h @@ -0,0 +1,138 @@ +/** + * \file ripemd160.h + * + * \brief RIPE MD-160 message digest + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RIPEMD160_H +#define MBEDTLS_RIPEMD160_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_RIPEMD160_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RIPEMD-160 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_ripemd160_context; + +/** + * \brief Initialize RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be initialized + */ +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clear RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be cleared + */ +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clone (the state of) an RIPEMD-160 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ); + +/** + * \brief RIPEMD-160 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx ); + +/** + * \brief RIPEMD-160 process buffer + * + * \param ctx RIPEMD-160 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief RIPEMD-160 final digest + * + * \param ctx RIPEMD-160 context + * \param output RIPEMD-160 checksum result + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_RIPEMD160_ALT */ +#include "ripemd160.h" +#endif /* MBEDTLS_RIPEMD160_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = RIPEMD-160( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output RIPEMD-160 checksum result + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ripemd160_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_ripemd160.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/rsa.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/rsa.h new file mode 100644 index 0000000000..9c8645df69 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/rsa.h @@ -0,0 +1,652 @@ +/** + * \file rsa.h + * + * \brief The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RSA_H +#define MBEDTLS_RSA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * RSA Error codes + */ +#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the library's validity check. */ +#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* + * RSA constants + */ +#define MBEDTLS_RSA_PUBLIC 0 +#define MBEDTLS_RSA_PRIVATE 1 + +#define MBEDTLS_RSA_PKCS_V15 0 +#define MBEDTLS_RSA_PKCS_V21 1 + +#define MBEDTLS_RSA_SIGN 1 +#define MBEDTLS_RSA_CRYPT 2 + +#define MBEDTLS_RSA_SALT_LEN_ANY -1 + +/* + * The above constants may be used even if the RSA module is compile out, + * eg for alternative (PKCS#11) RSA implemenations in the PK layers. + */ +#if defined(MBEDTLS_RSA_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mbedtls_mpi N; /*!< public modulus */ + mbedtls_mpi E; /*!< public exponent */ + + mbedtls_mpi D; /*!< private exponent */ + mbedtls_mpi P; /*!< 1st prime factor */ + mbedtls_mpi Q; /*!< 2nd prime factor */ + mbedtls_mpi DP; /*!< D % (P - 1) */ + mbedtls_mpi DQ; /*!< D % (Q - 1) */ + mbedtls_mpi QP; /*!< 1 / (Q % P) */ + + mbedtls_mpi RN; /*!< cached R^2 mod N */ + mbedtls_mpi RP; /*!< cached R^2 mod P */ + mbedtls_mpi RQ; /*!< cached R^2 mod Q */ + + mbedtls_mpi Vi; /*!< cached blinding value */ + mbedtls_mpi Vf; /*!< cached un-blinding value */ + + int padding; /*!< MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of mbedtls_md_type_t as + specified in the mbedtls_md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex */ +#endif +} +mbedtls_rsa_context; + +/** + * \brief Initialize an RSA context + * + * Note: Set padding to MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \param ctx RSA context to be initialized + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using MBEDTLS_RSA_PKCS_V15 padding. + * + * \note Choice of padding mode is strictly enforced for private key + * operations, since there might be security concerns in + * mixing padding modes. For public key operations it's merely + * a default value, which can be overriden by calling specific + * rsa_rsaes_xxx or rsa_rsassa_xxx functions. + * + * \note The chosen hash is always used for OEAP encryption. + * For PSS signatures, it's always used for making signatures, + * but can be overriden (and always is, if set to + * MBEDTLS_MD_NONE) for verifying them. + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Set padding for an already initialized RSA context + * See \c mbedtls_rsa_init() for details. + * + * \param ctx RSA context to be set + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note mbedtls_rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a public-private RSA key pair. + * Check each of the contexts, and make sure they match. + * + * \param pub RSA context holding the public key + * \param prv RSA context holding the private key + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or assure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for blinding) + * \param p_rng RNG parameter + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 encryption using the + * mode from the context. Add the message padding, then do an + * RSA operation. + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 decryption using the + * mode from the context. Do an RSA operation, then remove + * the message padding + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Generic wrapper to perform a PKCS#1 signature using the + * mode from the context. Do a private RSA operation to sign + * a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \note \c mbedtls_rsa_rsassa_pss_sign() for details on md_alg and hash_id. + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is the one used for the + * encoding. md_alg in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Generic wrapper to perform a PKCS#1 verification using the + * mode from the context. Do a public RSA operation and check + * the message digest + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \c mbedtls_rsa_rsassa_pss_verify() about md_alg and hash_id. + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the "simple" version.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is the one used for the + * verification. md_alg in the function call is the type of + * hash that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. If hash_id in the RSA context is + * unset, the md_alg from the function call is used. + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the version with "full" options.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param mgf1_hash_id message digest used for mask generation + * \param expected_salt_len Length of the salt used in padding, use + * MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is ignored. + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ); + +/** + * \brief Copy the components of an RSA context + * + * \param dst Destination context + * \param src Source context + * + * \return 0 on success, + * MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_RSA_C */ + +#endif /* rsa.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha1.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha1.h new file mode 100644 index 0000000000..7a67c6c1fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha1.h @@ -0,0 +1,136 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha256.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha256.h new file mode 100644 index 0000000000..f8041adf08 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha256.h @@ -0,0 +1,141 @@ +/** + * \file sha256.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha256_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha512.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha512.h new file mode 100644 index 0000000000..627694f425 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sha512.h @@ -0,0 +1,141 @@ +/** + * \file sha512.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA512_H +#define MBEDTLS_SHA512_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +mbedtls_sha512_context; + +/** + * \brief Initialize SHA-512 context + * + * \param ctx SHA-512 context to be initialized + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief Clear SHA-512 context + * + * \param ctx SHA-512 context to be cleared + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-512 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha512_self_test( int verbose ); + +/* Internal use */ +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha512.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl.h new file mode 100644 index 0000000000..ff5f3897fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl.h @@ -0,0 +1,2393 @@ +/** + * \file ssl.h + * + * \brief SSL/TLS functions. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_H +#define MBEDTLS_SSL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "ecp.h" + +#include "ssl_ciphersuites.h" + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "x509_crt.h" +#include "x509_crl.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "dhm.h" +#endif + +#if defined(MBEDTLS_ECDH_C) +#include "ecdh.h" +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) +#include "zlib.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif + +/* + * SSL Error codes + */ +#define MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE -0x7080 /**< The requested feature is not available. */ +#define MBEDTLS_ERR_SSL_BAD_INPUT_DATA -0x7100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_SSL_INVALID_MAC -0x7180 /**< Verification of the message MAC failed. */ +#define MBEDTLS_ERR_SSL_INVALID_RECORD -0x7200 /**< An invalid SSL record was received. */ +#define MBEDTLS_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */ +#define MBEDTLS_ERR_SSL_UNKNOWN_CIPHER -0x7300 /**< An unknown cipher was received. */ +#define MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN -0x7380 /**< The server has no ciphersuites in common with the client. */ +#define MBEDTLS_ERR_SSL_NO_RNG -0x7400 /**< No RNG was provided to the SSL module. */ +#define MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480 /**< No client certification received from the client, but required by the authentication mode. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500 /**< Our own certificate(s) is/are too large to send in an SSL message. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED -0x7580 /**< The own certificate is not set, but needed by the server. */ +#define MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600 /**< The own private key or pre-shared key is not set, but needed. */ +#define MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED -0x7680 /**< No CA Chain is set, but required to operate. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE -0x7700 /**< An unexpected message was received from our peer. */ +#define MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780 /**< A fatal alert message was received from our peer. */ +#define MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED -0x7800 /**< Verification of our peer failed. */ +#define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /**< The peer notified us that the connection is going to be closed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 /**< Processing of the ClientHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /**< Processing of the ServerHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00 /**< Processing of the Certificate handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80 /**< Processing of the CertificateRequest handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /**< Processing of the ServerKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 /**< Processing of the ServerHelloDone handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /**< Processing of the ClientKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP -0x7C80 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS -0x7D00 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /**< Processing of the CertificateVerify handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 /**< Processing of the ChangeCipherSpec handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80 /**< Processing of the Finished handshake message failed. */ +#define MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00 /**< Memory allocation failed */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -0x7F80 /**< Hardware acceleration function returned with error */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ +#define MBEDTLS_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ +#define MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */ +#define MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00 /**< Processing of the NewSessionTicket handshake message failed. */ +#define MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED -0x6D80 /**< Session ticket has expired. */ +#define MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH -0x6D00 /**< Public key type mismatch (eg, asked for RSA key exchange and presented EC key) */ +#define MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY -0x6C80 /**< Unknown identity received (eg, PSK identity) */ +#define MBEDTLS_ERR_SSL_INTERNAL_ERROR -0x6C00 /**< Internal error (eg, unexpected failure in lower-level module) */ +#define MBEDTLS_ERR_SSL_COUNTER_WRAPPING -0x6B80 /**< A counter would wrap (eg, too many messages exchanged). */ +#define MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00 /**< Unexpected message at ServerHello in renegotiation. */ +#define MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80 /**< DTLS client must retry for hello verification */ +#define MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00 /**< A buffer is too small to receive or write a message */ +#define MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980 /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */ +#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< Connection requires a read call. */ +#define MBEDTLS_ERR_SSL_WANT_WRITE -0x6880 /**< Connection requires a write call. */ +#define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */ +#define MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780 /**< The client initiated a reconnect from the same port. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */ + +/* + * Various constants + */ +#define MBEDTLS_SSL_MAJOR_VERSION_3 3 +#define MBEDTLS_SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define MBEDTLS_SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ + +#define MBEDTLS_SSL_TRANSPORT_STREAM 0 /*!< TLS */ +#define MBEDTLS_SSL_TRANSPORT_DATAGRAM 1 /*!< DTLS */ + +#define MBEDTLS_SSL_MAX_HOST_NAME_LEN 255 /*!< Maximum host name defined in RFC 1035 */ + +/* RFC 6066 section 4, see also mfl_code_to_length in ssl_tls.c + * NONE must be zero so that memset()ing structure to zero works */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_NONE 0 /*!< don't use this extension */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_512 1 /*!< MaxFragmentLength 2^9 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_1024 2 /*!< MaxFragmentLength 2^10 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_2048 3 /*!< MaxFragmentLength 2^11 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_4096 4 /*!< MaxFragmentLength 2^12 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_INVALID 5 /*!< first invalid value */ + +#define MBEDTLS_SSL_IS_CLIENT 0 +#define MBEDTLS_SSL_IS_SERVER 1 + +#define MBEDTLS_SSL_IS_NOT_FALLBACK 0 +#define MBEDTLS_SSL_IS_FALLBACK 1 + +#define MBEDTLS_SSL_EXTENDED_MS_DISABLED 0 +#define MBEDTLS_SSL_EXTENDED_MS_ENABLED 1 + +#define MBEDTLS_SSL_ETM_DISABLED 0 +#define MBEDTLS_SSL_ETM_ENABLED 1 + +#define MBEDTLS_SSL_COMPRESS_NULL 0 +#define MBEDTLS_SSL_COMPRESS_DEFLATE 1 + +#define MBEDTLS_SSL_VERIFY_NONE 0 +#define MBEDTLS_SSL_VERIFY_OPTIONAL 1 +#define MBEDTLS_SSL_VERIFY_REQUIRED 2 +#define MBEDTLS_SSL_VERIFY_UNSET 3 /* Used only for sni_authmode */ + +#define MBEDTLS_SSL_LEGACY_RENEGOTIATION 0 +#define MBEDTLS_SSL_SECURE_RENEGOTIATION 1 + +#define MBEDTLS_SSL_RENEGOTIATION_DISABLED 0 +#define MBEDTLS_SSL_RENEGOTIATION_ENABLED 1 + +#define MBEDTLS_SSL_ANTI_REPLAY_DISABLED 0 +#define MBEDTLS_SSL_ANTI_REPLAY_ENABLED 1 + +#define MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED -1 +#define MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT 16 + +#define MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION 0 +#define MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION 1 +#define MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE 2 + +#define MBEDTLS_SSL_TRUNC_HMAC_DISABLED 0 +#define MBEDTLS_SSL_TRUNC_HMAC_ENABLED 1 +#define MBEDTLS_SSL_TRUNCATED_HMAC_LEN 10 /* 80 bits, rfc 6066 section 7 */ + +#define MBEDTLS_SSL_SESSION_TICKETS_DISABLED 0 +#define MBEDTLS_SSL_SESSION_TICKETS_ENABLED 1 + +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED 0 +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED 1 + +#define MBEDTLS_SSL_ARC4_ENABLED 0 +#define MBEDTLS_SSL_ARC4_DISABLED 1 + +#define MBEDTLS_SSL_PRESET_DEFAULT 0 +#define MBEDTLS_SSL_PRESET_SUITEB 2 + +/* + * Default range for DTLS retransmission timer value, in milliseconds. + * RFC 6347 4.2.4.1 says from 1 second to 60 seconds. + */ +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN 1000 +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX 60000 + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME) +#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +#endif + +/* + * Maxium fragment length in bytes, + * determines the size of each of the two internal I/O buffers. + * + * Note: the RFC defines the default size of SSL / TLS messages. If you + * change the value here, other clients / servers may not be able to + * communicate with you anymore. Only change this value if you control + * both sides of the connection and have it reduced at both sides, or + * if you're using the Max Fragment Length extension and you know all your + * peers are using it too! + */ +#if !defined(MBEDTLS_SSL_MAX_CONTENT_LEN) +#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +#endif + +/* \} name SECTION: Module settings */ + +/* + * Length of the verify data for secure renegotiation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 36 +#else +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 12 +#endif + +/* + * Signaling ciphersuite values (SCSV) + */ +#define MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ +#define MBEDTLS_SSL_FALLBACK_SCSV_VALUE 0x5600 /**< draft-ietf-tls-downgrade-scsv-00 */ + +/* + * Supported Signature and Hash algorithms (For TLS 1.2) + * RFC 5246 section 7.4.1.4.1 + */ +#define MBEDTLS_SSL_HASH_NONE 0 +#define MBEDTLS_SSL_HASH_MD5 1 +#define MBEDTLS_SSL_HASH_SHA1 2 +#define MBEDTLS_SSL_HASH_SHA224 3 +#define MBEDTLS_SSL_HASH_SHA256 4 +#define MBEDTLS_SSL_HASH_SHA384 5 +#define MBEDTLS_SSL_HASH_SHA512 6 + +#define MBEDTLS_SSL_SIG_ANON 0 +#define MBEDTLS_SSL_SIG_RSA 1 +#define MBEDTLS_SSL_SIG_ECDSA 3 + +/* + * Client Certificate Types + * RFC 5246 section 7.4.4 plus RFC 4492 section 5.5 + */ +#define MBEDTLS_SSL_CERT_TYPE_RSA_SIGN 1 +#define MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN 64 + +/* + * Message, alert and handshake types + */ +#define MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define MBEDTLS_SSL_MSG_ALERT 21 +#define MBEDTLS_SSL_MSG_HANDSHAKE 22 +#define MBEDTLS_SSL_MSG_APPLICATION_DATA 23 + +#define MBEDTLS_SSL_ALERT_LEVEL_WARNING 1 +#define MBEDTLS_SSL_ALERT_LEVEL_FATAL 2 + +#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ +#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ + +#define MBEDTLS_SSL_HS_HELLO_REQUEST 0 +#define MBEDTLS_SSL_HS_CLIENT_HELLO 1 +#define MBEDTLS_SSL_HS_SERVER_HELLO 2 +#define MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST 3 +#define MBEDTLS_SSL_HS_NEW_SESSION_TICKET 4 +#define MBEDTLS_SSL_HS_CERTIFICATE 11 +#define MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE 12 +#define MBEDTLS_SSL_HS_CERTIFICATE_REQUEST 13 +#define MBEDTLS_SSL_HS_SERVER_HELLO_DONE 14 +#define MBEDTLS_SSL_HS_CERTIFICATE_VERIFY 15 +#define MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define MBEDTLS_SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define MBEDTLS_TLS_EXT_SERVERNAME 0 +#define MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME 0 + +#define MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH 1 + +#define MBEDTLS_TLS_EXT_TRUNCATED_HMAC 4 + +#define MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS 11 + +#define MBEDTLS_TLS_EXT_SIG_ALG 13 + +#define MBEDTLS_TLS_EXT_ALPN 16 + +#define MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC 22 /* 0x16 */ +#define MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET 0x0017 /* 23 */ + +#define MBEDTLS_TLS_EXT_SESSION_TICKET 35 + +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP 256 /* experimental */ + +#define MBEDTLS_TLS_EXT_RENEGOTIATION_INFO 0xFF01 + +/* + * Size defines + */ +#if !defined(MBEDTLS_PSK_MAX_LEN) +#define MBEDTLS_PSK_MAX_LEN 32 /* 256 bits */ +#endif + +/* Dummy type used only for its size */ +union mbedtls_ssl_premaster_secret +{ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + unsigned char _pms_rsa[48]; /* RFC 5246 8.1.1 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + unsigned char _pms_dhm[MBEDTLS_MPI_MAX_SIZE]; /* RFC 5246 8.1.2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + unsigned char _pms_ecdh[MBEDTLS_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + unsigned char _pms_psk[4 + 2 * MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + unsigned char _pms_dhe_psk[4 + MBEDTLS_MPI_MAX_SIZE + + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 3 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + unsigned char _pms_rsa_psk[52 + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 4 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + unsigned char _pms_ecdhe_psk[4 + MBEDTLS_ECP_MAX_BYTES + + MBEDTLS_PSK_MAX_LEN]; /* RFC 5489 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + unsigned char _pms_ecjpake[32]; /* Thread spec: SHA-256 output */ +#endif +}; + +#define MBEDTLS_PREMASTER_SIZE sizeof( union mbedtls_ssl_premaster_secret ) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SSL state machine + */ +typedef enum +{ + MBEDTLS_SSL_HELLO_REQUEST, + MBEDTLS_SSL_CLIENT_HELLO, + MBEDTLS_SSL_SERVER_HELLO, + MBEDTLS_SSL_SERVER_CERTIFICATE, + MBEDTLS_SSL_SERVER_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_REQUEST, + MBEDTLS_SSL_SERVER_HELLO_DONE, + MBEDTLS_SSL_CLIENT_CERTIFICATE, + MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_VERIFY, + MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_CLIENT_FINISHED, + MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_SERVER_FINISHED, + MBEDTLS_SSL_FLUSH_BUFFERS, + MBEDTLS_SSL_HANDSHAKE_WRAPUP, + MBEDTLS_SSL_HANDSHAKE_OVER, + MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, + MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, +} +mbedtls_ssl_states; + +/* Defined below */ +typedef struct mbedtls_ssl_session mbedtls_ssl_session; +typedef struct mbedtls_ssl_context mbedtls_ssl_context; +typedef struct mbedtls_ssl_config mbedtls_ssl_config; + +/* Defined in ssl_internal.h */ +typedef struct mbedtls_ssl_transform mbedtls_ssl_transform; +typedef struct mbedtls_ssl_handshake_params mbedtls_ssl_handshake_params; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) +typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; +#endif + +/* + * This structure is used for storing current session data. + */ +struct mbedtls_ssl_session +{ +#if defined(MBEDTLS_HAVE_TIME) + time_t start; /*!< starting time */ +#endif + int ciphersuite; /*!< chosen ciphersuite */ + int compression; /*!< chosen compression */ + size_t id_len; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + uint32_t verify_result; /*!< verification result */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + unsigned char *ticket; /*!< RFC 5077 session ticket */ + size_t ticket_len; /*!< session ticket length */ + uint32_t ticket_lifetime; /*!< ticket lifetime hint */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */ +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + int trunc_hmac; /*!< flag for truncated hmac activation */ +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + int encrypt_then_mac; /*!< flag for EtM activation */ +#endif +}; + +/** + * SSL/TLS configuration to be shared between mbedtls_ssl_context structures. + */ +struct mbedtls_ssl_config +{ + /* Group items by size (largest first) to minimize padding overhead */ + + /* + * Pointers + */ + + const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version */ + + /** Callback for printing debug output */ + void (*f_dbg)(void *, int, const char *, int, const char *); + void *p_dbg; /*!< context for the debug function */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + + /** Callback to retrieve a session from the cache */ + int (*f_get_cache)(void *, mbedtls_ssl_session *); + /** Callback to store a session into the cache */ + int (*f_set_cache)(void *, const mbedtls_ssl_session *); + void *p_cache; /*!< context for cache callbacks */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /** Callback for setting cert according to SNI extension */ + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_sni; /*!< context for SNI callback */ +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /** Callback to customize X.509 certificate chain verification */ + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; /*!< context for X.509 verify calllback */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /** Callback to retrieve PSK key from identity */ + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_psk; /*!< context for PSK callback */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a cookie for ClientHello veirifcation */ + int (*f_cookie_write)( void *, unsigned char **, unsigned char *, + const unsigned char *, size_t ); + /** Callback to verify validity of a ClientHello cookie */ + int (*f_cookie_check)( void *, const unsigned char *, size_t, + const unsigned char *, size_t ); + void *p_cookie; /*!< context for the cookie callbacks */ +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a session ticket */ + int (*f_ticket_write)( void *, const mbedtls_ssl_session *, + unsigned char *, const unsigned char *, size_t *, uint32_t * ); + /** Callback to parse a session ticket into a session structure */ + int (*f_ticket_parse)( void *, mbedtls_ssl_session *, unsigned char *, size_t); + void *p_ticket; /*!< context for the ticket callbacks */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + /** Callback to export key block and master secret */ + int (*f_export_keys)( void *, const unsigned char *, + const unsigned char *, size_t, size_t, size_t ); + void *p_export_keys; /*!< context for key export callback */ +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + const mbedtls_x509_crt_profile *cert_profile; /*!< verification profile */ + mbedtls_ssl_key_cert *key_cert; /*!< own certificate/key pair(s) */ + mbedtls_x509_crt *ca_chain; /*!< trusted CAs */ + mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + const int *sig_hashes; /*!< allowed signature hashes */ +#endif + +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ +#endif + +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi dhm_P; /*!< prime modulus for DHM */ + mbedtls_mpi dhm_G; /*!< generator for DHM */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + unsigned char *psk; /*!< pre-shared key */ + size_t psk_len; /*!< length of the pre-shared key */ + unsigned char *psk_identity; /*!< identity for PSK negotiation */ + size_t psk_identity_len;/*!< length of identity */ +#endif + +#if defined(MBEDTLS_SSL_ALPN) + const char **alpn_list; /*!< ordered list of protocols */ +#endif + + /* + * Numerical settings (int then char) + */ + + uint32_t read_timeout; /*!< timeout for mbedtls_ssl_read (ms) */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint32_t hs_timeout_min; /*!< initial value of the handshake + retransmission timeout (ms) */ + uint32_t hs_timeout_max; /*!< maximum value of the handshake + retransmission timeout (ms) */ +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_max_records; /*!< grace period for renegotiation */ + unsigned char renego_period[8]; /*!< value of the record counters + that triggers renegotiation */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned int badmac_limit; /*!< limit of records with a bad MAC */ +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + unsigned int dhm_min_bitlen; /*!< min. bit length of the DHM prime */ +#endif + + unsigned char max_major_ver; /*!< max. major version used */ + unsigned char max_minor_ver; /*!< max. minor version used */ + unsigned char min_major_ver; /*!< min. major version used */ + unsigned char min_minor_ver; /*!< min. minor version used */ + + /* + * Flags (bitfields) + */ + + unsigned int endpoint : 1; /*!< 0: client, 1: server */ + unsigned int transport : 1; /*!< stream (TLS) or datagram (DTLS) */ + unsigned int authmode : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ + /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ + unsigned int allow_legacy_renegotiation : 2 ; /*!< MBEDTLS_LEGACY_XXX */ +#if defined(MBEDTLS_ARC4_C) + unsigned int arc4_disabled : 1; /*!< blacklist RC4 ciphersuites? */ +#endif +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned int mfl_code : 3; /*!< desired fragment length */ +#endif +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + unsigned int encrypt_then_mac : 1 ; /*!< negotiate encrypt-then-mac? */ +#endif +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + unsigned int extended_ms : 1; /*!< negotiate extended master secret? */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + unsigned int anti_replay : 1; /*!< detect and prevent replay? */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + unsigned int cbc_record_splitting : 1; /*!< do cbc record splitting */ +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + unsigned int disable_renegotiation : 1; /*!< disable renegotiation? */ +#endif +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + unsigned int trunc_hmac : 1; /*!< negotiate truncated hmac? */ +#endif +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + unsigned int session_tickets : 1; /*!< use session tickets? */ +#endif +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) + unsigned int fallback : 1; /*!< is this a fallback? */ +#endif +}; + + +struct mbedtls_ssl_context +{ + const mbedtls_ssl_config *conf; /*!< configuration information */ + + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_status; /*!< Initial, in progress, pending? */ + int renego_records_seen; /*!< Records since renego request, or with DTLS, + number of retransmissions of request if + renego_max_records is < 0 */ +#endif + + int major_ver; /*!< equal to MBEDTLS_SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned badmac_seen; /*!< records with a bad MAC received */ +#endif + + /* + * Callbacks + */ + int (*f_send)(void *, const unsigned char *, size_t); + int (*f_recv)(void *, unsigned char *, size_t); + int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t); + void *p_bio; /*!< context for I/O operations */ + + /* + * Session layer + */ + mbedtls_ssl_session *session_in; /*!< current session data (in) */ + mbedtls_ssl_session *session_out; /*!< current session data (out) */ + mbedtls_ssl_session *session; /*!< negotiated session data */ + mbedtls_ssl_session *session_negotiate; /*!< session data in negotiation */ + + mbedtls_ssl_handshake_params *handshake; /*!< params required only during + the handshake process */ + + /* + * Record layer transformations + */ + mbedtls_ssl_transform *transform_in; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform_out; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform; /*!< negotiated transform params */ + mbedtls_ssl_transform *transform_negotiate; /*!< transform params in negotiation */ + + /* + * Timers + */ + void *p_timer; /*!< context for the timer callbacks */ + void (*f_set_timer)(void *, uint32_t, uint32_t); /*!< set timer callback */ + int (*f_get_timer)(void *); /*!< get timer callback */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_buf; /*!< input buffer */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter + TLS: maintained by us + DTLS: read from peer */ + unsigned char *in_hdr; /*!< start of record header */ + unsigned char *in_len; /*!< two-bytes message length field */ + unsigned char *in_iv; /*!< ivlen-byte IV */ + unsigned char *in_msg; /*!< message contents (in_iv+ivlen) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + size_t in_msglen; /*!< record header: message length */ + size_t in_left; /*!< amount of data read so far */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t in_epoch; /*!< DTLS epoch for incoming records */ + size_t next_record_offset; /*!< offset of the next record in datagram + (equal to in_left if none) */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + uint64_t in_window_top; /*!< last validated record seq_num */ + uint64_t in_window; /*!< bitmask for replay detection */ +#endif + + size_t in_hslen; /*!< current handshake message length, + including the handshake header */ + int nb_zero; /*!< # of 0-length encrypted messages */ + int record_read; /*!< record is already present */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_buf; /*!< output buffer */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< start of record header */ + unsigned char *out_len; /*!< two-bytes message length field */ + unsigned char *out_iv; /*!< ivlen-byte IV */ + unsigned char *out_msg; /*!< message contents (out_iv+ivlen) */ + + int out_msgtype; /*!< record header: message type */ + size_t out_msglen; /*!< record header: message length */ + size_t out_left; /*!< amount of data not yet written */ + +#if defined(MBEDTLS_ZLIB_SUPPORT) + unsigned char *compress_buf; /*!< zlib data buffer */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + signed char split_done; /*!< current record already splitted? */ +#endif + + /* + * PKI layer + */ + int client_auth; /*!< flag for client auth. */ + + /* + * User settings + */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + char *hostname; /*!< expected peer CN for verification + (and SNI if available) */ +#endif + +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn_chosen; /*!< negotiated protocol */ +#endif + + /* + * Information for DTLS hello verify + */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + unsigned char *cli_id; /*!< transport-level ID of the client */ + size_t cli_id_len; /*!< length of cli_id */ +#endif + + /* + * Secure renegotiation + */ + /* needed to know when to send extension on server */ + int secure_renegotiation; /*!< does peer support legacy or + secure renegotiation */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + size_t verify_data_len; /*!< length of verify data stored */ + char own_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ + char peer_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ +#endif +}; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + +#define MBEDTLS_SSL_CHANNEL_OUTBOUND 0 +#define MBEDTLS_SSL_CHANNEL_INBOUND 1 + +extern int (*mbedtls_ssl_hw_record_init)(mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen); +extern int (*mbedtls_ssl_hw_record_activate)(mbedtls_ssl_context *ssl, int direction); +extern int (*mbedtls_ssl_hw_record_reset)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_write)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_read)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_finish)(mbedtls_ssl_context *ssl); +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/** + * \brief Returns the list of ciphersuites supported by the SSL/TLS module. + * + * \return a statically allocated array of ciphersuites, the last + * entry is 0. + */ +const int *mbedtls_ssl_list_ciphersuites( void ); + +/** + * \brief Return the name of the ciphersuite associated with the + * given ID + * + * \param ciphersuite_id SSL ciphersuite ID + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ); + +/** + * \brief Return the ID of the ciphersuite associated with the + * given name + * + * \param ciphersuite_name SSL ciphersuite name + * + * \return the ID with the ciphersuite or 0 if not found + */ +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ); + +/** + * \brief Initialize an SSL context + * Just makes the context ready for mbedtls_ssl_setup() or + * mbedtls_ssl_free() + * + * \param ssl SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ); + +/** + * \brief Set up an SSL context for use + * + * \note No copy of the configuration context is made, it can be + * shared by many mbedtls_ssl_context structures. + * + * \warning Modifying the conf structure after is has been used in this + * function is unsupported! + * + * \param ssl SSL context + * \param conf SSL configuration to use + * + * \return 0 if successful, or MBEDTLS_ERR_SSL_ALLOC_FAILED if + * memory allocation failed + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ); + +/** + * \brief Reset an already initialized SSL context for re-use + * while retaining application-set variables, function + * pointers and data. + * + * \param ssl SSL context + * \return 0 if successful, or POLASSL_ERR_SSL_MALLOC_FAILED, + MBEDTLS_ERR_SSL_HW_ACCEL_FAILED or + * MBEDTLS_ERR_SSL_COMPRESSION_FAILED + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param conf SSL configuration + * \param endpoint must be MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ); + +/** + * \brief Set the transport type (TLS or DTLS). + * Default: TLS + * + * \note For DTLS, you must either provide a recv callback that + * doesn't block, or one that handles timeouts, see + * \c mbedtls_ssl_set_bio(). You also need to provide timer + * callbacks with \c mbedtls_ssl_set_timer_cb(). + * + * \param conf SSL configuration + * \param transport transport type: + * MBEDTLS_SSL_TRANSPORT_STREAM for TLS, + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS. + */ +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ); + +/** + * \brief Set the certificate verification mode + * Default: NONE on server, REQUIRED on client + * + * \param conf SSL configuration + * \param authmode can be: + * + * MBEDTLS_SSL_VERIFY_NONE: peer certificate is not checked + * (default on server) + * (insecure on client) + * + * MBEDTLS_SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * mbedtls_ssl_get_verify_result() can be called after the + * handshake is complete. + * + * MBEDTLS_SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + * + * \note On client, MBEDTLS_SSL_VERIFY_REQUIRED is the recommended mode. + * With MBEDTLS_SSL_VERIFY_OPTIONAL, the user needs to call mbedtls_ssl_get_verify_result() at + * the right time(s), which may not be obvious, while REQUIRED always perform + * the verification as soon as possible. For example, REQUIRED was protecting + * against the "triple handshake" attack even before it was found. + */ +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the verification callback (Optional). + * + * If set, the verify callback is called for each + * certificate in the chain. For implementation + * information, please see \c x509parse_verify() + * + * \param conf SSL configuration + * \param f_vrfy verification function + * \param p_vrfy verification parameter + */ +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Set the random number generator callback + * + * \param conf SSL configuration + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * The callback has the following argument: + * void * opaque context for the callback + * int debug level + * const char * file name + * int line number + * const char * message + * + * \param conf SSL configuration + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO callbacks for write, read and + * read-with-timeout. + * + * \param ssl SSL context + * \param p_bio parameter (context) shared by BIO callbacks + * \param f_send write callback + * \param f_recv read callback + * \param f_recv_timeout blocking read callback with timeout. + * The last argument is the timeout in milliseconds, + * 0 means no timeout (block forever until a message comes) + * + * \note One of f_recv or f_recv_timeout can be NULL, in which case + * the other is used. If both are non-NULL, f_recv_timeout is + * used and f_recv is ignored (as if it were NULL). + * + * \note The two most common use cases are: + * - non-blocking I/O, f_recv != NULL, f_recv_timeout == NULL + * - blocking I/O, f_recv == NULL, f_recv_timout != NULL + * + * \note For DTLS, you need to provide either a non-NULL + * f_recv_timeout callback, or a f_recv that doesn't block. + */ +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + int (*f_send)(void *, const unsigned char *, size_t), + int (*f_recv)(void *, unsigned char *, size_t), + int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t) ); + +/** + * \brief Set the timeout period for mbedtls_ssl_read() + * (Default: no timeout.) + * + * \param conf SSL configuration context + * \param timeout Timeout value in milliseconds. + * Use 0 for no timeout (default). + * + * \note With blocking I/O, this will only work if a non-NULL + * \c f_recv_timeout was set with \c mbedtls_ssl_set_bio(). + * With non-blocking I/O, this will only work if timer + * callbacks were set with \c mbedtls_ssl_set_timer_cb(). + * + * \note With non-blocking I/O, you may also skip this function + * altogether and handle timeouts at the application layer. + */ +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ); + +/** + * \brief Set the timer callbacks + * (Mandatory for DTLS.) + * + * \param ssl SSL context + * \param p_timer parameter (context) shared by timer callback + * \param f_set_timer set timer callback + * Accepts an intermediate and a final delay in milliseconcs + * If the final delay is 0, cancels the running timer. + * \param f_get_timer get timer callback. Must return: + * -1 if cancelled + * 0 if none of the delays is expired + * 1 if the intermediate delay only is expired + * 2 if the final delay is expired + */ +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + void (*f_set_timer)(void *, uint32_t int_ms, uint32_t fin_ms), + int (*f_get_timer)(void *) ); + +/** + * \brief Callback type: generate and write session ticket + * + * \note This describes what a callback implementation should do. + * This callback should generate and encrypted and + * authenticated ticket for the session and write it to the + * output buffer. Here, ticket means the opaque ticket part + * of the NewSessionTicket structure of RFC 5077. + * + * \param p_ticket Context for the callback + * \param session SSL session to bo written in the ticket + * \param start Start of the outpur buffer + * \param end End of the output buffer + * \param tlen On exit, holds the length written + * \param lifetime On exit, holds the lifetime of the ticket in seconds + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_ticket_write_t( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *lifetime ); + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Callback type: Export key block and master secret + * + * \note This is required for certain uses of TLS, e.g. EAP-TLS + * (RFC 5216) and Thread. The key pointers are ephemeral and + * therefore must not be stored. The master secret and keys + * should not be used directly except as an input to a key + * derivation function. + * + * \param p_expkey Context for the callback + * \param ms Pointer to master secret (fixed length: 48 bytes) + * \param kb Pointer to key block, see RFC 5246 section 6.3 + * (variable length: 2 * maclen + 2 * keylen + 2 * ivlen). + * \param maclen MAC length + * \param keylen Key length + * \param ivlen IV length + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_keys_t( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \brief Callback type: parse and load session ticket + * + * \note This describes what a callback implementation should do. + * This callback should parse a session ticket as generated + * by the corresponding mbedtls_ssl_ticket_write_t function, + * and, if the ticket is authentic and valid, load the + * session. + * + * \note The implementation is allowed to modify the first len + * bytes of the input buffer, eg to use it as a temporary + * area for the decrypted ticket contents. + * + * \param p_ticket Context for the callback + * \param session SSL session to be loaded + * \param buf Start of the buffer containing the ticket + * \param len Length of the ticket. + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_INVALID_MAC if not authentic, or + * MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED if expired, or + * any other non-zero code for other failures. + */ +typedef int mbedtls_ssl_ticket_parse_t( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ); + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Configure SSL session ticket callbacks (server only). + * (Default: none.) + * + * \note On server, session tickets are enabled by providing + * non-NULL callbacks. + * + * \note On client, use \c mbedtls_ssl_conf_session_tickets(). + * + * \param conf SSL configuration context + * \param f_ticket_write Callback for writing a ticket + * \param f_ticket_parse Callback for parsing a ticket + * \param p_ticket Context shared by the two callbacks + */ +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Configure key export callback. + * (Default: none.) + * + * \note See \c mbedtls_ssl_export_keys_t. + * + * \param conf SSL configuration context + * \param f_export_keys Callback for exporting keys + * \param p_export_keys Context for the callback + */ +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \brief Callback type: generate a cookie + * + * \param ctx Context for the callback + * \param p Buffer to write to, + * must be updated to point right after the cookie + * \param end Pointer to one past the end of the output buffer + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 on success, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_write_t( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *info, size_t ilen ); + +/** + * \brief Callback type: verify a cookie + * + * \param ctx Context for the callback + * \param cookie Cookie to verify + * \param clen Length of cookie + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 if cookie is valid, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_check_t( void *ctx, + const unsigned char *cookie, size_t clen, + const unsigned char *info, size_t ilen ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Register callbacks for DTLS cookies + * (Server only. DTLS only.) + * + * Default: dummy callbacks that fail, in order to force you to + * register working callbacks (and initialize their context). + * + * To disable HelloVerifyRequest, register NULL callbacks. + * + * \warning Disabling hello verification allows your server to be used + * for amplification in DoS attacks against other hosts. + * Only disable if you known this can't happen in your + * particular environment. + * + * \note See comments on \c mbedtls_ssl_handshake() about handling + * the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected + * on the first handshake attempt when this is enabled. + * + * \note This is also necessary to handle client reconnection from + * the same port as described in RFC 6347 section 4.2.8 (only + * the variant with cookies is supported currently). See + * comments on \c mbedtls_ssl_read() for details. + * + * \param conf SSL configuration + * \param f_cookie_write Cookie write callback + * \param f_cookie_check Cookie check callback + * \param p_cookie Context for both callbacks + */ +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ); + +/** + * \brief Set client's transport-level identification info. + * (Server only. DTLS only.) + * + * This is usually the IP address (and port), but could be + * anything identify the client depending on the underlying + * network stack. Used for HelloVerifyRequest with DTLS. + * This is *not* used to route the actual packets. + * + * \param ssl SSL context + * \param info Transport-level info identifying the client (eg IP + port) + * \param ilen Length of info in bytes + * + * \note An internal copy is made, so the info buffer can be reused. + * + * \return 0 on success, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used on client, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if out of memory. + */ +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ); + +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +/** + * \brief Enable or disable anti-replay protection for DTLS. + * (DTLS only, no effect on TLS.) + * Default: enabled. + * + * \param conf SSL configuration + * \param mode MBEDTLS_SSL_ANTI_REPLAY_ENABLED or MBEDTLS_SSL_ANTI_REPLAY_DISABLED. + * + * \warning Disabling this is a security risk unless the application + * protocol handles duplicated packets in a safe way. You + * should not disable this without careful consideration. + * However, if your application already detects duplicated + * packets and needs information about them to adjust its + * transmission strategy, then you'll want to disable this. + */ +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ); +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +/** + * \brief Set a limit on the number of records with a bad MAC + * before terminating the connection. + * (DTLS only, no effect on TLS.) + * Default: 0 (disabled). + * + * \param conf SSL configuration + * \param limit Limit, or 0 to disable. + * + * \note If the limit is N, then the connection is terminated when + * the Nth non-authentic record is seen. + * + * \note Records with an invalid header are not counted, only the + * ones going through the authentication-decryption phase. + * + * \note This is a security trade-off related to the fact that it's + * often relatively easy for an active attacker ot inject UDP + * datagrams. On one hand, setting a low limit here makes it + * easier for such an attacker to forcibly terminated a + * connection. On the other hand, a high limit or no limit + * might make us waste resources checking authentication on + * many bogus packets. + */ +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ); +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/** + * \brief Set retransmit timeout values for the DTLS handshale. + * (DTLS only, no effect on TLS.) + * + * \param conf SSL configuration + * \param min Initial timeout value in milliseconds. + * Default: 1000 (1 second). + * \param max Maximum timeout value in milliseconds. + * Default: 60000 (60 seconds). + * + * \note Default values are from RFC 6347 section 4.2.4.1. + * + * \note Higher values for initial timeout may increase average + * handshake latency. Lower values may increase the risk of + * network congestion by causing more retransmissions. + */ +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the session cache callbacks (server-side only) + * If not set, no session resuming is done (except if session + * tickets are enabled too). + * + * The session cache has the responsibility to check for stale + * entries based on timeout. See RFC 5246 for recommendations. + * + * Warning: session.peer_cert is cleared by the SSL/TLS layer on + * connection shutdown, so do not cache the pointer! Either set + * it to NULL or make a full copy of the certificate. + * + * The get callback is called once during the initial handshake + * to enable session resuming. The get function has the + * following parameters: (void *parameter, mbedtls_ssl_session *session) + * If a valid entry is found, it should fill the master of + * the session object with the cached values and return 0, + * return 1 otherwise. Optionally peer_cert can be set as well + * if it is properly present in cache entry. + * + * The set callback is called once during the initial handshake + * to enable session resuming after the entire handshake has + * been finished. The set function has the following parameters: + * (void *parameter, const mbedtls_ssl_session *session). The function + * should create a cache entry for future retrieval based on + * the data in the session structure and should keep in mind + * that the mbedtls_ssl_session object presented (and all its referenced + * data) is cleared by the SSL/TLS layer when the connection is + * terminated. It is recommended to add metadata to determine if + * an entry is still valid in the future. Return 0 if + * successfully cached, return 1 otherwise. + * + * \param conf SSL configuration + * \param p_cache parmater (context) for both callbacks + * \param f_get_cache session get callback + * \param f_set_cache session set callback + */ +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ); +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Request resumption of session (client-side only) + * Session data is copied from presented session structure. + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid + * + * \sa mbedtls_ssl_get_session() + */ +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Set the list of allowed ciphersuites and the preference + * order. First in the list has the highest preference. + * (Overrides all version specific lists) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * Note: The server uses its own preferences + * over the preference of the client unless + * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined! + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + */ +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ); + +/** + * \brief Set the list of allowed ciphersuites and the + * preference order for a specific version of the protocol. + * (Only useful on the server side) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 + * supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 + * and MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + */ +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the X.509 security profile used for verification + * + * \note The restrictions are enforced for all certificates in the + * chain. However, signatures in the handshake are not covered + * by this setting but by \b mbedtls_ssl_conf_sig_hashes(). + * + * \param conf SSL configuration + * \param profile Profile to use + */ +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ); + +/** + * \brief Set the data required to verify peer certificate + * + * \param conf SSL configuration + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +/** + * \brief Set own certificate chain and private key + * + * \note own_cert should contain in order from the bottom up your + * certificate chain. The top certificate (self-signed) + * can be omitted. + * + * \note On server, this function can be called multiple times to + * provision more than one cert/key pair (eg one ECDSA, one + * RSA with SHA-256, one RSA with SHA-1). An adequate + * certificate will be selected according to the client's + * advertised capabilities. In case mutliple certificates are + * adequate, preference is given to the one set by the first + * call to this function, then second, etc. + * + * \note On client, only the first call has any effect. + * + * \param conf SSL configuration + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +/** + * \brief Set the Pre Shared Key (PSK) and the expected identity name + * + * \note This is mainly useful for clients. Servers will usually + * want to use \c mbedtls_ssl_conf_psk_cb() instead. + * + * \param conf SSL configuration + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * \param psk_identity pointer to the pre-shared key identity + * \param psk_identity_len identity key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ); + + +/** + * \brief Set the Pre Shared Key (PSK) for the current handshake + * + * \note This should only be called inside the PSK callback, + * ie the function passed to \c mbedtls_ssl_conf_psk_cb(). + * + * \param ssl SSL context + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ); + +/** + * \brief Set the PSK callback (server-side only). + * + * If set, the PSK callback is called for each + * handshake where a PSK ciphersuite was negotiated. + * The caller provides the identity received and wants to + * receive the actual PSK data and length. + * + * The callback has the following parameters: (void *parameter, + * mbedtls_ssl_context *ssl, const unsigned char *psk_identity, + * size_t identity_len) + * If a valid PSK identity is found, the callback should use + * \c mbedtls_ssl_set_hs_psk() on the ssl context to set the + * correct PSK and return 0. + * Any other return value will result in a denied PSK identity. + * + * \note If you set a PSK callback using this function, then you + * don't need to set a PSK key and identity using + * \c mbedtls_ssl_conf_psk(). + * + * \param conf SSL configuration + * \param f_psk PSK identity function + * \param p_psk PSK identity parameter + */ +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ); +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * (Default: MBEDTLS_DHM_RFC5114_MODP_2048_[PG]) + * + * \param conf SSL configuration + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param conf SSL configuration + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ); +#endif /* MBEDTLS_DHM_C && defined(MBEDTLS_SSL_SRV_C) */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the minimum length for Diffie-Hellman parameters. + * (Client-side only.) + * (Default: 1024 bits.) + * + * \param conf SSL configuration + * \param bitlen Minimum bit length of the DHM prime + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ); +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Set the allowed curves in order of preference. + * (Default: all defined curves.) + * + * On server: this only affects selection of the ECDHE curve; + * the curves used for ECDH and ECDSA are determined by the + * list of available certificates instead. + * + * On client: this affects the list of curves offered for any + * use. The server can override our preference order. + * + * Both sides: limits the set of curves accepted for use in + * ECDHE and in the peer's end-entity certificate. + * + * \note This has no influence on which curves are allowed inside the + * certificate chains, see \c mbedtls_ssl_conf_cert_profile() + * for that. For the end-entity certificate however, the key + * will be accepted only if it is allowed both by this list + * and by the cert profile. + * + * \note This list should be ordered by decreasing preference + * (preferred curve first). + * + * \param conf SSL configuration + * \param curves Ordered list of allowed curves, + * terminated by MBEDTLS_ECP_DP_NONE. + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curves ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/** + * \brief Set the allowed hashes for signatures during the handshake. + * (Default: all available hashes except MD5.) + * + * \note This only affects which hashes are offered and can be used + * for signatures during the handshake. Hashes for message + * authentication and the TLS PRF are controlled by the + * ciphersuite, see \c mbedtls_ssl_conf_ciphersuites(). Hashes + * used for certificate signature are controlled by the + * verification profile, see \c mbedtls_ssl_conf_cert_profile(). + * + * \note This list should be ordered by decreasing preference + * (preferred hash first). + * + * \param conf SSL configuration + * \param hashes Ordered list of allowed signature hashes, + * terminated by \c MBEDTLS_MD_NONE. + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ); +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set hostname for ServerName TLS extension + * (client-side only) + * + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +/** + * \brief Set own certificate and key for the current handshake + * + * \note Same as \c mbedtls_ssl_conf_own_cert() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); + +/** + * \brief Set the data required to verify peer certificate for the + * current handshake + * + * \note Same as \c mbedtls_ssl_conf_ca_chain() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +/** + * \brief Set authmode for the current handshake. + * + * \note Same as \c mbedtls_ssl_conf_authmode() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param authmode MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL or + * MBEDTLS_SSL_VERIFY_REQUIRED + */ +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ); + +/** + * \brief Set server side ServerName TLS extension callback + * (optional, server-side only). + * + * If set, the ServerName callback is called whenever the + * server receives a ServerName TLS extension from the client + * during a handshake. The ServerName callback has the + * following parameters: (void *parameter, mbedtls_ssl_context *ssl, + * const unsigned char *hostname, size_t len). If a suitable + * certificate is found, the callback must set the + * certificate(s) and key(s) to use with \c + * mbedtls_ssl_set_hs_own_cert() (can be called repeatedly), + * and may optionally adjust the CA and associated CRL with \c + * mbedtls_ssl_set_hs_ca_chain() as well as the client + * authentication mode with \c mbedtls_ssl_set_hs_authmode(), + * then must return 0. If no matching name is found, the + * callback must either set a default cert, or + * return non-zero to abort the handshake at this point. + * + * \param conf SSL configuration + * \param f_sni verification function + * \param p_sni verification parameter + */ +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_sni ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/** + * \brief Set the EC J-PAKE password for current handshake. + * + * \note An internal copy is made, and destroyed as soon as the + * handshake is completed, or when the SSL context is reset or + * freed. + * + * \note The SSL context needs to be already set up. The right place + * to call this function is between \c mbedtls_ssl_setup() or + * \c mbedtls_ssl_reset() and \c mbedtls_ssl_handshake(). + * + * \param ssl SSL context + * \param pw EC J-PAKE password (pre-shared secret) + * \param pw_len length of pw in bytes + * + * \return 0 on success, or a negative error code. + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ); +#endif /*MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +/** + * \brief Set the supported Application Layer Protocols. + * + * \param conf SSL configuration + * \param protos NULL-terminated list of supported protocols, + * in decreasing preference order. + * + * \return 0 on success, or MBEDTLS_ERR_SSL_BAD_INPUT_DATA. + */ +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ); + +/** + * \brief Get the name of the negotiated Application Layer Protocol. + * This function should be called after the handshake is + * completed. + * + * \param ssl SSL context + * + * \return Protcol name, or NULL if no protocol was negotiated. + */ +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_ALPN */ + +/** + * \brief Set the maximum supported version sent from the client side + * and/or accepted at the server side + * (Default: MBEDTLS_SSL_MAX_MAJOR_VERSION, MBEDTLS_SSL_MAX_MINOR_VERSION) + * + * \note This ignores ciphersuites from higher versions. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ); + +/** + * \brief Set the minimum accepted SSL/TLS protocol version + * (Default: TLS 1.0) + * + * \note Input outside of the SSL_MAX_XXXXX_VERSION and + * SSL_MIN_XXXXX_VERSION range is ignored. + * + * \note MBEDTLS_SSL_MINOR_VERSION_0 (SSL v3) should be avoided. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ); + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the fallback flag (client-side only). + * (Default: MBEDTLS_SSL_IS_NOT_FALLBACK). + * + * \note Set to MBEDTLS_SSL_IS_FALLBACK when preparing a fallback + * connection, that is a connection with max_version set to a + * lower value than the value you're willing to use. Such + * fallback connections are not recommended but are sometimes + * necessary to interoperate with buggy (version-intolerant) + * servers. + * + * \warning You should NOT set this to MBEDTLS_SSL_IS_FALLBACK for + * non-fallback connections! This would appear to work for a + * while, then cause failures when the server is upgraded to + * support a newer TLS version. + * + * \param conf SSL configuration + * \param fallback MBEDTLS_SSL_IS_NOT_FALLBACK or MBEDTLS_SSL_IS_FALLBACK + */ +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ); +#endif /* MBEDTLS_SSL_FALLBACK_SCSV && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +/** + * \brief Enable or disable Encrypt-then-MAC + * (Default: MBEDTLS_SSL_ETM_ENABLED) + * + * \note This should always be enabled, it is a security + * improvement, and should not cause any interoperability + * issue (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param etm MBEDTLS_SSL_ETM_ENABLED or MBEDTLS_SSL_ETM_DISABLED + */ +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ); +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +/** + * \brief Enable or disable Extended Master Secret negotiation. + * (Default: MBEDTLS_SSL_EXTENDED_MS_ENABLED) + * + * \note This should always be enabled, it is a security fix to the + * protocol, and should not cause any interoperability issue + * (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param ems MBEDTLS_SSL_EXTENDED_MS_ENABLED or MBEDTLS_SSL_EXTENDED_MS_DISABLED + */ +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ); +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_ARC4_C) +/** + * \brief Disable or enable support for RC4 + * (Default: MBEDTLS_SSL_ARC4_DISABLED) + * + * \warning Use of RC4 in (D)TLS has been prohibited by RFC ???? + * for security reasons. Use at your own risks. + * + * \note This function will likely be removed in future versions as + * RC4 will then be disabled by default at compile time. + * + * \param conf SSL configuration + * \param arc4 MBEDTLS_SSL_ARC4_ENABLED or MBEDTLS_SSL_ARC4_DISABLED + */ +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ); +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Set the maximum fragment length to emit and/or negotiate + * (Default: MBEDTLS_SSL_MAX_CONTENT_LEN, usually 2^14 bytes) + * (Server: set maximum fragment length to emit, + * usually negotiated by the client during handshake + * (Client: set maximum fragment length to emit *and* + * negotiate with the server during handshake) + * + * \param conf SSL configuration + * \param mfl_code Code for maximum fragment length (allowed values: + * MBEDTLS_SSL_MAX_FRAG_LEN_512, MBEDTLS_SSL_MAX_FRAG_LEN_1024, + * MBEDTLS_SSL_MAX_FRAG_LEN_2048, MBEDTLS_SSL_MAX_FRAG_LEN_4096) + * + * \return 0 if successful or MBEDTLS_ERR_SSL_BAD_INPUT_DATA + */ +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +/** + * \brief Activate negotiation of truncated HMAC + * (Default: MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + * + * \param conf SSL configuration + * \param truncate Enable or disable (MBEDTLS_SSL_TRUNC_HMAC_ENABLED or + * MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + */ +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ); +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +/** + * \brief Enable / Disable 1/n-1 record splitting + * (Default: MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED) + * + * \note Only affects SSLv3 and TLS 1.0, not higher versions. + * Does not affect non-CBC ciphersuites in any version. + * + * \param conf SSL configuration + * \param split MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED or + * MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED + */ +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ); +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Enable / Disable session tickets (client only). + * (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.) + * + * \note On server, use \c mbedtls_ssl_conf_session_tickets_cb(). + * + * \param conf SSL configuration + * \param use_tickets Enable or disable (MBEDTLS_SSL_SESSION_TICKETS_ENABLED or + * MBEDTLS_SSL_SESSION_TICKETS_DISABLED) + */ +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enable / Disable renegotiation support for connection when + * initiated by peer + * (Default: MBEDTLS_SSL_RENEGOTIATION_DISABLED) + * + * \warning It is recommended to always disable renegotation unless you + * know you need it and you know what you're doing. In the + * past, there has been several issues associated with + * renegotiation or a poor understanding of its properties. + * + * \note Server-side, enabling renegotiation also makes the server + * susceptible to a resource DoS by a malicious client. + * + * \param conf SSL configuration + * \param renegotiation Enable or disable (MBEDTLS_SSL_RENEGOTIATION_ENABLED or + * MBEDTLS_SSL_RENEGOTIATION_DISABLED) + */ +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Prevent or allow legacy renegotiation. + * (Default: MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION) + * + * MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION allows connections to + * be established even if the peer does not support + * secure renegotiation, but does not allow renegotiation + * to take place if not secure. + * (Interoperable and secure option) + * + * MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION allows renegotiations + * with non-upgraded peers. Allowing legacy renegotiation + * makes the connection vulnerable to specific man in the + * middle attacks. (See RFC 5746) + * (Most interoperable and least secure option) + * + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE breaks off connections + * if peer does not support secure renegotiation. Results + * in interoperability issues with non-upgraded peers + * that do not support renegotiation altogether. + * (Most secure option, interoperability issues) + * + * \param conf SSL configuration + * \param allow_legacy Prevent or allow (SSL_NO_LEGACY_RENEGOTIATION, + * SSL_ALLOW_LEGACY_RENEGOTIATION or + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE) + */ +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enforce renegotiation requests. + * (Default: enforced, max_records = 16) + * + * When we request a renegotiation, the peer can comply or + * ignore the request. This function allows us to decide + * whether to enforce our renegotiation requests by closing + * the connection if the peer doesn't comply. + * + * However, records could already be in transit from the peer + * when the request is emitted. In order to increase + * reliability, we can accept a number of records before the + * expected handshake records. + * + * The optimal value is highly dependent on the specific usage + * scenario. + * + * \note With DTLS and server-initiated renegotiation, the + * HelloRequest is retransmited every time mbedtls_ssl_read() times + * out or receives Application Data, until: + * - max_records records have beens seen, if it is >= 0, or + * - the number of retransmits that would happen during an + * actual handshake has been reached. + * Please remember the request might be lost a few times + * if you consider setting max_records to a really low value. + * + * \warning On client, the grace period can only happen during + * mbedtls_ssl_read(), as opposed to mbedtls_ssl_write() and mbedtls_ssl_renegotiate() + * which always behave as if max_record was 0. The reason is, + * if we receive application data from the server, we need a + * place to write it, which only happens during mbedtls_ssl_read(). + * + * \param conf SSL configuration + * \param max_records Use MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED if you don't want to + * enforce renegotiation, or a non-negative value to enforce + * it but allow for a grace period of max_records records. + */ +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ); + +/** + * \brief Set record counter threshold for periodic renegotiation. + * (Default: 2^64 - 256.) + * + * Renegotiation is automatically triggered when a record + * counter (outgoing or ingoing) crosses the defined + * threshold. The default value is meant to prevent the + * connection from being closed when the counter is about to + * reached its maximal value (it is not allowed to wrap). + * + * Lower values can be used to enforce policies such as "keys + * must be refreshed every N packets with cipher X". + * + * \param conf SSL configuration + * \param period The threshold value: a big-endian 64-bit number. + * Set to 2^64 - 1 to disable periodic renegotiation + */ +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, + * -1 if result is not available (eg because the handshake was + * aborted too early), or + * a combination of BADCERT_xxx and BADCRL_xxx flags, see + * x509.h + */ +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the name of the current ciphersuite + * + * \param ssl SSL context + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the current SSL version (SSLv3/TLSv1/etc) + * + * \param ssl SSL context + * + * \return a string containing the SSL version + */ +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the (maximum) number of bytes added by the record + * layer: header + encryption/MAC overhead (inc. padding) + * + * \param ssl SSL context + * + * \return Current maximum record expansion in bytes, or + * MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE if compression is + * enabled, which makes expansion much less predictable + */ +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Return the maximum fragment length (payload, in bytes). + * This is the value negotiated with peer if any, + * or the locally configured value. + * + * \note With DTLS, \c mbedtls_ssl_write() will return an error if + * called with a larger length value. + * With TLS, \c mbedtls_ssl_write() will fragment the input if + * necessary and return the number of bytes written; it is up + * to the caller to call \c mbedtls_ssl_write() again in + * order to send the remaining bytes if any. + * + * \param ssl SSL context + * + * \return Current maximum fragment length. + */ +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Return the peer certificate from the current connection + * + * Note: Can be NULL in case no certificate was sent during + * the handshake. Different calls for the same connection can + * return the same or different pointers for the same + * certificate and even a different certificate altogether. + * The peer cert CAN change in a single connection if + * renegotiation is performed. + * + * \param ssl SSL context + * + * \return the current peer certificate + */ +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Save session in order to resume it later (client-side only) + * Session data is copied to presented session structure. + * + * \warning Currently, peer certificate is lost in the operation. + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid + * + * \sa mbedtls_ssl_set_session() + */ +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or + * a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note If DTLS is in use, then you may choose to handle + * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging + * purposes, as it is an expected return value rather than an + * actual error, but you still need to reset/free the context. + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ); + +/** + * \brief Perform a single step of the SSL handshake + * + * \note The state of the context (ssl->state) will be at + * the following state after execution of this function. + * Do not call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \param ssl SSL context + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * a specific SSL error code. + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Initiate an SSL renegotiation on the running connection. + * Client: perform the renegotiation right now. + * Server: request renegotiation, which will be performed + * during the next call to mbedtls_ssl_read() if honored by client. + * + * \param ssl SSL context + * + * \return 0 if successful, or any mbedtls_ssl_handshake() return value. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len maximum number of bytes to read + * + * \return the number of bytes read, or + * 0 for EOF, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or + * another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * (which can only happen server-side), it means that a client + * is initiating a new connection using the same source port. + * You can either treat that as a connection close and wait + * for the client to resend a ClientHello, or directly + * continue with \c mbedtls_ssl_handshake() with the same + * context (as it has beeen reset internally). Either way, you + * should make sure this is seen by the application as a new + * connection: application state, if any, should be reset, and + * most importantly the identity of the client must be checked + * again. WARNING: not validating the identity of the client + * again, or not transmitting the new identity to the + * application layer, would allow authentication bypass! + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ); + +/** + * \brief Try to write exactly 'len' application data bytes + * + * \warning This function will do partial writes in some cases. If the + * return value is non-negative but less than length, the + * function must be called again with updated arguments: + * buf + ret, len - ret (if ret is the return value) until + * it returns a value equal to the last 'len' argument. + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return the number of bytes actually written (may be less than len), + * or MBEDTLS_ERR_SSL_WANT_WRITE of MBEDTLS_ERR_SSL_WANT_READ, + * or another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, + * it must be called later with the *same* arguments, + * until it returns a positive value. + * + * \note If the requested length is greater than the maximum + * fragment length (either the built-in limit or the one set + * or negotiated with the peer), then: + * - with TLS, less bytes than requested are written. + * - with DTLS, MBEDTLS_ERR_SSL_BAD_INPUT_DATA is returned. + * \c mbedtls_ssl_get_max_frag_len() may be used to query the + * active maximum fragment length. + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ); + +/** + * \brief Send an alert message + * + * \param ssl SSL context + * \param level The alert level of the message + * (MBEDTLS_SSL_ALERT_LEVEL_WARNING or MBEDTLS_SSL_ALERT_LEVEL_FATAL) + * \param message The alert message (SSL_ALERT_MSG_*) + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ); +/** + * \brief Notify the peer that the connection is being closed + * + * \param ssl SSL context + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ); + +/** + * \brief Free referenced items in an SSL context and clear memory + * + * \param ssl SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ); + +/** + * \brief Initialize an SSL configuration context + * Just makes the context ready for + * mbedtls_ssl_config_defaults() or mbedtls_ssl_config_free(). + * + * \note You need to call mbedtls_ssl_config_defaults() unless you + * manually set all of the relevent fields yourself. + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ); + +/** + * \brief Load reasonnable default SSL configuration values. + * (You need to call mbedtls_ssl_config_init() first.) + * + * \param conf SSL configuration context + * \param endpoint MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + * \param transport MBEDTLS_SSL_TRANSPORT_STREAM for TLS, or + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS + * \param preset a MBEDTLS_SSL_PRESET_XXX value + * (currently unused). + * + * \note See \c mbedtls_ssl_conf_transport() for notes on DTLS. + * + * \return 0 if successful, or + * MBEDTLS_ERR_XXX_ALLOC_FAILED on memory allocation error. + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ); + +/** + * \brief Free an SSL configuration context + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ); + +/** + * \brief Initialize SSL session structure + * + * \param session SSL session + */ +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ); + +/** + * \brief Free referenced items in an SSL session including the + * peer certificate and clear memory + * + * \param session SSL session + */ +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cache.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cache.h new file mode 100644 index 0000000000..1155924a92 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cache.h @@ -0,0 +1,143 @@ +/** + * \file ssl_cache.h + * + * \brief SSL session cache implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CACHE_H +#define MBEDTLS_SSL_CACHE_H + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT) +#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /*!< 1 day */ +#endif + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES) +#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /*!< Maximum entries in cache */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mbedtls_ssl_cache_context mbedtls_ssl_cache_context; +typedef struct mbedtls_ssl_cache_entry mbedtls_ssl_cache_entry; + +/** + * \brief This structure is used for storing cache entries + */ +struct mbedtls_ssl_cache_entry +{ +#if defined(MBEDTLS_HAVE_TIME) + time_t timestamp; /*!< entry timestamp */ +#endif + mbedtls_ssl_session session; /*!< entry session */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_buf peer_cert; /*!< entry peer_cert */ +#endif + mbedtls_ssl_cache_entry *next; /*!< chain pointer */ +}; + +/** + * \brief Cache context + */ +struct mbedtls_ssl_cache_context +{ + mbedtls_ssl_cache_entry *chain; /*!< start of the chain */ + int timeout; /*!< cache entry timeout */ + int max_entries; /*!< maximum entries */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +}; + +/** + * \brief Initialize an SSL cache context + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ); + +/** + * \brief Cache get callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to retrieve entry for + */ +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ); + +/** + * \brief Cache set callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to store entry for + */ +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ); + +#if defined(MBEDTLS_HAVE_TIME) +/** + * \brief Set the cache timeout + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT (1 day)) + * + * A timeout of 0 indicates no timeout. + * + * \param cache SSL cache context + * \param timeout cache entry timeout in seconds + */ +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ); +#endif /* MBEDTLS_HAVE_TIME */ + +/** + * \brief Set the maximum number of cache entries + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES (50)) + * + * \param cache SSL cache context + * \param max cache entry maximum + */ +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ); + +/** + * \brief Free referenced items in a cache context and clear memory + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cache.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ciphersuites.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ciphersuites.h new file mode 100644 index 0000000000..deaaa37515 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ciphersuites.h @@ -0,0 +1,321 @@ +/** + * \file ssl_ciphersuites.h + * + * \brief SSL Ciphersuites for mbed TLS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CIPHERSUITES_H +#define MBEDTLS_SSL_CIPHERSUITES_H + +#include "pk.h" +#include "cipher.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Supported ciphersuites (Official IANA names) + */ +#define MBEDTLS_TLS_RSA_WITH_NULL_MD5 0x01 /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA 0x02 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 0x04 +#define MBEDTLS_TLS_RSA_WITH_RC4_128_SHA 0x05 +#define MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA 0x09 /**< Weak! Not in TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x0A + +#define MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA 0x15 /**< Weak! Not in TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x16 + +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA 0x2C /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA 0x2D /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA 0x2E /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA 0x2F + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x33 +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA 0x35 +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x39 + +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA256 0x3B /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 0x3C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 0x3D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x41 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x45 + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x67 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x6B /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x84 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x88 + +#define MBEDTLS_TLS_PSK_WITH_RC4_128_SHA 0x8A +#define MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA 0x8B +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA 0x8C +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA 0x8D + +#define MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA 0x8E +#define MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA 0x8F +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x90 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x91 + +#define MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA 0x92 +#define MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA 0x93 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA 0x94 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA 0x95 + +#define MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 0x9C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 0x9D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x9E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x9F /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 0xA8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 0xA9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 0xAA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 0xAB /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 0xAC /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 0xAD /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 0xAE +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 0xAF +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA256 0xB0 /**< Weak! */ +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA384 0xB1 /**< Weak! */ + +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 0xB2 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 0xB3 +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 0xB4 /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 0xB5 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 0xB6 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 0xB7 +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 0xB8 /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 0xB9 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBE /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC4 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 /**< Weak! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B /**< Weak! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA 0xC033 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA 0xC034 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xC035 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xC036 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0xC037 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0xC038 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA 0xC039 /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 0xC03A /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 0xC03B /**< Weak! No SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC074 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC075 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC076 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC077 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC078 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC079 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07A /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07B /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07C /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC086 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC087 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC088 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC089 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08A /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC08E /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC08F /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC090 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC091 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC092 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC093 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC094 +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC095 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC096 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC097 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC098 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC099 +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC09A /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC09B /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM 0xC09C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM 0xC09D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM 0xC09E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM 0xC09F /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 0xC0A2 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 0xC0A3 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM 0xC0A4 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM 0xC0A5 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM 0xC0A6 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM 0xC0A7 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 0xC0A8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 0xC0A9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 0xC0AA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 0xC0AB /**< TLS 1.2 */ +/* The last two are named with PSK_DHE in the RFC, which looks like a typo */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 0xC0FF /**< experimental */ + +/* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. + * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below + */ +typedef enum { + MBEDTLS_KEY_EXCHANGE_NONE = 0, + MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_KEY_EXCHANGE_ECJPAKE, +} mbedtls_key_exchange_type_t; + +/* Key exchanges using a certificate */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#endif + +/* Key exchanges using a PSK */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#endif + +/* Key exchanges using a ECDHE */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#endif + +typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t; + +#define MBEDTLS_CIPHERSUITE_WEAK 0x01 /**< Weak ciphersuite flag */ +#define MBEDTLS_CIPHERSUITE_SHORT_TAG 0x02 /**< Short authentication tag, + eg for CCM_8 */ +#define MBEDTLS_CIPHERSUITE_NODTLS 0x04 /**< Can't be used with DTLS */ + +/** + * \brief This structure is used for storing ciphersuite information + */ +struct mbedtls_ssl_ciphersuite_t +{ + int id; + const char * name; + + mbedtls_cipher_type_t cipher; + mbedtls_md_type_t mac; + mbedtls_key_exchange_type_t key_exchange; + + int min_major_ver; + int min_minor_ver; + int max_major_ver; + int max_minor_ver; + + unsigned char flags; +}; + +const int *mbedtls_ssl_list_ciphersuites( void ); + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ); +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id ); + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ); +#endif + +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ); +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ciphersuites.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cookie.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cookie.h new file mode 100644 index 0000000000..037e1c3112 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_cookie.h @@ -0,0 +1,108 @@ +/** + * \file ssl_cookie.h + * + * \brief DTLS cookie callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_COOKIE_H +#define MBEDTLS_SSL_COOKIE_H + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ +#ifndef MBEDTLS_SSL_COOKIE_TIMEOUT +#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Context for the default cookie functions. + */ +typedef struct +{ + mbedtls_md_context_t hmac_ctx; /*!< context for the HMAC portion */ +#if !defined(MBEDTLS_HAVE_TIME) + unsigned long serial; /*!< serial number for expiration */ +#endif + unsigned long timeout; /*!< timeout delay, in seconds if HAVE_TIME, + or in number of tickets issued */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_ssl_cookie_ctx; + +/** + * \brief Initialize cookie context + */ +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Setup cookie context (generate keys) + */ +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set expiration delay for cookies + * (Default MBEDTLS_SSL_COOKIE_TIMEOUT) + * + * \param ctx Cookie contex + * \param delay Delay, in seconds if HAVE_TIME, or in number of cookies + * issued in the meantime. + * 0 to disable expiration (NOT recommended) + */ +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ); + +/** + * \brief Free cookie context + */ +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Generate cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_write_t mbedtls_ssl_cookie_write; + +/** + * \brief Verify cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_check_t mbedtls_ssl_cookie_check; + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cookie.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_internal.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_internal.h new file mode 100644 index 0000000000..3af059f89e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_internal.h @@ -0,0 +1,495 @@ +/** + * \file ssl_ticket.h + * + * \brief Internal functions shared by the SSL modules + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_INTERNAL_H +#define MBEDTLS_SSL_INTERNAL_H + +#include "ssl.h" + +#if defined(MBEDTLS_MD5_C) +#include "md5.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "sha512.h" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#include "ecjpake.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Determine minimum supported version */ +#define MBEDTLS_SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +/* Determine maximum supported version */ +#define MBEDTLS_SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#define MBEDTLS_SSL_INITIAL_HANDSHAKE 0 +#define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS 1 /* In progress */ +#define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ +#define MBEDTLS_SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ + +/* + * DTLS retransmission states, see RFC 6347 4.2.4 + * + * The SENDING state is merged in PREPARING for initial sends, + * but is distinct for resends. + * + * Note: initial state is wrong for server, but is not used anyway. + */ +#define MBEDTLS_SSL_RETRANS_PREPARING 0 +#define MBEDTLS_SSL_RETRANS_SENDING 1 +#define MBEDTLS_SSL_RETRANS_WAITING 2 +#define MBEDTLS_SSL_RETRANS_FINISHED 3 + +/* + * Allow extra bytes for record, authentication and encryption overhead: + * counter (8) + header (5) + IV(16) + MAC (16-48) + padding (0-256) + * and allow for a maximum of 1024 of compression expansion if + * enabled. + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) +#define MBEDTLS_SSL_COMPRESSION_ADD 1024 +#else +#define MBEDTLS_SSL_COMPRESSION_ADD 0 +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_MODE_CBC) +/* Ciphersuites using HMAC */ +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_SSL_MAC_ADD 48 /* SHA-384 used for HMAC */ +#elif defined(MBEDTLS_SHA256_C) +#define MBEDTLS_SSL_MAC_ADD 32 /* SHA-256 used for HMAC */ +#else +#define MBEDTLS_SSL_MAC_ADD 20 /* SHA-1 used for HMAC */ +#endif +#else +/* AEAD ciphersuites: GCM and CCM use a 128 bits tag */ +#define MBEDTLS_SSL_MAC_ADD 16 +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_SSL_PADDING_ADD 256 +#else +#define MBEDTLS_SSL_PADDING_ADD 0 +#endif + +#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ + ) + +/* + * TLS extension flags (for extensions with outgoing ServerHello content + * that need it (e.g. for RENEGOTIATION_INFO the server already knows because + * of state of the renegotiation flag, so no indicator is required) + */ +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT (1 << 0) +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK (1 << 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure contains the parameters only needed during handshake. + */ +struct mbedtls_ssl_handshake_params +{ + /* + * Handshake specific crypto variables + */ + int sig_alg; /*!< Hash algorithm for signature */ + int cert_type; /*!< Requested cert type */ + int verify_sig_alg; /*!< Signature algorithm for verify */ +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_context dhm_ctx; /*!< DHM key exchange */ +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_context ecjpake_ctx; /*!< EC J-PAKE key exchange */ +#if defined(MBEDTLS_SSL_CLI_C) + unsigned char *ecjpake_cache; /*!< Cache for ClientHello ext */ + size_t ecjpake_cache_len; /*!< Length of cached data */ +#endif +#endif +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + const mbedtls_ecp_curve_info **curves; /*!< Supported elliptic curves */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + unsigned char *psk; /*!< PSK from the callback */ + size_t psk_len; /*!< Length of PSK from callback */ +#endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + int sni_authmode; /*!< authmode from SNI callback */ + mbedtls_ssl_key_cert *sni_key_cert; /*!< key/cert list from SNI */ + mbedtls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ + mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ +#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ + unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ + + unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie + Srv: unused */ + unsigned char verify_cookie_len; /*!< Cli: cookie length + Srv: flag for sending a cookie */ + + unsigned char *hs_msg; /*!< Reassembled handshake message */ + + uint32_t retransmit_timeout; /*!< Current value of timeout */ + unsigned char retransmit_state; /*!< Retransmission state */ + mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ + mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + unsigned int in_flight_start_seq; /*!< Minimum message sequence in the + flight being received */ + mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for + resending messages */ + unsigned char alt_out_ctr[8]; /*!< Alternative record epoch/counter + for resending messages */ +#endif + + /* + * Checksum contexts + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_context fin_md5; + mbedtls_sha1_context fin_sha1; +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_context fin_sha256; +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context fin_sha512; +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); + void (*calc_verify)(mbedtls_ssl_context *, unsigned char *); + void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); + int (*tls_prf)(const unsigned char *, size_t, const char *, + const unsigned char *, size_t, + unsigned char *, size_t); + + size_t pmslen; /*!< premaster length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; + /*!< premaster secret */ + + int resume; /*!< session resume indicator*/ + int max_major_ver; /*!< max. major version client*/ + int max_minor_ver; /*!< max. minor version client*/ + int cli_exts; /*!< client extension presence*/ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + int new_session_ticket; /*!< use NewSessionTicket? */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + int extended_ms; /*!< use Extended Master Secret? */ +#endif +}; + +/* + * This structure contains a full set of runtime transform parameters + * either in negotiation or active. + */ +struct mbedtls_ssl_transform +{ + /* + * Session specific crypto layer + */ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + /*!< Chosen cipersuite_info */ + unsigned int keylen; /*!< symmetric key length (bytes) */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t fixed_ivlen; /*!< Fixed part of IV (AEAD) */ + size_t maclen; /*!< MAC length */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* Needed only for SSL v3.0 secret */ + unsigned char mac_enc[20]; /*!< SSL v3.0 secret (enc) */ + unsigned char mac_dec[20]; /*!< SSL v3.0 secret (dec) */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + + mbedtls_md_context_t md_ctx_enc; /*!< MAC (encryption) */ + mbedtls_md_context_t md_ctx_dec; /*!< MAC (decryption) */ + + mbedtls_cipher_context_t cipher_ctx_enc; /*!< encryption context */ + mbedtls_cipher_context_t cipher_ctx_dec; /*!< decryption context */ + + /* + * Session specific compression layer + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif +}; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * List of certificate + private key pairs + */ +struct mbedtls_ssl_key_cert +{ + mbedtls_x509_crt *cert; /*!< cert */ + mbedtls_pk_context *key; /*!< private key */ + mbedtls_ssl_key_cert *next; /*!< next key/cert pair */ +}; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * List of handshake messages kept around for resending + */ +struct mbedtls_ssl_flight_item +{ + unsigned char *p; /*!< message, including handshake headers */ + size_t len; /*!< length of p */ + unsigned char type; /*!< type of the message: handshake or CCS */ + mbedtls_ssl_flight_item *next; /*!< next handshake message(s) */ +}; +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + +/** + * \brief Free referenced items in an SSL transform context and clear + * memory + * + * \param transform SSL transform context + */ +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); + +/** + * \brief Free referenced items in an SSL handshake context and clear + * memory + * + * \param handshake SSL handshake context + */ +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ); + +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); + +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ); +#endif + +#if defined(MBEDTLS_PK_C) +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ); +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ); +#endif + +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ); +unsigned char mbedtls_ssl_hash_from_md_alg( int md ); + +#if defined(MBEDTLS_ECP_C) +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static inline mbedtls_pk_context *mbedtls_ssl_own_key( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->key ); +} + +static inline mbedtls_x509_crt *mbedtls_ssl_own_cert( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->cert ); +} + +/* + * Check usage of a certificate wrt extensions: + * keyUsage, extendedKeyUsage (later), and nSCertType (later). + * + * Warning: cert_endpoint is the endpoint of the cert (ie, of our peer when we + * check a cert we received from them)! + * + * Return 0 if everything is OK, -1 if not. + */ +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ); +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ); + +static inline size_t mbedtls_ssl_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 13 ); +#else + ((void) ssl); +#endif + return( 5 ); +} + +static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 12 ); +#else + ((void) ssl); +#endif + return( 4 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ); +#endif + +/* Visible for testing purposes only */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); +#endif + +/* constant-time buffer comparison */ +static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + const unsigned char *A = (const unsigned char *) a; + const unsigned char *B = (const unsigned char *) b; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= A[i] ^ B[i]; + + return( diff ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_internal.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ticket.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ticket.h new file mode 100644 index 0000000000..7c6bc61bfb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/ssl_ticket.h @@ -0,0 +1,135 @@ +/** + * \file ssl_ticket.h + * + * \brief TLS server ticket callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_TICKET_H +#define MBEDTLS_SSL_TICKET_H + +/* + * This implementation of the session ticket callbacks includes key + * management, rotating the keys periodically in order to preserve forward + * secrecy, when MBEDTLS_HAVE_TIME is defined. + */ + +#include "ssl.h" +#include "cipher.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Information for session ticket protection + */ +typedef struct +{ + unsigned char name[4]; /*!< random key identifier */ + uint32_t generation_time; /*!< key generation timestamp (seconds) */ + mbedtls_cipher_context_t ctx; /*!< context for auth enc/decryption */ +} +mbedtls_ssl_ticket_key; + +/** + * \brief Context for session ticket handling functions + */ +typedef struct +{ + mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ + unsigned char active; /*!< index of the currently active key */ + + uint32_t ticket_lifetime; /*!< lifetime of tickets in seconds */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ssl_ticket_context; + +/** + * \brief Initialize a ticket context. + * (Just make it ready for mbedtls_ssl_ticket_setup() + * or mbedtls_ssl_ticket_free().) + * + * \param ctx Context to be initialized + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ); + +/** + * \brief Prepare context to be actually used + * + * \param ctx Context to be set up + * \param f_rng RNG callback function + * \param p_rng RNG callback context + * \param cipher AEAD cipher to use for ticket protection. + * Recommended value: MBEDTLS_CIPHER_AES_256_GCM. + * \param lifetime Tickets lifetime in seconds + * Recommended value: 86400 (one day). + * + * \note It is highly recommended to select a cipher that is at + * least as strong as the the strongest ciphersuite + * supported. Usually that means a 256-bit key. + * + * \note The lifetime of the keys is twice the lifetime of tickets. + * It is recommended to pick a reasonnable lifetime so as not + * to negate the benefits of forward secrecy. + * + * \return 0 if successful, + * or a specific MBEDTLS_ERR_XXX error code + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ); + +/** + * \brief Implementation of the ticket write callback + * + * \note See \c mbedlts_ssl_ticket_write_t for description + */ +mbedtls_ssl_ticket_write_t mbedtls_ssl_ticket_write; + +/** + * \brief Implementation of the ticket parse callback + * + * \note See \c mbedlts_ssl_ticket_parse_t for description + */ +mbedtls_ssl_ticket_parse_t mbedtls_ssl_ticket_parse; + +/** + * \brief Free a context's content and zeroize it. + * + * \param ctx Context to be cleaned up + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ticket.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/espconn_mbedtls.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/espconn_mbedtls.h new file mode 100644 index 0000000000..c0d7026f44 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/espconn_mbedtls.h @@ -0,0 +1,278 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef ESPCONN_MBEDTLS_H_ +#define ESPCONN_MBEDTLS_H_ + +#include "lwip/ip.h" +#include "lwip/app/espconn.h" +#include "user_interface.h" + +#if !defined(ESPCONN_MBEDTLS) + +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +typedef struct espconn *pmbedtls_espconn; +typedef struct espconn mbedtls_espconn; +typedef struct{ + int record_len; +}mbedtls_record; + +#if defined(ESP8266_PLATFORM) +typedef struct{ + uint8* finished_buf; + int finished_len; +}mbedtls_finished, *pmbedtls_finished; +#endif + +typedef struct{ +// mbedtls_entropy_context entropy; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_pk_context pkey; +}mbedtls_session, *pmbedtls_session; + +typedef struct{ + bool quiet; + mbedtls_record record; +#if defined(ESP8266_PLATFORM) + pmbedtls_finished pfinished; +#endif + pmbedtls_session psession; + mbedtls_net_context fd; + mbedtls_net_context listen_fd; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_entropy_context entropy; + + bool SentFnFlag; + sint32 verify_result; +}mbedtls_msg, *pmbedtls_msg; + +typedef enum { + ESPCONN_CERT_OWN, + ESPCONN_CERT_AUTH, + ESPCONN_PK, + ESPCONN_PASSWORD +}mbedtls_auth_type; + +typedef enum { + ESPCONN_IDLE = 0, + ESPCONN_CLIENT, + ESPCONN_SERVER, + ESPCONN_BOTH, + ESPCONN_MAX +}espconn_level; + +typedef struct _file_head{ + char file_name[32]; + uint16_t file_length; +}file_head; + +typedef struct _file_param{ + file_head file_head; + int32 file_offerset; +}file_param; + +typedef struct _ssl_sector{ + uint32 sector; + bool flag; +}ssl_sector; + +struct ssl_packet{ + uint8* pbuffer; + uint16 buffer_size; + ssl_sector cert_ca_sector; + ssl_sector cert_req_sector; +}; + +typedef struct _ssl_opt { + struct ssl_packet server; + struct ssl_packet client; + uint8 type; +}ssl_opt; + +typedef struct{ + mbedtls_auth_type auth_type; + espconn_level auth_level; +}mbedtls_auth_info; + +#define SSL_KEEP_INTVL 1 +#define SSL_KEEP_CNT 5 +#define SSL_KEEP_IDLE 90 + +#define ssl_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) +#define ssl_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) + +enum { + SIG_ESPCONN_TLS_ERRER = 0x3B +}; + +#define ESPCONN_SECURE_MAX_SIZE 8192 +#define ESPCONN_SECURE_DEFAULT_HEAP 0x3800 +#define ESPCONN_SECURE_DEFAULT_SIZE 0x0800 +#define ESPCONN_HANDSHAKE_TIMEOUT 0x3C +#define ESPCONN_INVALID_TYPE 0xFFFFFFFF +#define MBEDTLS_SSL_PLAIN_ADD TCP_MSS +#define FLASH_SECTOR_SIZE 4096 + +extern ssl_opt ssl_option; + +typedef struct{ + uint32 parame_sec; + uint32 parame_type; + uint32 parame_datalen; + char* parame_data; +}mbedtls_parame, *pmbedtls_parame; + +/* +* Storage format identifiers +* Recognized formats: PEM and DER +*/ +typedef enum{ + ESPCONN_FORMAT_INIT = 0, + ESPCONN_FORMAT_DER = 1, + ESPCONN_FORMAT_PEM = 2, + ESPCONN_FORMAT_INVALID +}espconn_format; + +#define ESPCONN_EVENT_RECV(pcb,p,err) \ + do { \ + if((pcb)!= NULL && (pcb)->recv_callback != NULL) { \ + (pcb)->state = ESPCONN_READ; \ + (pcb)->recv_callback((pcb),(p),(err));\ + (pcb)->state = ESPCONN_CONNECT; \ + } else { \ + ESP_LOG("%s %d\n", __FILE__, __LINE__); \ + } \ + } while (0) + +#define ESPCONN_EVENT_SEND(pcb) \ + do { \ + if((pcb)!= NULL && (pcb)->sent_callback != NULL) { \ + (pcb)->state = ESPCONN_CONNECT; \ + (pcb)->sent_callback(pcb);\ + } else { \ + ESP_LOG("%s %d\n", __FILE__, __LINE__); \ + } \ + } while (0) + +#define ESPCONN_EVENT_CONNECTED(pcb) \ + do { \ + if((pcb)!= NULL && (pcb)->proto.tcp != NULL && (pcb)->proto.tcp->connect_callback != NULL) { \ + (pcb)->state = ESPCONN_CONNECT; \ + (pcb)->proto.tcp->connect_callback(pcb);\ + } else { \ + ESP_LOG("%s %d\n", __FILE__, __LINE__); \ + } \ + } while (0) + +#define ESPCONN_EVENT_CLOSED(pcb) \ + do { \ + if((pcb)!= NULL && (pcb)->proto.tcp != NULL && (pcb)->proto.tcp->disconnect_callback != NULL) { \ + (pcb)->state = ESPCONN_CLOSE; \ + (pcb)->proto.tcp->disconnect_callback(pcb);\ + } else { \ + ESP_LOG("%s %d\n", __FILE__, __LINE__); \ + } \ + } while (0) + +#define ESPCONN_EVENT_ERROR(pcb,err) \ + do { \ + if((pcb)!= NULL && (pcb)->proto.tcp != NULL && (pcb)->proto.tcp->reconnect_callback != NULL) { \ + (pcb)->state = ESPCONN_CLOSE; \ + (pcb)->proto.tcp->reconnect_callback(pcb,err);\ + } else { \ + ESP_LOG("%s %d\n", __FILE__, __LINE__); \ + } \ + } while (0) + +/****************************************************************************** + * FunctionName : mbedtls_load_default_obj + * Description : Initialize the server: set up a listen PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ +bool mbedtls_load_default_obj(uint32 flash_sector, int obj_type, const unsigned char *load_buf, uint16 length); + +/****************************************************************************** + * FunctionName : sslserver_start + * Description : Initialize the server: set up a listen PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_ssl_server(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_ssl_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_ssl_client(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_ssl_write + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ + +extern void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_ssl_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_ssl_disconnect(espconn_msg *pdis); + +/****************************************************************************** + * FunctionName : espconn_secure_get_size + * Description : get buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : buffer size for client or server +*******************************************************************************/ + +extern sint16 espconn_secure_get_size(uint8 level); + +#endif + + + +#endif /* ESPCONN_MBEDTLS_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/socket.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/socket.h new file mode 100644 index 0000000000..eb1a9aac4c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/sys/socket.h @@ -0,0 +1,343 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef ESP_SOCKET_H_ +#define ESP_SOCKET_H_ + +#include "lwip/inet.h" +#include "lwip/opt.h" +#include "lwip/app/espconn_buf.h" + +#if 0 +#define ESP_LOG os_printf +#else +#define ESP_LOG(...) +#endif + +#define NUM_SOCKETS 3 + +#define ESP_OK 0 /* No error, everything OK. */ +#define ESP_MEM -1 /* Out of memory error. */ +#define ESP_TIMEOUT -3 /* Timeout. */ +#define ESP_RTE -4 /* Routing problem. */ +#define ESP_INPROGRESS -5 /* Operation in progress */ +#define ESP_MAXNUM -7 /* Total number exceeds the set maximum*/ + +#define ESP_ABRT -8 /* Connection aborted. */ +#define ESP_RST -9 /* Connection reset. */ +#define ESP_CLSD -10 /* Connection closed. */ +#define ESP_CONN -11 /* Not connected. */ + +#define ESP_ARG -12 /* Illegal argument. */ +#define ESP_IF -14 /* Low_level error */ +#define ESP_ISCONN -15 /* Already connected. */ + +typedef enum{ + NETCONN_STATE_NONE = 0, + NETCONN_STATE_ESTABLISHED, + NETCONN_STATE_WRITE, + NETCONN_STATE_READ, + NETCONN_STATE_CLOSED, + NETCONN_STATE_ERROR, + NETCONN_STATE_SUMNUM +}netconn_state; + +#if (!defined(lwIP_unlikely)) +#define lwIP_unlikely(Expression) !!(Expression) +#endif + +#define lwIP_ASSERT(Expression) do{if (!(Expression)) ESP_LOG("%d\n", __LINE__);}while(0) + +#define lwIP_REQUIRE_ACTION(Expression,Label,Action) \ + do{\ + if (lwIP_unlikely(!(Expression))) \ + {\ + ESP_LOG("%d\n", __LINE__);\ + {Action;}\ + goto Label;\ + }\ + }while(0) + +#define lwIP_REQUIRE_NOERROR(Expression,Label) \ + do{\ + int LocalError;\ + LocalError = (int)Expression;\ + if (lwIP_unlikely(LocalError != 0)) \ + {\ + ESP_LOG("%d 0x%x\n", __LINE__, LocalError);\ + goto Label;\ + }\ + }while(0) + +#define lwIP_REQUIRE_NOERROR_ACTION(Expression,Label,Action) \ + do{\ + int LocalError;\ + LocalError = (int)Expression;\ + if (lwIP_unlikely(LocalError != 0)) \ + {\ + ESP_LOG("%d\n", __LINE__);\ + {Action;}\ + goto Label;\ + }\ + }while(0) + +#define lwIP_EVENT_PARSE(s, error) \ + do { \ + mbedtls_parse_internal(s, error); \ + } while (0) + +#define lwIP_EVENT_THREAD(s, event, error) \ + do { \ + mbedtls_parse_thread(s, event, error); \ + }while(0) + +typedef enum{ + ENTCONN_EVENT_NONE = 0, + NETCONN_EVENT_ESTABLISHED = 1, + ENTCONN_EVENT_RECV = 2, + NETCONN_EVENT_SEND = 3, + NETCONN_EVENT_ERROR = 4, + NETCONN_EVENT_CLOSE = 5, + NETCONN_EVENT_SUMNUM = 6 +}netconn_event; + +typedef enum _netconn_type { + NETCONN_INVALID = 0, + /* ESPCONN_TCP Group */ + NETCONN_TCP = 0x10, + /* ESPCONN_UDP Group */ + NETCONN_UDP = 0x20, +} netconn_type; + +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + u8_t sin_family; + u16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +/** A netconn descriptor */ +typedef struct _lwIP_netconn{ + /** flags blocking or nonblocking defines */ + uint8 flags; + /** type of the lwIP_netconn (TCP, UDP) */ + netconn_type type; + /** current state of the lwIP_netconn */ + netconn_state state; + /** the lwIP internal protocol control block */ + struct tcp_pcb *tcp; + + /**the new socket is unknown and sync*/ + void *acceptmbox; + + /**the lwIP internal buffer control block*/ + ringbuf *readbuf; + /** only used for socket layer */ + int socket; +}lwIP_netconn, *lwIPNetconn; + +/** Contains all internal pointers and states used for a socket */ +typedef struct _lwIP_sock{ + /** sockets currently are built on lwIP_netconn, each socket has one lwIP_netconn */ + lwIP_netconn *conn; + /** data that was left from the previous read */ + u32_t recv_index; + u32_t send_index; + u32_t recv_data_len; + void *send_buffer; +}lwIP_sock; + +typedef uint8 sa_family_t; + +struct sockaddr { + uint8 sa_len; + sa_family_t sa_family; + char sa_data[14]; +}; + +typedef uint32 socklen_t; + +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) + +#define AF_UNSPEC 0 +#define AF_INET 2 + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +#define lwIPThreadPrio 25 +#define lwIPThreadQueueLen 15 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_TYPE 0x1008 /* get socket type */ + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +#define SOL_SOCKET 0xfff /* options for socket level */ + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +/* Flags for struct netconn.flags (u8_t) */ +/** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores whether to wake up the original application task + if data couldn't be sent in the first try. */ +#define NETCONN_FLAG_WRITE_DELAYED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If this is set, a TCP netconn must call netconn_recved() to update + the TCP receive window (done automatically if not set). */ +#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +#undef FD_SETSIZE +/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +#define FD_SETSIZE NUM_SOCKETS +#define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) +#define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) +#define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) +#define FD_ZERO(p) os_memset((void*)(p),0,sizeof(*(p))) + +typedef struct fd_set { + unsigned char fd_bits[(FD_SETSIZE + 7) / 8]; +} fd_set; + +#endif /* FD_SET */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt(int s, int level, int optname, void *optval,socklen_t *optlen); +int lwip_setsockopt(int s, int level, int optname, const void *optval,socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags,struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags,const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset,fd_set *exceptset, struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); +uint32_t lwip_getul(char *str); + +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define shutdown(a,b) lwip_shutdown(a,b) +#define closesocket(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#define getsockname(a,b,c) lwip_getsockname(a,b,c) +#define getpeername(a,b,c) lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b) lwip_listen(a,b) +#define recv(a,b,c,d) lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket(a,b,c) +#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) + +#define read(a,b,c) lwip_read(a,b,c) +#define write(a,b,c) lwip_write(a,b,c) +#define close(s) lwip_close(s) +#define getul(s) lwip_getul(s) + +#endif /* ESPCONN_SOCKT_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/threading.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/threading.h new file mode 100644 index 0000000000..c39cbf24d7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/threading.h @@ -0,0 +1,104 @@ +/** + * \file threading.h + * + * \brief Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_THREADING_H +#define MBEDTLS_THREADING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */ +#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +#include +typedef struct +{ + pthread_mutex_t mutex; + char is_valid; +} mbedtls_threading_mutex_t; +#endif + +#if defined(MBEDTLS_THREADING_ALT) +/* You should define the mbedtls_threading_mutex_t type in your header */ +#include "threading_alt.h" + +/** + * \brief Set your alternate threading implementation function + * pointers and initialize global mutexes. If used, this + * function must be called once in the main thread before any + * other mbed TLS function is called, and + * mbedtls_threading_free_alt() must be called once in the main + * thread after all other mbed TLS functions. + * + * \note mutex_init() and mutex_free() don't return a status code. + * If mutex_init() fails, it should leave its argument (the + * mutex) in a state such that mutex_lock() will fail when + * called with this argument. + * + * \param mutex_init the init function implementation + * \param mutex_free the free function implementation + * \param mutex_lock the lock function implementation + * \param mutex_unlock the unlock function implementation + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ); + +/** + * \brief Free global mutexes. + */ +void mbedtls_threading_free_alt( void ); +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * The function pointers for mutex_init, mutex_free, mutex_ and mutex_unlock + * + * All these functions are expected to work or the result will be undefined. + */ +extern void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t *mutex ); +extern void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex ); + +/* + * Global mutexes + */ +extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; +extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex; + +#ifdef __cplusplus +} +#endif + +#endif /* threading.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/timing.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/timing.h new file mode 100644 index 0000000000..ae7a713e7a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/timing.h @@ -0,0 +1,141 @@ +/** + * \file timing.h + * + * \brief Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_TIMING_H +#define MBEDTLS_TIMING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief timer structure + */ +struct mbedtls_timing_hr_time +{ + unsigned char opaque[32]; +}; + +/** + * \brief Context for mbedtls_timing_set/get_delay() + */ +typedef struct +{ + struct mbedtls_timing_hr_time timer; + uint32_t int_ms; + uint32_t fin_ms; +} mbedtls_timing_delay_context; + +extern volatile int mbedtls_timing_alarmed; + +/** + * \brief Return the CPU cycle counter value + * + * \warning This is only a best effort! Do not rely on this! + * In particular, it is known to be unreliable on virtual + * machines. + */ +unsigned long mbedtls_timing_hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "mbedtls_timing_alarmed" flag is set + * + * \warning Only one alarm at a time is supported. In a threaded + * context, this means one for the whole process, not one per + * thread. + */ +void mbedtls_set_alarm( int seconds ); + +/** + * \brief Set a pair of delays to watch + * (See \c mbedtls_timing_get_delay().) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * \param int_ms First (intermediate) delay in milliseconds. + * \param fin_ms Second (final) delay in milliseconds. + * Pass 0 to cancel the current delay. + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); + +/** + * \brief Get the status of delays + * (Memory helper: number of delays passed.) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * + * \return -1 if cancelled (fin_ms = 0) + * 0 if none of the delays are passed, + * 1 if only the intermediate delay is passed, + * 2 if the final delay is passed. + */ +int mbedtls_timing_get_delay( void *data ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_timing_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/version.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/version.h new file mode 100644 index 0000000000..ea2966e8ac --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/version.h @@ -0,0 +1,111 @@ +/** + * \file version.h + * + * \brief Run-time version information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This set of compile-time defines and run-time variables can be used to + * determine the version number of the mbed TLS library used. + */ +#ifndef MBEDTLS_VERSION_H +#define MBEDTLS_VERSION_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/** + * The version number x.y.z is split into three parts. + * Major, Minor, Patchlevel + */ +#define MBEDTLS_VERSION_MAJOR 2 +#define MBEDTLS_VERSION_MINOR 2 +#define MBEDTLS_VERSION_PATCH 1 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define MBEDTLS_VERSION_NUMBER 0x02020100 +#define MBEDTLS_VERSION_STRING "2.2.1" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.2.1" + +#if defined(MBEDTLS_VERSION_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the version number. + * + * \return The constructed version number in the format + * MMNNPP00 (Major, Minor, Patch). + */ +unsigned int mbedtls_version_get_number( void ); + +/** + * Get the version string ("x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 9 bytes in size) + */ +void mbedtls_version_get_string( char *string ); + +/** + * Get the full version string ("mbed TLS x.y.z"). + * + * \param string The string that will receive the value. The mbed TLS version + * string will use 18 bytes AT MOST including a terminating + * null byte. + * (So the buffer should be at least 18 bytes to receive this + * version string). + */ +void mbedtls_version_get_string_full( char *string ); + +/** + * \brief Check if support for a feature was compiled into this + * mbed TLS binary. This allows you to see at runtime if the + * library was for instance compiled with or without + * Multi-threading support. + * + * \note only checks against defines in the sections "System + * support", "mbed TLS modules" and "mbed TLS feature + * support" in config.h + * + * \param feature The string for the define to check (e.g. "MBEDTLS_AES_C") + * + * \return 0 if the feature is present, + * -1 if the feature is not present and + * -2 if support for feature checking as a whole was not + * compiled in. + */ +int mbedtls_version_check_feature( const char *feature ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_VERSION_C */ + +#endif /* version.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509.h new file mode 100644 index 0000000000..54dac166b4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509.h @@ -0,0 +1,331 @@ +/** + * \file x509.h + * + * \brief X.509 generic defines and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_H +#define MBEDTLS_X509_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +/** + * \addtogroup x509_module + * \{ + */ + +#if !defined(MBEDTLS_X509_MAX_INTERMEDIATE_CA) +/** + * Maximum number of intermediate CAs in a verification chain. + * That is, maximum length of the chain, excluding the end-entity certificate + * and the trusted root certificate. + * + * Set this to a low value to prevent an adversary from making you waste + * resources verifying an overlong certificate chain. + */ +#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 +#endif + +/** + * \name X509 Error codes + * \{ + */ +#define MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define MBEDTLS_ERR_X509_UNKNOWN_OID -0x2100 /**< Requested OID is unknown. */ +#define MBEDTLS_ERR_X509_INVALID_FORMAT -0x2180 /**< The CRT/CRL/CSR format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_X509_INVALID_VERSION -0x2200 /**< The CRT/CRL/CSR version element is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SIGNATURE -0x2480 /**< The signature tag or value invalid. */ +#define MBEDTLS_ERR_X509_INVALID_EXTENSIONS -0x2500 /**< The extension tag or value is invalid. */ +#define MBEDTLS_ERR_X509_UNKNOWN_VERSION -0x2580 /**< CRT/CRL/CSR has an unsupported version number. */ +#define MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG -0x2600 /**< Signature algorithm (oid) is unsupported. */ +#define MBEDTLS_ERR_X509_SIG_MISMATCH -0x2680 /**< Signature algorithms do not match. (see \c ::mbedtls_x509_crt sig_oid) */ +#define MBEDTLS_ERR_X509_CERT_VERIFY_FAILED -0x2700 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT -0x2780 /**< Format not recognized as DER or PEM. */ +#define MBEDTLS_ERR_X509_BAD_INPUT_DATA -0x2800 /**< Input invalid. */ +#define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */ +/* \} name */ + +/** + * \name X509 Verify codes + * \{ + */ +/* Reminder: update x509_crt_verify_strings[] in library/x509_crt.c */ +#define MBEDTLS_X509_BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define MBEDTLS_X509_BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define MBEDTLS_X509_BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define MBEDTLS_X509_BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_NOT_TRUSTED 0x10 /**< The CRL is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_EXPIRED 0x20 /**< The CRL is expired. */ +#define MBEDTLS_X509_BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define MBEDTLS_X509_BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +#define MBEDTLS_X509_BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ +#define MBEDTLS_X509_BADCERT_FUTURE 0x0200 /**< The certificate validity starts in the future. */ +#define MBEDTLS_X509_BADCRL_FUTURE 0x0400 /**< The CRL is from the future */ +#define MBEDTLS_X509_BADCERT_KEY_USAGE 0x0800 /**< Usage does not match the keyUsage extension. */ +#define MBEDTLS_X509_BADCERT_EXT_KEY_USAGE 0x1000 /**< Usage does not match the extendedKeyUsage extension. */ +#define MBEDTLS_X509_BADCERT_NS_CERT_TYPE 0x2000 /**< Usage does not match the nsCertType extension. */ +#define MBEDTLS_X509_BADCERT_BAD_MD 0x4000 /**< The certificate is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCERT_BAD_PK 0x8000 /**< The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCERT_BAD_KEY 0x010000 /**< The certificate is signed with an unacceptable key (eg bad curve, RSA too short). */ +#define MBEDTLS_X509_BADCRL_BAD_MD 0x020000 /**< The CRL is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCRL_BAD_PK 0x040000 /**< The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCRL_BAD_KEY 0x080000 /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */ + +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * X.509 v3 Key Usage Extension flags + * Reminder: update x509_info_key_usage() when adding new flags. + */ +#define MBEDTLS_X509_KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define MBEDTLS_X509_KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define MBEDTLS_X509_KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define MBEDTLS_X509_KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define MBEDTLS_X509_KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define MBEDTLS_X509_KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define MBEDTLS_X509_KU_CRL_SIGN (0x02) /* bit 6 */ +#define MBEDTLS_X509_KU_ENCIPHER_ONLY (0x01) /* bit 7 */ +#define MBEDTLS_X509_KU_DECIPHER_ONLY (0x8000) /* bit 8 */ + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define MBEDTLS_X509_NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +/* + * X.509 extension types + * + * Comments refer to the status for using certificates. Status can be + * different for writing certificates or reading CRLs or CSRs. + */ +#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define MBEDTLS_X509_EXT_KEY_USAGE (1 << 2) +#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES (1 << 3) +#define MBEDTLS_X509_EXT_POLICY_MAPPINGS (1 << 4) +#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME (1 << 5) /* Supported (DNS) */ +#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME (1 << 6) +#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS (1 << 8) /* Supported */ +#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS (1 << 9) +#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS (1 << 10) +#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE (1 << 11) +#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define MBEDTLS_X509_EXT_FRESHEST_CRL (1 << 14) + +#define MBEDTLS_X509_EXT_NS_CERT_TYPE (1 << 16) /* Parsed (and then ?) */ + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define MBEDTLS_X509_FORMAT_DER 1 +#define MBEDTLS_X509_FORMAT_PEM 2 + +#define MBEDTLS_X509_MAX_DN_NAME_SIZE 256 /**< Maximum value size of a DN entry */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates, CRLs and CSRs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef mbedtls_asn1_buf mbedtls_x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef mbedtls_asn1_bitstring mbedtls_x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.). + */ +typedef mbedtls_asn1_named_data mbedtls_x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef mbedtls_asn1_sequence mbedtls_x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct mbedtls_x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +mbedtls_x509_time; + +/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ +/** \} addtogroup x509_module */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the past. + * + * \note Intended usage is "if( is_past( valid_to ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param time mbedtls_x509_time to check + * + * \return 1 if the given time is in the past or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_past( const mbedtls_x509_time *time ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the future. + * + * \note Intended usage is "if( is_future( valid_from ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param time mbedtls_x509_time to check + * + * \return 1 if the given time is in the future or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_future( const mbedtls_x509_time *time ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ); +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ); +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ); +#endif +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *time ); +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ); +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ); +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ); +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, + size_t val_len ); +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); + +#define MBEDTLS_X509_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crl.h new file mode 100644 index 0000000000..7988439900 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crl.h @@ -0,0 +1,173 @@ +/** + * \file x509_crl.h + * + * \brief X.509 certificate revocation list parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRL_H +#define MBEDTLS_X509_CRL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for parsing CRLs + * \{ + */ + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct mbedtls_x509_crl_entry +{ + mbedtls_x509_buf raw; + + mbedtls_x509_buf serial; + + mbedtls_x509_time revocation_date; + + mbedtls_x509_buf entry_ext; + + struct mbedtls_x509_crl_entry *next; +} +mbedtls_x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct mbedtls_x509_crl +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< CRL version (1=v1, 2=v2) */ + mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + + mbedtls_x509_time this_update; + mbedtls_x509_time next_update; + + mbedtls_x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + mbedtls_x509_buf crl_ext; + + mbedtls_x509_buf sig_oid2; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crl *next; +} +mbedtls_x509_crl; + +/** + * \brief Parse a DER-encoded CRL and append it to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ); +/** + * \brief Parse one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from (in PEM or DER encoding) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ); + +/** + * \brief Initialize a CRL (chain) + * + * \param crl CRL chain to initialize + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ); + +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ); + +/* \} name */ +/* \} addtogroup x509_module */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crl.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crt.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crt.h new file mode 100644 index 0000000000..fe821d1cfb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_crt.h @@ -0,0 +1,645 @@ +/** + * \file x509_crt.h + * + * \brief X.509 certificate parsing and writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRT_H +#define MBEDTLS_X509_CRT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" +#include "x509_crl.h" + +/** + * \addtogroup x509_module + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Structures and functions for parsing and writing X.509 certificates + * \{ + */ + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct mbedtls_x509_crt +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ + mbedtls_x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + mbedtls_x509_buf sig_oid; /**< Signature algorithm, e.g. sha1RSA */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_x509_time valid_from; /**< Start time of certificate validity. */ + mbedtls_x509_time valid_to; /**< End time of certificate validity. */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + + mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ + + mbedtls_x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ +} +mbedtls_x509_crt; + +/** + * Build flag from an algorithm/curve identifier (pk, md, ecp) + * Since 0 is always XXX_NONE, ignore it. + */ +#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( id - 1 ) ) + +/** + * Security profile for certificate verification. + * + * All lists are bitfields, built by ORing flags from MBEDTLS_X509_ID_FLAG(). + */ +typedef struct +{ + uint32_t allowed_mds; /**< MDs for signatures */ + uint32_t allowed_pks; /**< PK algs for signatures */ + uint32_t allowed_curves; /**< Elliptic curves for ECDSA */ + uint32_t rsa_min_bitlen; /**< Minimum size for RSA keys */ +} +mbedtls_x509_crt_profile; + +#define MBEDTLS_X509_CRT_VERSION_1 0 +#define MBEDTLS_X509_CRT_VERSION_2 1 +#define MBEDTLS_X509_CRT_VERSION_3 2 + +#define MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN 32 +#define MBEDTLS_X509_RFC5280_UTC_TIME_LEN 15 + +/** + * Container for writing a certificate (CRT) + */ +typedef struct mbedtls_x509write_cert +{ + int version; + mbedtls_mpi serial; + mbedtls_pk_context *subject_key; + mbedtls_pk_context *issuer_key; + mbedtls_asn1_named_data *subject; + mbedtls_asn1_named_data *issuer; + mbedtls_md_type_t md_alg; + char not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_cert; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * Default security profile. Should provide a good balance between security + * and compatibility with current deployments. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default; + +/** + * Expected next default profile. Recommended for new deployments. + * Currently targets a 128-bit security level, except for RSA-2048. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next; + +/** + * NSA Suite B profile. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb; + +/** + * \brief Parse a single DER formatted certificate and add it + * to the chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ); + +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ); + +/** + * \brief Returns an informational string about the + * verification status of a certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param flags Verification flags created by mbedtls_x509_crt_verify() + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ); + +/** + * \brief Verify the certificate signature + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, mbedtls_x509_crt *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything but a fatal error. + * + * \note In case verification failed, the results can be displayed + * using \c mbedtls_x509_crt_verify_info() + * + * \note Same as \c mbedtls_x509_crt_verify_with_profile() with the + * default security profile. + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error in case of a fatal error encountered + * during the verification process. + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature according to profile + * + * \note Same as \c mbedtls_x509_crt_verify(), but with explicit + * security profile. + * + * \note The restrictions on keys (RSA minimum size, allowed curves + * for ECDSA) apply to all certificates: trusted root, + * intermediate CAs if any, and end entity certificate. + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param profile security profile for verification + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error in case of a fatal error encountered + * during the verification process. + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +/** + * \brief Check usage of certificate against keyUsage extension. + * + * \param crt Leaf certificate used. + * \param usage Intended usage(s) (eg MBEDTLS_X509_KU_KEY_ENCIPHERMENT + * before using the certificate to perform an RSA key + * exchange). + * + * \note Except for decipherOnly and encipherOnly, a bit set in the + * usage argument means this bit MUST be set in the + * certificate. For decipherOnly and encipherOnly, it means + * that bit MAY be set. + * + * \return 0 is these uses of the certificate are allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if the keyUsage extension + * is present but does not match the usage argument. + * + * \note You should only call this function on leaf certificates, on + * (intermediate) CAs the keyUsage extension is automatically + * checked by \c mbedtls_x509_crt_verify(). + */ +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +/** + * \brief Check usage of certificate against extentedJeyUsage. + * + * \param crt Leaf certificate used. + * \param usage_oid Intended usage (eg MBEDTLS_OID_SERVER_AUTH or MBEDTLS_OID_CLIENT_AUTH). + * \param usage_len Length of usage_oid (eg given by MBEDTLS_OID_SIZE()). + * + * \return 0 if this use of the certificate is allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if not. + * + * \note Usually only makes sense on leaf certificates. + */ +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ); +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/** + * \brief Verify the certificate revocation status + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ); +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/** + * \brief Initialize a certificate (chain) + * + * \param crt Certificate chain to initialize + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ); + +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CRT_WRITE_C) +/** + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: MBEDTLS_X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (MBEDTLS_X509_CRT_VERSION_1, MBEDTLS_X509_CRT_VERSION_2 or + * MBEDTLS_X509_CRT_VERSION_3) + */ +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param key public key to include + */ +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param key private key to sign with + */ +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Generic function to add to or replace an extension in the + * CRT + * + * \param ctx CRT context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param critical if the extension is critical (per the RFC's definition) + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ); + +/** + * \brief Set the basicConstraints extension for a CRT + * + * \param ctx CRT context to use + * \param is_ca is this a CA certificate + * \param max_pathlen maximum length of certificate chains below this + * certificate (only for CA certificates, -1 is + * inlimited) + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ); + +#if defined(MBEDTLS_SHA1_C) +/** + * \brief Set the subjectKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_subject_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the authorityKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_issuer_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ); +#endif /* MBEDTLS_SHA1_C */ + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CRT context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CRT context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a built up certificate to a X509 PEM string + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CRT_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crt.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_csr.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_csr.h new file mode 100644 index 0000000000..34998a3a59 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/x509_csr.h @@ -0,0 +1,292 @@ +/** + * \file x509_csr.h + * + * \brief X.509 certificate signing request parsing and writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CSR_H +#define MBEDTLS_X509_CSR_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for X.509 Certificate Signing Requests (CSR) + * \{ + */ + +/** + * Certificate Signing Request (CSR) structure. + */ +typedef struct mbedtls_x509_csr +{ + mbedtls_x509_buf raw; /**< The raw CSR data (DER). */ + mbedtls_x509_buf cri; /**< The raw CertificateRequestInfo body (DER). */ + + int version; /**< CSR version (1=v1). */ + + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf sig_oid; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ +} +mbedtls_x509_csr; + +/** + * Container for writing a CSR + */ +typedef struct mbedtls_x509write_csr +{ + mbedtls_pk_context *key; + mbedtls_asn1_named_data *subject; + mbedtls_md_type_t md_alg; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_csr; + +#if defined(MBEDTLS_X509_CSR_PARSE_C) +/** + * \brief Load a Certificate Signing Request (CSR) in DER format + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ); + +/** + * \brief Load a Certificate Signing Request (CSR), DER or PEM format + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load a Certificate Signing Request (CSR) + * + * \param csr CSR context to fill + * \param path filename to read the CSR from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * CSR. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param csr The X509 CSR to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ); + +/** + * \brief Initialize a CSR + * + * \param csr CSR to initialize + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ); + +/** + * \brief Unallocate all CSR data + * + * \param csr CSR to free + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ); +#endif /* MBEDTLS_X509_CSR_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CSR_WRITE_C) +/** + * \brief Initialize a CSR context + * + * \param ctx CSR context to initialize + */ +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ); + +/** + * \brief Set the subject name for a CSR + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CSR context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ); + +/** + * \brief Set the key for a CSR (public key will be included, + * private key used to sign the CSR when writing it) + * + * \param ctx CSR context to use + * \param key Asymetric key to include + */ +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CSR context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CSR context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CSR context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Generic function to add to or replace an extension in the + * CSR + * + * \param ctx CSR context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ); + +/** + * \brief Free the contents of a CSR context + * + * \param ctx CSR context to free + */ +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ); + +/** + * \brief Write a CSR (Certificate Signing Request) to a + * DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a CSR (Certificate Signing Request) to a + * PEM string + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for couermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CSR_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_csr.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/xtea.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/xtea.h new file mode 100644 index 0000000000..b073f84efa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/mbedtls/xtea.h @@ -0,0 +1,139 @@ +/** + * \file xtea.h + * + * \brief XTEA block cipher (32-bit) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_XTEA_H +#define MBEDTLS_XTEA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_XTEA_ENCRYPT 1 +#define MBEDTLS_XTEA_DECRYPT 0 + +#define MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ + +#if !defined(MBEDTLS_XTEA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief XTEA context structure + */ +typedef struct +{ + uint32_t k[4]; /*!< key */ +} +mbedtls_xtea_context; + +/** + * \brief Initialize XTEA context + * + * \param ctx XTEA context to be initialized + */ +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ); + +/** + * \brief Clear XTEA context + * + * \param ctx XTEA context to be cleared + */ +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ); + +/** + * \brief XTEA key schedule + * + * \param ctx XTEA context to be initialized + * \param key the secret key + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ); + +/** + * \brief XTEA cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, + int mode, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief XTEA CBC cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param length the length of input, multiple of 8 + * \param iv initialization vector for CBC mode + * \param input input block + * \param output output block + * + * \return 0 if successful, + * MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH if the length % 8 != 0 + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* MBEDTLS_XTEA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_xtea_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/etharp.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/etharp.h new file mode 100644 index 0000000000..2092ab7a1c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/etharp.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN 6 +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** Ethernet header */ +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#if ETHARP_SUPPORT_VLAN + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ +struct eth_vlan_hdr { + PACK_STRUCT_FIELD(u16_t tpid); + PACK_STRUCT_FIELD(u16_t prio_vid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF) + +#endif /* ETHARP_SUPPORT_VLAN */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message, see RFC 826 ("Packet format") */ +struct etharp_hdr { + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FIELD(u8_t hwlen); + PACK_STRUCT_FIELD(u8_t protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FIELD(struct eth_addr shwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); + PACK_STRUCT_FIELD(struct eth_addr dhwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETHARP_HDR 28 +#define SIZEOF_ETHARP_MINSIZE 46 +#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) +#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE) + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP 0x0806 +#define ETHTYPE_IP 0x0800 +#define ETHTYPE_VLAN 0x8100 +#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHTYPE_PAE 0x888e + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables + * or known to be 32-bit aligned within the protocol header. */ +#ifndef ETHADDR32_COPY +#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local + * variables and known to be 16-bit aligned within the protocol header. */ +#ifndef ETHADDR16_COPY +#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +/** ARP message types (opcodes) */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct etharp_q_entry { + struct etharp_q_entry *next; + struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, not init needed. */ +void etharp_tmr(void)ICACHE_FLASH_ATTR; +s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR; +err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR; +err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) +void etharp_cleanup_netif(struct netif *netif); + +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR; +err_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, + const u16_t opcode)ICACHE_FLASH_ATTR; +#endif /* LWIP_AUTOIP */ + +#endif /* LWIP_ARP */ + +err_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR; + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) + +extern const struct eth_addr ethbroadcast, ethzero; + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#if 0 +/** Ethernet header */ +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN 6 +#endif + + +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; + + +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_ARP_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/if_llc.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/if_llc.h new file mode 100644 index 0000000000..ca09b38687 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/if_llc.h @@ -0,0 +1,173 @@ +/* $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ */ + +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_llc.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD$ + */ + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcommings in many + * compilers. + */ + +struct llc { + uint8_t llc_dsap; + uint8_t llc_ssap; + union { + struct { + uint8_t control; + uint8_t format_id; + uint8_t class; + uint8_t window_x2; + } __packed type_u; + struct { + uint8_t num_snd_x2; + uint8_t num_rcv_x2; + } __packed type_i; + struct { + uint8_t control; + uint8_t num_rcv_x2; + } __packed type_s; + struct { + uint8_t control; + /* + * We cannot put the following fields in a structure because + * the structure rounding might cause padding. + */ + uint8_t frmr_rej_pdu0; + uint8_t frmr_rej_pdu1; + uint8_t frmr_control; + uint8_t frmr_control_ext; + uint8_t frmr_cause; + } __packed type_frmr; + struct { + uint8_t control; + uint8_t org_code[3]; + uint16_t ether_type; + } __packed type_snap; + struct { + uint8_t control; + uint8_t control_ext; + } __packed type_raw; + } __packed llc_un; +} __packed; + +struct frmrinfo { + uint8_t frmr_rej_pdu0; + uint8_t frmr_rej_pdu1; + uint8_t frmr_control; + uint8_t frmr_control_ext; + uint8_t frmr_cause; +} __packed; + +#define llc_control llc_un.type_u.control +#define llc_control_ext llc_un.type_raw.control_ext +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmr_cause +#define llc_snap llc_un.type_snap + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 +#define LLC_SNAPFRAMELEN 8 + +#ifdef CTASSERT +CTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN); +#endif + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_8021D_LSAP 0x42 +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +#define RFC1042_LEN 6 +#define RFC1042 {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00} +#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8} + +/* + * copied from sys/net/ethernet.h + */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */ +#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */ + + + +#endif /* _NET_IF_LLC_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/ppp_oe.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/ppp_oe.h new file mode 100644 index 0000000000..e1cdfa5199 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/ppp_oe.h @@ -0,0 +1,190 @@ +/***************************************************************************** +* ppp_oe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT > 0 + +#include "netif/etharp.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { + PACK_STRUCT_FIELD(u8_t vertype); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +#define PPPOE_STATE_CLOSING 4 +/* passive */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +#ifndef ETHERMTU +#define ETHERMTU 1500 +#endif + +/* two byte PPP protocol discriminator, then IP data */ +#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2) + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif + +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + int sc_pd; /* ppp unit number */ + void (*sc_linkStatusCB)(int pd, int up); + + int sc_state; /* discovery phase or session connected */ + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + +#ifdef PPPOE_TODO + char *sc_service_name; /* if != NULL: requested name of service */ + char *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_TODO */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + size_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + size_t sc_hunique_len; /* length of host unique */ +#endif + int sc_padi_retried; /* number of PADI retries already done */ + int sc_padr_retried; /* number of PADR retries already done */ +}; + + +#define pppoe_init() /* compatibility define, no initialization needed */ + +err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); +err_t pppoe_destroy(struct netif *ifp); + +int pppoe_connect(struct pppoe_softc *sc); +void pppoe_disconnect(struct pppoe_softc *sc); + +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); + +/** used in ppp.c */ +#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN) + +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_OE_H */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/wlan_lwip_if.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/wlan_lwip_if.h new file mode 100644 index 0000000000..ed9c477562 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/netif/wlan_lwip_if.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010-2011 Espressif System + * +*/ + +#ifndef _WLAN_LWIP_IF_H_ +#define _WLAN_LWIP_IF_H_ + +#define LWIP_IF0_PRIO 28 +#define LWIP_IF1_PRIO 29 + +enum { + SIG_LWIP_RX = 0, +}; + +struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info); +struct netif * eagle_lwip_getif(uint8 index); + +#ifndef IOT_SIP_MODE +sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb); +#else +sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb); +#endif + +#endif /* _WLAN_LWIP_IF_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_secure.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_secure.h new file mode 100755 index 0000000000..cf0b9ac47f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_secure.h @@ -0,0 +1,46 @@ +#ifndef __ESPCONN_ENCRY_H__ +#define __ESPCONN_ENCRY_H__ + +#include "lwip/app/espconn.h" +#include "ssl/app/espconn_ssl.h" +/****************************************************************************** + * FunctionName : espconn_encry_connect + * Description : The function given as connection + * Parameters : espconn -- the espconn used to connect with the host + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_connect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_encry_disconnect + * Description : The function given as the disconnection + * Parameters : espconn -- the espconn used to disconnect with the host + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_secure_disconnect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_encry_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_secure_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_secure_accept(struct espconn *espconn); + +#endif + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_ssl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_ssl.h new file mode 100755 index 0000000000..a14086113e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/app/espconn_ssl.h @@ -0,0 +1,156 @@ +#ifndef ESPCONN_SSL_CLIENT_H +#define ESPCONN_SSL_CLIENT_H + +#include "ssl/ssl_ssl.h" +#include "ssl/ssl_tls1.h" + +#include "lwip/app/espconn.h" + +#define SSL_KEEP_INTVL 1000 +#define SSL_KEEP_CNT 3 +#define SSL_KEEP_IDLE 60000 + +#define ssl_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) +#define ssl_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) + +typedef struct { + char *buffer; + int length; + int start; + int end; +}EspRingBuffer; + +int EspRingBuffer_full(EspRingBuffer *buffer); +int EspRingBuffer_empty(EspRingBuffer *buffer); +int EspRingBuffer_available_data(EspRingBuffer *buffer); +int EspRingBuffer_available_space(EspRingBuffer *buffer); + +#define EspRingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start -1) +#define EspRingBuffer_available_space(B) ((B)->length - (B)->end -1) +#define EspRingBuffer_full(B) (EspRingBuffer_available_data((B))- (B)->length == 0) +#define EspRingBuffer_empty(B) (EspRingBuffer_available_data((B)) == 0) +#define EspRingBuffer_starts_at(B) ((B)->buffer + (B)->start) +#define EspRingBuffer_ends_at(B) ((B)->buffer + (B)->end) +#define EspRingBuffer_commit_read(B, A) ((B)->start = ((B)->start + (A)) % (B)->length) +#define EspRingBuffer_commit_write(B, A) ((B)->end = ((B)->end + (A)) % (B)->length) + +typedef struct _SSL_RING{ + EspRingBuffer *RingBuffer; + uint16 RemainLength; +}SSL_RING; + +typedef struct _ssl_msg { + SSL_CTX *ssl_ctx; + SSL *ssl; + SSL_RING SSLRing; + bool quiet; + bool SentFnFlag; + u16_t pkt_length; +} ssl_msg; + +typedef struct _ssl_sector{ + uint32 sector; + bool flag; +}ssl_sector; + +struct ssl_packet{ + uint8* pbuffer; + uint16 buffer_size; + ssl_sector cert_ca_sector; + ssl_sector cert_req_sector; +}; + +typedef struct _ssl_opt { + struct ssl_packet server; + struct ssl_packet client; + uint8 type; +}ssl_opt; + +enum { + ESPCONN_IDLE = 0, + ESPCONN_CLIENT, + ESPCONN_SERVER, + ESPCONN_BOTH, + ESPCONN_MAX +}; + +enum { + SIG_ESPCONN_TLS_ERRER = 0x3B +}; + +enum { + ESPCONN_CERT_REQ, + ESPCONN_CERT_AUTH +}; + +typedef struct _file_head{ + char file_name[32]; + uint16_t file_length; +}file_head; + +typedef struct _file_param{ + file_head file_head; + int32 file_offerset; +}file_param; + +#define ESPCONN_SECURE_MAX_SIZE 8192 +#define ESPCONN_SECURE_DEFAULT_HEAP 0x3800 +#define ESPCONN_SECURE_DEFAULT_SIZE RT_MAX_PLAIN_LENGTH+RT_EXTRA +#define ESPCONN_HANDSHAKE_TIMEOUT 0x3C + +#define espconn_TlsTaskPrio 25 + +extern ssl_opt ssl_option; + +/****************************************************************************** + * FunctionName : sslserver_start + * Description : Initialize the server: set up a listen PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_ssl_server(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_ssl_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_ssl_client(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_ssl_write + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ + +extern void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_ssl_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_ssl_disconnect(espconn_msg *pdis); + +/****************************************************************************** + * FunctionName : espconn_secure_get_size + * Description : get buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : buffer size for client or server +*******************************************************************************/ + +extern sint16 espconn_secure_get_size(uint8 level); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint.h new file mode 100755 index 0000000000..99f5415147 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIGINT_HEADER +#define BIGINT_HEADER + +#include "ssl/ssl_crypto.h" + +BI_CTX *bi_initialize(void); +void bi_terminate(BI_CTX *ctx); +void bi_permanent(bigint *bi); +void bi_depermanent(bigint *bi); +void bi_clear_cache(BI_CTX *ctx); +void bi_free(BI_CTX *ctx, bigint *bi); +bigint *bi_copy(bigint *bi); +bigint *bi_clone(BI_CTX *ctx, const bigint *bi); +void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size); +bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len); +bigint *int_to_bi(BI_CTX *ctx, comp i); + +/* the functions that actually do something interesting */ +bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); +bigint *bi_subtract(BI_CTX *ctx, bigint *bia, + bigint *bib, int *is_negative); +bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod); +bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); +bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp); +bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp); +int bi_compare(bigint *bia, bigint *bib); +void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); +void bi_free_mod(BI_CTX *ctx, int mod_offset); + +#ifdef CONFIG_SSL_FULL_MODE +void bi_print(const char *label, bigint *bi); +bigint *bi_str_import(BI_CTX *ctx, const char *data); +#endif + +/** + * @def bi_mod + * Find the residue of B. bi_set_mod() must be called before hand. + */ +#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1) + +/** + * bi_residue() is technically the same as bi_mod(), but it uses the + * appropriate reduction technique (which is bi_mod() when doing classical + * reduction). + */ +#if defined(CONFIG_BIGINT_MONTGOMERY) +#define bi_residue(A, B) bi_mont(A, B) +bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#elif defined(CONFIG_BIGINT_BARRETT) +#define bi_residue(A, B) bi_barrett(A, B) +bigint *bi_barrett(BI_CTX *ctx, bigint *bi); +#else /* if defined(CONFIG_BIGINT_CLASSICAL) */ +#define bi_residue(A, B) bi_mod(A, B) +#endif + +#ifdef CONFIG_BIGINT_SQUARE +bigint *bi_square(BI_CTX *ctx, bigint *bi); +#else +#define bi_square(A, B) bi_multiply(A, bi_copy(B), B) +#endif + +#ifdef CONFIG_BIGINT_CRT +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, + bigint *qInv); +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint_impl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint_impl.h new file mode 100755 index 0000000000..c82fefb6da --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_bigint_impl.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIGINT_IMPL_HEADER +#define BIGINT_IMPL_HEADER + +/* Maintain a number of precomputed variables when doing reduction */ +#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ +#ifdef CONFIG_BIGINT_CRT +#define BIGINT_P_OFFSET 1 /**< p modulo offset. */ +#define BIGINT_Q_OFFSET 2 /**< q module offset. */ +#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ +#else +#define BIGINT_NUM_MODS 1 +#endif + +/* Architecture specific functions for big ints */ +#if defined(CONFIG_INTEGER_8BIT) +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ +#ifdef WIN32 +#define COMP_RADIX 4294967296i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 +#else +#define COMP_RADIX 4294967296ULL /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */ +#endif +#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ +typedef uint32_t comp; /**< A single precision component. */ +typedef uint64_t long_comp; /**< A double precision component. */ +typedef sint64_t slong_comp; /**< A signed double precision component. */ +#endif + +/** + * @struct _bigint + * @brief A big integer basic object + */ +struct _bigint +{ + struct _bigint* next; /**< The next bigint in the cache. */ + short size; /**< The number of components in this bigint. */ + short max_comps; /**< The heapsize allocated for this bigint */ + int refs; /**< An internal reference count. */ + comp* comps; /**< A ptr to the actual component data */ +}; + +typedef struct _bigint bigint; /**< An alias for _bigint */ + +/** + * Maintains the state of the cache, and a number of variables used in + * reduction. + */ +typedef struct /**< A big integer "session" context. */ +{ + bigint *active_list; /**< Bigints currently used. */ + bigint *free_list; /**< Bigints not used. */ + bigint *bi_radix; /**< The radix used. */ + bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ + +#if defined(CONFIG_BIGINT_MONTGOMERY) + bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ + bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ + comp N0_dash[BIGINT_NUM_MODS]; +#elif defined(CONFIG_BIGINT_BARRETT) + bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ +#endif + bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ + bigint **g; /**< Used by sliding-window. */ + int window; /**< The size of the sliding window */ + int active_count; /**< Number of active bigints. */ + int free_count; /**< Number of free bigints. */ + +#ifdef CONFIG_BIGINT_MONTGOMERY + uint8_t use_classical; /**< Use classical reduction. */ +#endif + uint8_t mod_offset; /**< The mod offset we are using */ +} BI_CTX; + +#ifndef WIN32 +#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */ +#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */ +#endif + +#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_cert.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_cert.h new file mode 100755 index 0000000000..30c7b65882 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_cert.h @@ -0,0 +1,43 @@ +unsigned char default_certificate[] = { + 0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab, + 0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34, + 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61, + 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32, + 0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32, + 0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, + 0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, + 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, + 0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, + 0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, + 0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, + 0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, + 0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, + 0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, + 0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, + 0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, + 0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, + 0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, + 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, + 0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88, + 0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06, + 0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b, + 0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8, + 0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13, + 0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac, + 0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27, + 0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e, + 0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80, + 0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54, + 0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5 +}; +unsigned int default_certificate_len = 475; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_config.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_config.h new file mode 100755 index 0000000000..2d50a8ac62 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_config.h @@ -0,0 +1,130 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#undef CONFIG_PLATFORM_LINUX +#define CONFIG_PLATFORM_CYGWIN 1 +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#define PREFIX "/usr/local" +#define CONFIG_DEBUG 1 +#undef CONFIG_STRIP_UNWANTED_SECTIONS +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#undef CONFIG_VISUAL_STUDIO_10_0 +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_VISUAL_STUDIO_10_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#undef CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_FULL_MODE 1 +#undef CONFIG_SSL_SKELETON_MODE +#undef CONFIG_SSL_PROT_LOW +#define CONFIG_SSL_PROT_MEDIUM 1 +#undef CONFIG_SSL_PROT_HIGH +#define CONFIG_SSL_USE_DEFAULT_KEY +#define CONFIG_SSL_PRIVATE_KEY_LOCATION "" +#define CONFIG_SSL_PRIVATE_KEY_PASSWORD "" +#define CONFIG_SSL_X509_CERT_LOCATION "" +#undef CONFIG_SSL_GENERATE_X509_CERT +#define CONFIG_SSL_X509_COMMON_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME "" +#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE +#define CONFIG_SSL_HAS_PEM 1 +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME 24 +#define CONFIG_X509_MAX_CA_CERTS 3 +#define CONFIG_SSL_MAX_CERTS 3 +#undef CONFIG_SSL_CTX_MUTEXING +#define CONFIG_USE_DEV_URANDOM 1 +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#define CONFIG_SSL_TEST 1 +#undef CONFIG_AXTLSWRAP +#define CONFIG_AXHTTPD 1 + +/*add by LiuH for debug at 2015.06.11*/ +#define CONFIG_SSL_DISPLAY_MODE 1 + +/* + * Axhttpd Configuration + */ +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_PORT 80 +#define CONFIG_HTTP_HTTPS_PORT 443 +#define CONFIG_HTTP_SESSION_CACHE_SIZE 5 +#define CONFIG_HTTP_WEBROOT "../www" +#define CONFIG_HTTP_TIMEOUT 300 + +/* + * CGI + */ +#undef CONFIG_HTTP_HAS_CGI +#define CONFIG_HTTP_CGI_EXTENSIONS ".lua,.lp,.php" +#define CONFIG_HTTP_ENABLE_LUA 1 +#define CONFIG_HTTP_LUA_PREFIX "/usr" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_CGI_LAUNCHER "/usr/bin/cgi" +#define CONFIG_HTTP_DIRECTORIES 1 +#define CONFIG_HTTP_HAS_AUTHORIZATION 1 +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#define CONFIG_HTTP_VERBOSE 0 +#undef CONFIG_HTTP_IS_DAEMON + +/* + * Language Bindings + */ +#undef CONFIG_BINDINGS +#undef CONFIG_CSHARP_BINDINGS +#undef CONFIG_VBNET_BINDINGS +#define CONFIG_DOT_NET_FRAMEWORK_BASE "" +#undef CONFIG_JAVA_BINDINGS +#define CONFIG_JAVA_HOME "" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" +#undef CONFIG_LUA_BINDINGS +#define CONFIG_LUA_CORE "" + +/* + * Samples + */ +#define CONFIG_SAMPLES 1 +#define CONFIG_C_SAMPLES 1 +#undef CONFIG_CSHARP_SAMPLES +#undef CONFIG_VBNET_SAMPLES +#undef CONFIG_JAVA_SAMPLES +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_LUA_SAMPLES + +/* + * BigInt Options + */ +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#define CONFIG_BIGINT_BARRETT 1 +#define CONFIG_BIGINT_CRT 1 +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#define CONFIG_BIGINT_SLIDING_WINDOW 1 +#define CONFIG_BIGINT_SQUARE 1 +#define CONFIG_BIGINT_CHECK_ON 1 +#define CONFIG_INTEGER_32BIT 1 +#undef CONFIG_INTEGER_16BIT +#undef CONFIG_INTEGER_8BIT diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto.h new file mode 100755 index 0000000000..5d9022754a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2007-2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file crypto.h + */ + +#ifndef HEADER_CRYPTO_H +#define HEADER_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ssl/ssl_config.h" +#include "ssl/ssl_bigint_impl.h" +#include "ssl/ssl_bigint.h" + +#ifndef STDCALL +#define STDCALL +#endif +#ifndef EXP_FUNC +#define EXP_FUNC +#endif + + +/* enable features based on a 'super-set' capbaility. */ +#if defined(CONFIG_SSL_FULL_MODE) +#define CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_CERT_VERIFICATION +#elif defined(CONFIG_SSL_ENABLE_CLIENT) +#define CONFIG_SSL_CERT_VERIFICATION +#endif + +/************************************************************************** + * AES declarations + **************************************************************************/ + +#define AES_MAXROUNDS 14 +#define AES_BLOCKSIZE 16 +#define AES_IV_SIZE 16 + +typedef struct aes_key_st +{ + uint16_t rounds; + uint16_t key_size; + uint32_t ks[(AES_MAXROUNDS+1)*8]; + uint8_t iv[AES_IV_SIZE]; +} AES_CTX; + +typedef enum +{ + AES_MODE_128, + AES_MODE_256 +} AES_MODE; + +void AES_set_key(AES_CTX *ctx, const uint8_t *key, + const uint8_t *iv, AES_MODE mode); +void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, + uint8_t *out, int length); +void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length); +void AES_convert_key(AES_CTX *ctx); + +/************************************************************************** + * RC4 declarations + **************************************************************************/ + +typedef struct +{ + uint8_t x, y, m[256]; +} RC4_CTX; + +void RC4_setup(RC4_CTX *s, const uint8_t *key, int length); +void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length); + +/************************************************************************** + * SHA1 declarations + **************************************************************************/ + +#define SHA1_SIZE 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct +{ + uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint16_t Message_Block_Index; /* Index into message block array */ + uint8_t Message_Block[64]; /* 512-bit message blocks */ +} SHA1_CTX; + +void SHA1_Init(SHA1_CTX *); +void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1_Final(uint8_t *digest, SHA1_CTX *); + +/************************************************************************** + * SHA256 declarations + **************************************************************************/ + +#define SHA256_SIZE 32 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint8_t buffer[64]; +} SHA256_CTX; + +void SHA256_Init(SHA256_CTX *c); +void SHA256_Update(SHA256_CTX *, const uint8_t *input, int len); +void SHA256_Final(uint8_t *digest, SHA256_CTX *); + +/************************************************************************** + * SHA512 declarations + **************************************************************************/ + +#define SHA512_SIZE 64 + +typedef struct +{ + union + { + uint64_t h[8]; + uint8_t digest[64]; + } h_dig; + union + { + uint64_t w[80]; + uint8_t buffer[128]; + } w_buf; + size_t size; + uint64_t totalSize; +} SHA512_CTX; + +void SHA512_Init(SHA512_CTX *c); +void SHA512_Update(SHA512_CTX *, const uint8_t *input, int len); +void SHA512_Final(uint8_t *digest, SHA512_CTX *); + +/************************************************************************** + * SHA384 declarations + **************************************************************************/ + +#define SHA384_SIZE 48 + +typedef SHA512_CTX SHA384_CTX; +void SHA384_Init(SHA384_CTX *c); +void SHA384_Update(SHA384_CTX *, const uint8_t *input, int len); +void SHA384_Final(uint8_t *digest, SHA384_CTX *); + +/************************************************************************** + * MD5 declarations + **************************************************************************/ + +#define MD5_SIZE 16 + +typedef struct +{ + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + uint8_t buffer[64]; /* input buffer */ +} MD5_CTX; + +EXP_FUNC void STDCALL MD5_Init(MD5_CTX *); +EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len); +EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); + +/************************************************************************** + * HMAC declarations + **************************************************************************/ +void ssl_hmac_md5(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest);// fix hmac_md5 to ssl_hmac_md5, discriminate ieee80211 +void ssl_hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest);// fix hmac_md5 to ssl_hmac_sha1, discriminate ieee80211 + +/************************************************************************** + * RSA declarations + **************************************************************************/ + +typedef struct +{ + bigint *m; /* modulus */ + bigint *e; /* public exponent */ + bigint *d; /* private exponent */ +#ifdef CONFIG_BIGINT_CRT + bigint *p; /* p as in m = pq */ + bigint *q; /* q as in m = pq */ + bigint *dP; /* d mod (p-1) */ + bigint *dQ; /* d mod (q-1) */ + bigint *qInv; /* q^-1 mod p */ +#endif + int num_octets; + BI_CTX *bi_ctx; +} RSA_CTX; + +void RSA_priv_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len, + const uint8_t *priv_exp, int priv_len +#ifdef CONFIG_BIGINT_CRT + , const uint8_t *p, int p_len, + const uint8_t *q, int q_len, + const uint8_t *dP, int dP_len, + const uint8_t *dQ, int dQ_len, + const uint8_t *qInv, int qInv_len +#endif + ); +void RSA_pub_key_new(RSA_CTX **rsa_ctx, + const uint8_t *modulus, int mod_len, + const uint8_t *pub_exp, int pub_len); +void RSA_free(RSA_CTX *ctx); +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, + int out_len, int is_decryption); +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) +bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp); +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, + uint8_t *out_data, int is_signing); +void RSA_print(const RSA_CTX *ctx); +#endif + +/************************************************************************** + * RNG declarations + **************************************************************************/ +EXP_FUNC void STDCALL RNG_initialize(void); +EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size); +EXP_FUNC void STDCALL RNG_terminate(void); +EXP_FUNC int STDCALL get_random(int num_rand_bytes, uint8_t *rand_data); +int get_random_NZ(int num_rand_bytes, uint8_t *rand_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto_misc.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto_misc.h new file mode 100755 index 0000000000..074ec06d2b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_crypto_misc.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2007-2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file crypto_misc.h + */ + +#ifndef HEADER_CRYPTO_MISC_H +#define HEADER_CRYPTO_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ssl/ssl_crypto.h" +#include "ssl/ssl_bigint.h" + +/************************************************************************** + * X509 declarations + **************************************************************************/ +#define X509_OK 0 +#define X509_NOT_OK -1 +#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 +#define X509_VFY_ERROR_BAD_SIGNATURE -3 +#define X509_VFY_ERROR_NOT_YET_VALID -4 +#define X509_VFY_ERROR_EXPIRED -5 +#define X509_VFY_ERROR_SELF_SIGNED -6 +#define X509_VFY_ERROR_INVALID_CHAIN -7 +#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 +#define X509_INVALID_PRIV_KEY -9 +#define X509_MAX_CERTS -10 + +/* + * The Distinguished Name + */ +#define X509_NUM_DN_TYPES 3 +#define X509_COMMON_NAME 0 +#define X509_ORGANIZATION 1 +#define X509_ORGANIZATIONAL_UNIT 2 + +struct _x509_ctx +{ + char *ca_cert_dn[X509_NUM_DN_TYPES]; + char *cert_dn[X509_NUM_DN_TYPES]; + char **subject_alt_dnsnames; + time_t not_before; + time_t not_after; + uint8_t *signature; + uint16_t sig_len; + uint8_t sig_type; + RSA_CTX *rsa_ctx; + bigint *digest; + struct _x509_ctx *next; +}; + +typedef struct _x509_ctx X509_CTX; + +#ifdef CONFIG_SSL_CERT_VERIFICATION +typedef struct +{ + X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; +} CA_CERT_CTX; +#endif + +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); +void x509_free(X509_CTX *x509_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); +#endif +#ifdef CONFIG_SSL_FULL_MODE +void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx); +const char * x509_display_error(int error); +#endif + +/************************************************************************** + * ASN1 declarations + **************************************************************************/ +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_OID 0x06 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_PRINTABLE_STR 0x13 +#define ASN1_TELETEX_STR 0x14 +#define ASN1_IA5_STR 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNICODE_STR 0x1e +#define ASN1_SEQUENCE 0x30 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_SET 0x31 +#define ASN1_V3_DATA 0xa3 +#define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_V3_DATA 0xa3 + +#define SIG_TYPE_MD2 0x02 +#define SIG_TYPE_MD5 0x04 +#define SIG_TYPE_SHA1 0x05 +#define SIG_TYPE_SHA256 0x0b +#define SIG_TYPE_SHA384 0x0c +#define SIG_TYPE_SHA512 0x0d + +uint32_t get_asn1_length(const uint8_t *buf, int *offset); +int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); +int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); +int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object); +int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_name(const uint8_t *cert, int *offset, char *dn[]); +int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_find_subjectaltname(const uint8_t* cert, int offset); +int asn1_compare_dn(char * const dn1[], char * const dn2[]); +#endif /* CONFIG_SSL_CERT_VERIFICATION */ +int asn1_signature_type(const uint8_t *cert, + int *offset, X509_CTX *x509_ctx); + +/************************************************************************** + * MISC declarations + **************************************************************************/ +#define SALT_SIZE 8 + +extern const char * const unsupported_str; + +typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int); +typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); + +int get_file(const char *filename, uint8_t **buf); + +#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) +EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...); +#else + #define print_blob(...) +#endif + +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_int.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_int.h new file mode 100755 index 0000000000..0d81bb287f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_int.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_int.h + * + * Ensure a consistent bit size + */ + +#ifndef HEADER_OS_INT_H +#define HEADER_OS_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WIN32) +typedef UINT8 uint8_t; +typedef INT8 int8_t; +typedef UINT16 uint16_t; +typedef INT16 int16_t; +typedef UINT32 uint32_t; +typedef INT32 int32_t; +typedef UINT64 uint64_t; +typedef INT64 int64_t; +#else /* Not Win32 */ + +#ifdef CONFIG_PLATFORM_SOLARIS +#include +#else +//#include +#endif /* Not Solaris */ + +#endif /* Not Win32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_port.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_port.h new file mode 100755 index 0000000000..4d8a318c94 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_os_port.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2007-2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_port.h + * + * Some stuff to minimise the differences between windows and linux/unix + */ + +#ifndef HEADER_OS_PORT_H +#define HEADER_OS_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#include "../crypto/os_int.h" +#include "c_types.h" +#include "osapi.h" +#include +#include "lwip/app/time.h" + +#if 0 +#define ssl_printf(fmt, args...) os_printf(fmt,## args) +#else +#define ssl_printf(fmt, args...) +#endif + +#define STDCALL +#define EXP_FUNC + +//struct timeval { +// unsigned long tv_sec; /* seconds */ +// unsigned long tv_usec; /* and microseconds */ +//}; + +#define tls_htons(x) ((uint16)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))) +#define tls_ntohs(x) tls_htons(x) +#define tls_htonl(_n) ((uint32)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) +#define tls_ntohl(x) tls_htonl(x) + +#ifndef be16toh +#define be16toh(x) ((uint16)tls_ntohs((uint16)(x))) +#endif + +#ifndef htobe16 +#define htobe16(x) ((uint16)tls_htons((uint16)(x))) +#endif + +#ifndef be32toh +#define be32toh(x) ((uint32)tls_ntohl((uint32)(x))) +#endif + +#ifndef htobe32 +#define htobe32(x) ((uint32)tls_htonl((uint32)(x))) +#endif + +#ifndef be64toh +static __inline__ uint64 be64toh(uint64 __x); +static __inline__ uint64 be64toh(uint64 __x) {return (((uint64)be32toh(__x & (uint64)0xFFFFFFFFULL)) << 32) | ((uint64)be32toh((__x & (uint64)0xFFFFFFFF00000000ULL) >> 32));} +#define be64toh(x) be64toh(x) +#endif + +#ifndef htobe64 +#define htobe64(x) be64toh(x) +#endif + +/* Mutexing definitions */ + +#define SSL_CTX_MUTEX_INIT(A) +#define SSL_CTX_MUTEX_DESTROY(A) +#define SSL_CTX_LOCK(A) +#define SSL_CTX_UNLOCK(A) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_private_key.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_private_key.h new file mode 100755 index 0000000000..ce7985c5a7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_private_key.h @@ -0,0 +1,54 @@ +unsigned char default_private_key[] = { + 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd, + 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e, + 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29, + 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf, + 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7, + 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60, + 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84, + 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04, + 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14, + 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe, + 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91, + 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2, + 0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24, + 0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c, + 0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5, + 0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1, + 0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab, + 0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad, + 0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60, + 0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e, + 0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d, + 0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1, + 0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0, + 0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d, + 0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5, + 0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c, + 0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16, + 0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb, + 0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3, + 0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8, + 0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57, + 0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7, + 0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26, + 0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c, + 0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28, + 0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38, + 0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf, + 0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63, + 0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e, + 0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62, + 0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea, + 0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5, + 0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46, + 0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a, + 0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89, + 0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37, + 0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e, + 0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c, + 0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3, + 0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5 +}; +unsigned int default_private_key_len = 609; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_ssl.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_ssl.h new file mode 100755 index 0000000000..113f73e33e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_ssl.h @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @mainpage axTLS API + * + * @image html axolotl.jpg + * + * The axTLS library has features such as: + * - The TLSv1 SSL client/server protocol + * - No requirement to use any openssl libraries. + * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers. + * - RSA encryption/decryption with variable sized keys (up to 4096 bits). + * - Certificate chaining and peer authentication. + * - Session resumption, session renegotiation. + * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding. + * - Highly configurable compile time options. + * - Portable across many platforms (written in ANSI C), and has language + * bindings in C, C#, VB.NET, Java, Perl and Lua. + * - Partial openssl API compatibility (via a wrapper). + * - A very small footprint (around 50-60kB for the library in 'server-only' + * mode). + * - No dependencies on sockets - can use serial connections for example. + * - A very simple API - ~ 20 functions/methods. + * + * A list of these functions/methods are described below. + * + * @ref c_api + * + * @ref bigint_api + * + * @ref csharp_api + * + * @ref java_api + */ +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/app/time.h" +//typedef long time_t; + +/* need to predefine before ssl_lib.h gets to it */ +#define SSL_SESSION_ID_SIZE 32 + +#include "ssl/ssl_tls1.h" + +/* The optional parameters that can be given to the client/server SSL engine */ +#define SSL_CLIENT_AUTHENTICATION 0x00010000 +#define SSL_SERVER_VERIFY_LATER 0x00020000 +#define SSL_NO_DEFAULT_KEY 0x00040000 +#define SSL_DISPLAY_STATES 0x00080000 +#define SSL_DISPLAY_BYTES 0x00100000 +#define SSL_DISPLAY_CERTS 0x00200000 +#define SSL_DISPLAY_RSA 0x00400000 +#define SSL_CONNECT_IN_PARTS 0x00800000 + +/* errors that can be generated */ +#define SSL_OK 0 +#define SSL_NOT_OK -1 +#define SSL_ERROR_DEAD -2 +#define SSL_CLOSE_NOTIFY -3 +#define SSL_ERROR_CONN_LOST -256 +#define SSL_ERROR_SOCK_SETUP_FAILURE -258 +#define SSL_ERROR_INVALID_HANDSHAKE -260 +#define SSL_ERROR_INVALID_PROT_MSG -261 +#define SSL_ERROR_INVALID_HMAC -262 +#define SSL_ERROR_INVALID_VERSION -263 +#define SSL_ERROR_INVALID_SESSION -265 +#define SSL_ERROR_NO_CIPHER -266 +#define SSL_ERROR_BAD_CERTIFICATE -268 +#define SSL_ERROR_INVALID_KEY -269 +#define SSL_ERROR_FINISHED_INVALID -271 +#define SSL_ERROR_NO_CERT_DEFINED -272 +#define SSL_ERROR_NO_CLIENT_RENOG -273 +#define SSL_ERROR_NOT_SUPPORTED -274 +#define SSL_X509_OFFSET -512 +#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A) + +/* alert types that are recognized */ +#define SSL_ALERT_TYPE_WARNING 1 +#define SLL_ALERT_TYPE_FATAL 2 + +/* these are all the alerts that are recognized */ +#define SSL_ALERT_CLOSE_NOTIFY 0 +#define SSL_ALERT_UNEXPECTED_MESSAGE 10 +#define SSL_ALERT_BAD_RECORD_MAC 20 +#define SSL_ALERT_HANDSHAKE_FAILURE 40 +#define SSL_ALERT_BAD_CERTIFICATE 42 +#define SSL_ALERT_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_DECODE_ERROR 50 +#define SSL_ALERT_DECRYPT_ERROR 51 +#define SSL_ALERT_INVALID_VERSION 70 +#define SSL_ALERT_NO_RENEGOTIATION 100 + +/* The ciphers that are supported */ +#define SSL_AES128_SHA 0x2f +#define SSL_AES256_SHA 0x35 +#define SSL_RC4_128_SHA 0x05 +#define SSL_RC4_128_MD5 0x04 + +/* build mode ids' */ +#define SSL_BUILD_SKELETON_MODE 0x01 +#define SSL_BUILD_SERVER_ONLY 0x02 +#define SSL_BUILD_ENABLE_VERIFICATION 0x03 +#define SSL_BUILD_ENABLE_CLIENT 0x04 +#define SSL_BUILD_FULL_MODE 0x05 + +/* offsets to retrieve configuration information */ +#define SSL_BUILD_MODE 0 +#define SSL_MAX_CERT_CFG_OFFSET 1 +#define SSL_MAX_CA_CERT_CFG_OFFSET 2 +#define SSL_HAS_PEM 3 + +/* default session sizes */ +#define SSL_DEFAULT_SVR_SESS 1 //modify 5->1 by lhan +#define SSL_DEFAULT_CLNT_SESS 1 + +/* X.509/X.520 distinguished name types */ +#define SSL_X509_CERT_COMMON_NAME 0 +#define SSL_X509_CERT_ORGANIZATION 1 +#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2 +#define SSL_X509_CA_CERT_COMMON_NAME 3 +#define SSL_X509_CA_CERT_ORGANIZATION 4 +#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5 + +/* SSL object loader types */ +#define SSL_OBJ_X509_CERT 1 +#define SSL_OBJ_X509_CACERT 2 +#define SSL_OBJ_RSA_KEY 3 +#define SSL_OBJ_PKCS8 4 +#define SSL_OBJ_PKCS12 5 + +/** + * @defgroup c_api Standard C API + * @brief The standard interface in C. + * @{ + */ + +/** + * @brief Establish a new client/server context. + * + * This function is called before any client/server SSL connections are made. + * + * Each new connection will use the this context's private key and + * certificate chain. If a different certificate chain is required, then a + * different context needs to be be used. + * + * There are two threading models supported - a single thread with one + * SSL_CTX can support any number of SSL connections - and multiple threads can + * support one SSL_CTX object each (the default). But if a single SSL_CTX + * object uses many SSL objects in individual threads, then the + * CONFIG_SSL_CTX_MUTEXING option needs to be configured. + * + * @param options [in] Any particular options. At present the options + * supported are: + * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server + * authentication fails. The certificate can be authenticated later with a + * call to ssl_verify_cert(). + * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication + * i.e. each handshake will include a "certificate request" message from the + * server. Only available if verification has been enabled. + * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences + * during the handshake. + * - SSL_DISPLAY_STATES (full mode build only): Display the state changes + * during the handshake. + * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that + * are passed during a handshake. + * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that + * are passed during a handshake. + * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of + * ssl_client_new(). + * @param num_sessions [in] The number of sessions to be used for session + * caching. If this value is 0, then there is no session caching. This option + * is not used in skeleton mode. + * @return A client/server context. + */ +EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions); + +/** + * @brief Remove a client/server context. + * + * Frees any used resources used by this context. Each connection will be + * sent a "Close Notify" alert (if possible). + * @param ssl_ctx [in] The client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); + +/** + * @brief (server only) Establish a new SSL connection to an SSL client. + * + * It is up to the application to establish the logical connection (whether it + * is a socket, serial connection etc). + * @param ssl_ctx [in] The server context. + * @param client_fd [in] The client's file descriptor. + * @return An SSL object reference. + */ +//EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); + +EXP_FUNC SSL *STDCALL sslserver_new(SSL_CTX *ssl_ctx, struct tcp_pcb* client_pcb); +/** + * @brief (client only) Establish a new SSL connection to an SSL server. + * + * It is up to the application to establish the initial logical connection + * (whether it is a socket, serial connection etc). + * + * This is a normally a blocking call - it will finish when the handshake is + * complete (or has failed). To use in non-blocking mode, set + * SSL_CONNECT_IN_PARTS in ssl_ctx_new(). + * @param ssl_ctx [in] The client context. + * @param client_fd [in] The client's file descriptor. + * @param session_id [in] A 32 byte session id for session resumption. This + * can be null if no session resumption is being used or required. This option + * is not used in skeleton mode. + * @param sess_id_size The size of the session id (max 32) + * @return An SSL object reference. Use ssl_handshake_status() to check + * if a handshake succeeded. + */ +//EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size); + +EXP_FUNC SSL *STDCALL SSLClient_new(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb, const + uint8_t *session_id, uint8_t sess_id_size); +/** + * @brief Free any used resources on this connection. + + * A "Close Notify" message is sent on this connection (if possible). It is up + * to the application to close the socket or file descriptor. + * @param ssl [in] The ssl object reference. + */ +EXP_FUNC void STDCALL ssl_free(SSL *ssl); + +/** + * @brief Read the SSL data stream. + * If the socket is non-blocking and data is blocked then SSO_OK will be + * returned. + * @param ssl [in] An SSL object reference. + * @param in_data [out] If the read was successful, a pointer to the read + * buffer will be here. Do NOT ever free this memory as this buffer is used in + * sucessive calls. If the call was unsuccessful, this value will be null. + * @return The number of decrypted bytes: + * - if > 0, then the handshaking is complete and we are returning the number + * of decrypted bytes. + * - SSL_OK if the handshaking stage is successful (but not yet complete). + * - < 0 if an error. + * @see ssl.h for the error code list. + * @note Use in_data before doing any successive ssl calls. + */ +EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); + +/** + * @brief Write to the SSL data stream. + * if the socket is non-blocking and data is blocked then a check is made + * to ensure that all data is sent (i.e. blocked mode is forced). + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); + +/** + * @brief Find an ssl object based on a file descriptor. + * + * Goes through the list of SSL objects maintained in a client/server context + * to look for a file descriptor match. + * @param ssl_ctx [in] The client/server context. + * @param client_fd [in] The file descriptor. + * @return A reference to the SSL object. Returns null if the object could not + * be found. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @param ssl [in] An SSL object reference. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ +EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl); + +/** + * @brief Get the session id size for a handshake. + * + * This will normally be 32 but could be 0 (no session id) or something else. + * @param ssl [in] An SSL object reference. + * @return The size of the session id. + */ +EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); + +/** + * @brief Return the cipher id (in the SSL form). + * @param ssl [in] An SSL object reference. + * @return The cipher id. This will be one of the following: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_RC4_128_SHA (0x05) + * - SSL_RC4_128_MD5 (0x04) + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); + +/** + * @brief Return the status of the handshake. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl); + +/** + * @brief Retrieve various parameters about the axTLS engine. + * @param offset [in] The configuration offset. It will be one of the following: + * - SSL_BUILD_MODE The build mode. This will be one of the following: + * - SSL_BUILD_SERVER_ONLY (basic server mode) + * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication) + * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties) + * - SSL_BUILD_FULL_MODE (client/server with diagnostics) + * - SSL_BUILD_SKELETON_MODE (skeleton mode) + * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed. + * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed. + * - SSL_HAS_PEM 1 if supported + * @return The value of the requested parameter. + */ +EXP_FUNC int STDCALL ssl_get_config(int offset); + +/** + * @brief Display why the handshake failed. + * + * This call is only useful in a 'full mode' build. The output is to stdout. + * @param error_code [in] An error code. + * @see ssl.h for the error code list. + */ +//EXP_FUNC void STDCALL ssl_display_error(int error_code); + +/** + * @brief Authenticate a received certificate. + * + * This call is usually made by a client after a handshake is complete and the + * context is in SSL_SERVER_VERIFY_LATER mode. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); + +/** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); + +/** + * @brief Retrieve a Subject Alternative DNSName + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's DNS + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param dnsindex [in] The index of the DNS name to retrieve. + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); + +/** + * @brief Force the client to perform its handshake again. + * + * For a client this involves sending another "client hello" message. + * For the server is means sending a "hello request" message. + * + * This is a blocking call on the client (until the handshake completes). + * + * @param ssl [in] An SSL object reference. + * @return SSL_OK if renegotiation instantiation was ok + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl); + +/** + * @brief Process a file that is in binary DER or ASCII PEM format. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the file. Can be one of: + * - SSL_OBJ_X509_CERT (no password required) + * - SSL_OBJ_X509_CACERT (no password required) + * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) + * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported) + * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported) + * + * PEM files are automatically detected (if supported). The object type is + * also detected, and so is not relevant for these types of files. + * @param filename [in] The location of a file in DER/PEM format. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @note Not available in skeleton build mode. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password); + +/** + * @brief Process binary data. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the memory data. + * @param data [in] The binary data to be loaded. + * @param len [in] The amount of data to be loaded. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @see ssl_obj_load for more details on obj_type. + */ +EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +/** + * @brief Create an X.509 certificate. + * + * This certificate is a self-signed v1 cert with a fixed start/stop validity + * times. It is signed with an internal private key in ssl_ctx. + * + * @param ssl_ctx [in] The client/server context. + * @param options [in] Not used yet. + * @param dn [in] An array of distinguished name strings. The array is defined + * by: + * - SSL_X509_CERT_COMMON_NAME (0) + * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the + * hostname will be used. + * - SSL_X509_CERT_ORGANIZATION (1) + * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME + * will be used. + * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2) + * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional. + * @param cert_data [out] The certificate as a sequence of bytes. + * @return < 0 if an error, or the size of the certificate in bytes. + * @note cert_data must be freed when there is no more need for it. + */ +EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data); +#endif + +/** + * @brief Return the axTLS library version as a string. + */ +EXP_FUNC const char * STDCALL ssl_version(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_tls1.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_tls1.h new file mode 100755 index 0000000000..5788394f89 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_tls1.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file tls1.h + * + * @brief The definitions for the TLS library. + */ +#ifndef HEADER_SSL_LIB_H +#define HEADER_SSL_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "c_types.h" +#include "ssl/ssl_version.h" +#include "ssl/ssl_config.h" +//#include "../crypto/os_int.h" +#include "ssl/ssl_crypto.h" +#include "ssl/ssl_crypto_misc.h" +#include "lwip/tcp.h" + +#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */ +#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */ +#define SSL_RANDOM_SIZE 32 +#define SSL_SECRET_SIZE 48 +#define SSL_FINISHED_HASH_SIZE 12 +#define SSL_RECORD_SIZE 5 +#define SSL_SERVER_READ 0 +#define SSL_SERVER_WRITE 1 +#define SSL_CLIENT_READ 2 +#define SSL_CLIENT_WRITE 3 +#define SSL_HS_HDR_SIZE 4 + +/* the flags we use while establishing a connection */ +#define SSL_NEED_RECORD 0x0001 +#define SSL_TX_ENCRYPTED 0x0002 +#define SSL_RX_ENCRYPTED 0x0004 +#define SSL_SESSION_RESUME 0x0008 +#define SSL_IS_CLIENT 0x0010 +#define SSL_HAS_CERT_REQ 0x0020 +#define SSL_SENT_CLOSE_NOTIFY 0x0040 + +/* some macros to muck around with flag bits */ +#define SET_SSL_FLAG(A) (ssl->flag |= A) +#define CLR_SSL_FLAG(A) (ssl->flag &= ~A) +#define IS_SET_SSL_FLAG(A) (ssl->flag & A) + +#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */ +#define RT_MAX_PLAIN_LENGTH 1024 +#define RT_EXTRA 1024 +#define BM_RECORD_OFFSET 5 + +#ifdef CONFIG_SSL_SKELETON_MODE +#define NUM_PROTOCOLS 1 +#else +#define NUM_PROTOCOLS 4 +#endif + +#define PARANOIA_CHECK(A, B) if (A < B) { \ + ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; } + +/* protocol types */ +enum +{ + PT_CHANGE_CIPHER_SPEC = 20, + PT_ALERT_PROTOCOL, + PT_HANDSHAKE_PROTOCOL, + PT_APP_PROTOCOL_DATA +}; + +/* handshaking types */ +enum +{ + HS_HELLO_REQUEST, + HS_CLIENT_HELLO, + HS_SERVER_HELLO, + HS_CERTIFICATE = 11, + HS_SERVER_KEY_XCHG, + HS_CERT_REQ, + HS_SERVER_HELLO_DONE, + HS_CERT_VERIFY, + HS_CLIENT_KEY_XCHG, + HS_FINISHED = 20 +}; + +typedef struct +{ + uint8_t cipher; + uint8_t key_size; + uint8_t iv_size; + uint8_t key_block_size; + uint8_t padding_size; + uint8_t digest_size; + hmac_func hmac; + crypt_func encrypt; + crypt_func decrypt; +} cipher_info_t; + +struct _SSLObjLoader +{ + uint8_t *buf; + int len; +}; + +typedef struct _SSLObjLoader SSLObjLoader; + +typedef struct +{ + time_t conn_time; + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t master_secret[SSL_SECRET_SIZE]; +} SSL_SESSION; + +typedef struct +{ + uint8_t *buf; + int size; +} SSL_CERT; + +typedef struct +{ + MD5_CTX md5_ctx; + SHA1_CTX sha1_ctx; + uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE]; + uint8_t *key_block; + uint8_t master_secret[SSL_SECRET_SIZE]; + uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */ + uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */ + uint16_t bm_proc_index; +} DISPOSABLE_CTX; + +struct _SSL +{ + uint32_t flag; + uint16_t need_bytes; + uint16_t got_bytes; + uint8_t record_type; + uint8_t cipher; + uint8_t sess_id_size; + uint8_t version; + uint8_t client_version; + sint16_t next_state; + sint16_t hs_status; + DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */ + //int client_fd; + struct tcp_pcb *SslClient_pcb;//add by ives 12.12.2013 + void *reserve; //modify by Liuhan 09.22.2015 + const cipher_info_t *cipher_info; + void *encrypt_ctx; + void *decrypt_ctx; +// uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA]; + uint8 *bm_all_data;//fix by Liuh 01.04.2015 + uint8_t *bm_data; + uint16_t bm_index; + uint16_t bm_read_index; + struct _SSL *next; /* doubly linked list */ + struct _SSL *prev; + struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */ +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t session_index; + SSL_SESSION *session; +#endif +#ifdef CONFIG_SSL_CERT_VERIFICATION + X509_CTX *x509_ctx; +#endif + + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */ + uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */ + uint8_t read_sequence[8]; /* 64 bit sequence number */ + uint8_t write_sequence[8]; /* 64 bit sequence number */ + uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */ +}; + +typedef struct _SSL SSL; + +struct _SSL_CTX +{ + uint32_t options; + uint8_t chain_length; + RSA_CTX *rsa_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION + CA_CERT_CTX *ca_cert_ctx; +#endif + SSL *head; + SSL *tail; + SSL_CERT certs[CONFIG_SSL_MAX_CERTS]; +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t num_sessions; + SSL_SESSION **ssl_sessions; +#endif +#ifdef CONFIG_SSL_CTX_MUTEXING + SSL_CTX_MUTEX_TYPE mutex; +#endif +#ifdef CONFIG_OPENSSL_COMPATIBLE + void *bonus_attr; +#endif +}; + +typedef struct _SSL_CTX SSL_CTX; + +/* backwards compatibility */ +typedef struct _SSL_CTX SSLCTX; + +extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS]; + +SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd); +SSL *ssl_new_context(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb); +void disposable_new(SSL *ssl); +void disposable_free(SSL *ssl); +int send_packet(SSL *ssl, uint8_t protocol, + const uint8_t *in, int length); +int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int process_finished(SSL *ssl, uint8_t *buf, int hs_len); +int process_sslv23_client_hello(SSL *ssl); +int send_alert(SSL *ssl, int error_code); +int send_finished(SSL *ssl); +int send_certificate(SSL *ssl); +int basic_read(SSL *ssl, uint8_t **in_data); +int send_change_cipher_spec(SSL *ssl); +void finished_digest(SSL *ssl, const char *label, uint8_t *digest); +void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret); +void add_packet(SSL *ssl, const uint8_t *pkt, int len); +int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj); +void ssl_obj_free(SSLObjLoader *ssl_obj); +int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int load_key_certs(SSL_CTX *ssl_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx); +#endif +#ifdef CONFIG_SSL_ENABLE_CLIENT +int do_client_connect(SSL *ssl); +#endif + +#ifdef CONFIG_SSL_FULL_MODE +//void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok); +//void DISPLAY_BYTES(SSL *ssl, const char *format, +// const uint8_t *data, int size, ...); +//void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx); +//void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx); +//void DISPLAY_ALERT(SSL *ssl, int alert); +#else +#define DISPLAY_STATE(A,B,C,D) +#define DISPLAY_CERT(A,B) +#define DISPLAY_RSA(A,B) +#define DISPLAY_ALERT(A, B) +#ifdef WIN32 +void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */ + const uint8_t *data, int size, ...); +#else +#define DISPLAY_BYTES(A,B,C,D,...) +#endif +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION +int process_certificate(SSL *ssl, X509_CTX **x509_ctx); +#endif + +SSL_SESSION *ssl_session_update(int max_sessions, + SSL_SESSION *ssl_sessions[], SSL *ssl, + const uint8_t *session_id); +void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_version.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_version.h new file mode 100755 index 0000000000..e8158cc0d9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/ssl/ssl_version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION "1.4.9" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/third_party/include/user_config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/Makefile new file mode 100755 index 0000000000..ad8189ce53 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/Makefile @@ -0,0 +1,51 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +UP_EXTRACT_DIR = .. +GEN_LIBS = liblwip.a +COMPONENTS_liblwip = api/liblwipapi.a \ + app/liblwipapp.a \ + core/liblwipcore.a \ + core/ipv4/liblwipipv4.a \ + netif/liblwipnetif.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += +CCFLAGS += -ffunction-sections -fdata-sections + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/Makefile new file mode 100755 index 0000000000..ef34edcfb3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblwipapi.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_lib.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_lib.c new file mode 100755 index 0000000000..158325b09a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_lib.c @@ -0,0 +1,740 @@ +/** + * @file + * Sequential API External module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* This is the part of the API that is linked with + the application */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api.h" +#include "lwip/tcpip.h" +#include "lwip/memp.h" + +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is also created. + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn* +netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) +{ + struct netconn *conn; + struct api_msg msg; + + conn = netconn_alloc(t, callback); + if (conn != NULL) { + msg.function = do_newconn; + msg.msg.msg.n.proto = proto; + msg.msg.conn = conn; + if (TCPIP_APIMSG(&msg) != ERR_OK) { + LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); + LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); + LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + sys_sem_free(&conn->op_completed); + sys_mbox_free(&conn->recvmbox); + memp_free(MEMP_NETCONN, conn); + return NULL; + } + } + return conn; +} + +/** + * Close a netconn 'connection' and free its resources. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_delete(struct netconn *conn) +{ + struct api_msg msg; + + /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ + if (conn == NULL) { + return ERR_OK; + } + + msg.function = do_delconn; + msg.msg.conn = conn; + tcpip_apimsg(&msg); + + netconn_free(conn); + + /* don't care for return value of do_delconn since it only calls void functions */ + + return ERR_OK; +} + +/** + * Get the local or remote IP address and port of a netconn. + * For RAW netconns, this returns the protocol instead of a port! + * + * @param conn the netconn to query + * @param addr a pointer to which to save the IP address + * @param port a pointer to which to save the port (or protocol for RAW) + * @param local 1 to get the local IP address, 0 to get the remote one + * @return ERR_CONN for invalid connections + * ERR_OK if the information was retrieved + */ +err_t +netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); + + msg.function = do_getaddr; + msg.msg.conn = conn; + msg.msg.msg.ad.ipaddr = addr; + msg.msg.msg.ad.port = port; + msg.msg.msg.ad.local = local; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Bind a netconn to a specific local IP address and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY + * to bind to all addresses) + * @param port the local port to bind the netconn to (not used for RAW) + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_bind; + msg.msg.conn = conn; + msg.msg.msg.bc.ipaddr = addr; + msg.msg.msg.bc.port = port; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Connect a netconn to a specific remote IP address and port. + * + * @param conn the netconn to connect + * @param addr the remote IP address to connect to + * @param port the remote port to connect to (no used for RAW) + * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise + */ +err_t +netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_connect; + msg.msg.conn = conn; + msg.msg.msg.bc.ipaddr = addr; + msg.msg.msg.bc.port = port; + /* This is the only function which need to not block tcpip_thread */ + err = tcpip_apimsg(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Disconnect a netconn from its current peer (only valid for UDP netconns). + * + * @param conn the netconn to disconnect + * @return TODO: return value is not set here... + */ +err_t +netconn_disconnect(struct netconn *conn) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_disconnect; + msg.msg.conn = conn; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Set a TCP netconn into listen mode + * + * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 + * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns + * don't return any error (yet?)) + */ +err_t +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) +{ +#if LWIP_TCP + struct api_msg msg; + err_t err; + + /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ + LWIP_UNUSED_ARG(backlog); + + LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_listen; + msg.msg.conn = conn; +#if TCP_LISTEN_BACKLOG + msg.msg.msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(backlog); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * Accept a new connection on a TCP listening netconn. + * + * @param conn the TCP listen netconn + * @param new_conn pointer where the new connection is stored + * @return ERR_OK if a new connection has been received or an error + * code otherwise + */ +err_t +netconn_accept(struct netconn *conn, struct netconn **new_conn) +{ +#if LWIP_TCP + struct netconn *newconn; + err_t err; +#if TCP_LISTEN_BACKLOG + struct api_msg msg; +#endif /* TCP_LISTEN_BACKLOG */ + + LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); + *new_conn = NULL; + LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;); + + err = conn->last_err; + if (ERR_IS_FATAL(err)) { + /* don't recv on fatal errors: this might block the application task + waiting on acceptmbox forever! */ + return err; + } + +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + + if (newconn == NULL) { + /* connection has been closed */ + NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); + return ERR_CLSD; + } +#if TCP_LISTEN_BACKLOG + /* Let the stack know that we have accepted the connection. */ + msg.function = do_recv; + msg.msg.conn = conn; + /* don't care for the return value of do_recv */ + TCPIP_APIMSG(&msg); +#endif /* TCP_LISTEN_BACKLOG */ + + *new_conn = newconn; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(new_conn); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * Receive data: actual implementation that doesn't care whether pbuf or netbuf + * is received + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf/netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +static err_t +netconn_recv_data(struct netconn *conn, void **new_buf) +{ + void *buf = NULL; + u16_t len; + err_t err; +#if LWIP_TCP + struct api_msg msg; +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); + + err = conn->last_err; + if (ERR_IS_FATAL(err)) { + /* don't recv on fatal errors: this might block the application task + waiting on recvmbox forever! */ + /* @todo: this does not allow us to fetch data that has been put into recvmbox + before the fatal error occurred - is that a problem? */ + return err; + } + +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + +#if LWIP_TCP + if (conn->type == NETCONN_TCP) { + if (!netconn_get_noautorecved(conn) || (buf == NULL)) { + /* Let the stack know that we have taken the data. */ + /* TODO: Speedup: Don't block and wait for the answer here + (to prevent multiple thread-switches). */ + msg.function = do_recv; + msg.msg.conn = conn; + if (buf != NULL) { + msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len; + } else { + msg.msg.msg.r.len = 1; + } + /* don't care for the return value of do_recv */ + TCPIP_APIMSG(&msg); + } + + /* If we are closed, we indicate that we no longer wish to use the socket */ + if (buf == NULL) { + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + /* Avoid to lose any previous error code */ + NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); + return ERR_CLSD; + } + len = ((struct pbuf *)buf)->tot_len; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ +#if (LWIP_UDP || LWIP_RAW) + { + LWIP_ASSERT("buf != NULL", buf != NULL); + len = netbuf_len((struct netbuf *)buf); + } +#endif /* (LWIP_UDP || LWIP_RAW) */ + +#if LWIP_SO_RCVBUF + SYS_ARCH_DEC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); + + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +} + +/** + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) +{ + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && + netconn_type(conn) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf); +} + +/** + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +err_t +netconn_recv(struct netconn *conn, struct netbuf **new_buf) +{ +#if LWIP_TCP + struct netbuf *buf = NULL; + err_t err; +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); + +#if LWIP_TCP + if (conn->type == NETCONN_TCP) { + struct pbuf *p = NULL; + /* This is not a listening netconn, since recvmbox is set */ + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + NETCONN_SET_SAFE_ERR(conn, ERR_MEM); + return ERR_MEM; + } + + err = netconn_recv_data(conn, (void **)&p); + if (err != ERR_OK) { + memp_free(MEMP_NETBUF, buf); + return err; + } + LWIP_ASSERT("p != NULL", p != NULL); + + buf->p = p; + buf->ptr = p; + buf->port = 0; + ip_addr_set_any(&buf->addr); + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; + } else +#endif /* LWIP_TCP */ + { +#if (LWIP_UDP || LWIP_RAW) + return netconn_recv_data(conn, (void **)new_buf); +#endif /* (LWIP_UDP || LWIP_RAW) */ + } +} + +/** + * TCP: update the receive window: by calling this, the application + * tells the stack that it has processed data and is able to accept + * new data. + * ATTENTION: use with care, this is mainly used for sockets! + * Can only be used when calling netconn_set_noautorecved(conn, 1) before. + * + * @param conn the netconn for which to update the receive window + * @param length amount of data processed (ATTENTION: this must be accurate!) + */ +void +netconn_recved(struct netconn *conn, u32_t length) +{ +#if LWIP_TCP + if ((conn != NULL) && (conn->type == NETCONN_TCP) && + (netconn_get_noautorecved(conn))) { + struct api_msg msg; + /* Let the stack know that we have taken the data. */ + /* TODO: Speedup: Don't block and wait for the answer here + (to prevent multiple thread-switches). */ + msg.function = do_recv; + msg.msg.conn = conn; + msg.msg.msg.r.len = length; + /* don't care for the return value of do_recv */ + TCPIP_APIMSG(&msg); + } +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(length); +#endif /* LWIP_TCP */ +} + +/** + * Send data (in form of a netbuf) to a specific remote IP address and port. + * Only to be used for UDP and RAW netconns (not TCP). + * + * @param conn the netconn over which to send data + * @param buf a netbuf containing the data to send + * @param addr the remote IP address to which to send the data + * @param port the remote port to which to send the data + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) +{ + if (buf != NULL) { + ip_addr_set(&buf->addr, addr); + buf->port = port; + return netconn_send(conn, buf); + } + return ERR_VAL; +} + +/** + * Send data over a UDP or RAW netconn (that is already connected). + * + * @param conn the UDP or RAW netconn over which to send data + * @param buf a netbuf containing the data to send + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_send(struct netconn *conn, struct netbuf *buf) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); + msg.function = do_send; + msg.msg.conn = conn; + msg.msg.msg.b = buf; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Send data over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param dataptr pointer to the application buffer that contains the data to send + * @param size size of the application data to send + * @param apiflags combination of following flags : + * - NETCONN_COPY: data will be copied into memory belonging to the stack + * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); + if (size == 0) { + return ERR_OK; + } + + /* @todo: for non-blocking write, check if 'size' would ever fit into + snd_queue or snd_buf */ + msg.function = do_write; + msg.msg.conn = conn; + msg.msg.msg.w.dataptr = dataptr; + msg.msg.msg.w.apiflags = apiflags; + msg.msg.msg.w.len = size; + /* For locking the core: this _can_ be delayed on low memory/low send buffer, + but if it is, this is done inside api_msg.c:do_write(), so we can use the + non-blocking version here. */ + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Close ot shutdown a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close or shutdown + * @param how fully close or only shutdown one side? + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +static err_t +netconn_close_shutdown(struct netconn *conn, u8_t how) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_close; + msg.msg.conn = conn; + /* shutting down both ends is the same as closing */ + msg.msg.msg.sd.shut = how; + /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close, + don't use TCPIP_APIMSG here */ + err = tcpip_apimsg(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ + /* shutting down both ends is the same as closing */ + return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); +} + +/** + * Shut down one or both sides of a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to shut down + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) +{ + return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param netif_addr the IP address of the network interface on which to send + * the igmp message + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group(struct netconn *conn, + ip_addr_t *multiaddr, + ip_addr_t *netif_addr, + enum netconn_igmp join_or_leave) +{ + struct api_msg msg; + err_t err; + + LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); + + msg.function = do_join_leave_group; + msg.msg.conn = conn; + msg.msg.msg.jl.multiaddr = multiaddr; + msg.msg.msg.jl.netif_addr = netif_addr; + msg.msg.msg.jl.join_or_leave = join_or_leave; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Execute a DNS query, only one IP address is returned + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated ip_addr_t where to store the resolved IP address + * @return ERR_OK: resolving succeeded + * ERR_MEM: memory error, try again later + * ERR_ARG: dns client not initialized or invalid hostname + * ERR_VAL: dns server response was invalid + */ +err_t +netconn_gethostbyname(const char *name, ip_addr_t *addr) +{ + struct dns_api_msg msg; + err_t err; + sys_sem_t sem; + + LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); + + err = sys_sem_new(&sem, 0); + if (err != ERR_OK) { + return err; + } + + msg.name = name; + msg.addr = addr; + msg.err = &err; + msg.sem = &sem; + + tcpip_callback(do_gethostbyname, &msg); + sys_sem_wait(&sem); + sys_sem_free(&sem); + + return err; +} +#endif /* LWIP_DNS*/ + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_msg.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_msg.c new file mode 100755 index 0000000000..dcb07e9c6a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/api_msg.c @@ -0,0 +1,1540 @@ +/** + * @file + * Sequential API Internal module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" + +#include "lwip/ip.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" + +#include "lwip/memp.h" +#include "lwip/tcpip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" + +#include + +#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) +#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) + +/* forward declarations */ +#if LWIP_TCP +static err_t do_writemore(struct netconn *conn); +static void do_close_internal(struct netconn *conn); +#endif + +#if LWIP_RAW +/** + * Receive callback function for RAW netconns. + * Doesn't 'eat' the packet, only references it and sends it to + * conn->recvmbox + * + * @see raw.h (struct raw_pcb.recv) for parameters and return value + */ +static u8_t +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip_addr_t *addr) +{ + struct pbuf *q; + struct netbuf *buf; + struct netconn *conn; + + LWIP_UNUSED_ARG(addr); + conn = (struct netconn *)arg; + + if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { +#if LWIP_SO_RCVBUF + int recv_avail; + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { + return 0; + } +#endif /* LWIP_SO_RCVBUF */ + /* copy the whole packet into new pbufs */ + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(q != NULL) { + if (pbuf_copy(q, p) != ERR_OK) { + pbuf_free(q); + q = NULL; + } + } + + if (q != NULL) { + u16_t len; + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(q); + return 0; + } + + buf->p = q; + buf->ptr = q; + ip_addr_copy(buf->addr, *ip_current_src_addr()); + buf->port = pcb->protocol; + + len = q->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return 0; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + } + } + + return 0; /* do not eat the packet */ +} +#endif /* LWIP_RAW*/ + +#if LWIP_UDP +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ +static void +recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *addr, u16_t port) +{ + struct netbuf *buf; + struct netconn *conn; + u16_t len; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ + LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_udp must have an argument", arg != NULL); + conn = (struct netconn *)arg; + LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); + +#if LWIP_SO_RCVBUF + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || + ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { +#else /* LWIP_SO_RCVBUF */ + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { +#endif /* LWIP_SO_RCVBUF */ + pbuf_free(p); + return; + } + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(p); + return; + } else { + buf->p = p; + buf->ptr = p; + ip_addr_set(&buf->addr, addr); + buf->port = port; +#if LWIP_NETBUF_RECVINFO + { + const struct ip_hdr* iphdr = ip_current_header(); + /* get the UDP header - always in the first pbuf, ensured by udp_input */ + const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); +#if LWIP_CHECKSUM_ON_COPY + buf->flags = NETBUF_FLAG_DESTADDR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + ip_addr_set(&buf->toaddr, ip_current_dest_addr()); + buf->toport_chksum = udphdr->dest; + } +#endif /* LWIP_NETBUF_RECVINFO */ + } + + len = p->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } +} +#endif /* LWIP_UDP */ + +#if LWIP_TCP +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct netconn *conn; + u16_t len; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); + conn = (struct netconn *)arg; + LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); + + if (conn == NULL) { + return ERR_VAL; + } + if (!sys_mbox_valid(&conn->recvmbox)) { + /* recvmbox already deleted */ + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } + return ERR_OK; + } + /* Unlike for UDP or RAW pcbs, don't check for available space + using recv_avail since that could break the connection + (data is already ACKed) */ + + /* don't overwrite fatal errors! */ + NETCONN_SET_SAFE_ERR(conn, err); + + if (p != NULL) { + len = p->tot_len; + } else { + len = 0; + } + + if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { + /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ + return ERR_MEM; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + + return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn->state == NETCONN_WRITE) { + do_writemore(conn); + } else if (conn->state == NETCONN_CLOSE) { + do_close_internal(conn); + } + /* @todo: implement connect timeout here? */ + + /* Did a nonblocking write fail before? Then check available write-space. */ + if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } + + return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +static err_t +sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn->state == NETCONN_WRITE) { + do_writemore(conn); + } else if (conn->state == NETCONN_CLOSE) { + do_close_internal(conn); + } + + if (conn) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); + } + } + + return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +static void +err_tcp(void *arg, err_t err) +{ + struct netconn *conn; + enum netconn_state old_state; + SYS_ARCH_DECL_PROTECT(lev); + + conn = (struct netconn *)arg; + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + conn->pcb.tcp = NULL; + + /* no check since this is always fatal! */ + SYS_ARCH_PROTECT(lev); + conn->last_err = err; + SYS_ARCH_UNPROTECT(lev); + + /* reset conn->state now before waking up other threads */ + old_state = conn->state; + conn->state = NETCONN_NONE; + + /* Notify the user layer about a connection error. Used to signal + select. */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + /* Try to release selects pending on 'read' or 'write', too. + They will get an error if they actually try to read or write. */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + /* pass NULL-message to recvmbox to wake up pending recv */ + if (sys_mbox_valid(&conn->recvmbox)) { + /* use trypost to prevent deadlock */ + sys_mbox_trypost(&conn->recvmbox, NULL); + } + /* pass NULL-message to acceptmbox to wake up pending accept */ + if (sys_mbox_valid(&conn->acceptmbox)) { + /* use trypost to preven deadlock */ + sys_mbox_trypost(&conn->acceptmbox, NULL); + } + + if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || + (old_state == NETCONN_CONNECT)) { + /* calling do_writemore/do_close_internal is not necessary + since the pcb has already been deleted! */ + int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + + if (!was_nonblocking_connect) { + /* set error return code */ + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + conn->current_msg->err = err; + conn->current_msg = NULL; + /* wake up the waiting task */ + sys_sem_signal(&conn->op_completed); + } + } else { + LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); + } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +static void +setup_tcp(struct netconn *conn) +{ + struct tcp_pcb *pcb; + + pcb = conn->pcb.tcp; + tcp_arg(pcb, conn); + tcp_recv(pcb, recv_tcp); + tcp_sent(pcb, sent_tcp); + tcp_poll(pcb, poll_tcp, 4); + tcp_err(pcb, err_tcp); +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +static err_t +accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + struct netconn *newconn; + struct netconn *conn = (struct netconn *)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); + + if (!sys_mbox_valid(&conn->acceptmbox)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); + return ERR_VAL; + } + + /* We have to set the callback here even though + * the new socket is unknown. conn->socket is marked as -1. */ + newconn = netconn_alloc(conn->type, conn->callback); + if (newconn == NULL) { + return ERR_MEM; + } + newconn->pcb.tcp = newpcb; + setup_tcp(newconn); + /* no protection: when creating the pcb, the netconn is not yet known + to the application thread */ + newconn->last_err = err; + + if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { + /* When returning != ERR_OK, the pcb is aborted in tcp_process(), + so do nothing here! */ + newconn->pcb.tcp = NULL; + /* no need to drain since we know the recvmbox is empty. */ + sys_mbox_free(&newconn->recvmbox); + sys_mbox_set_invalid(&newconn->recvmbox); + netconn_free(newconn); + return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + * @return msg->conn->err, but the return value is currently ignored + */ +static void +pcb_new(struct api_msg_msg *msg) +{ + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + + /* Allocate a PCB for this connection */ + switch(NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + if(msg->conn->pcb.raw == NULL) { + msg->err = ERR_MEM; + break; + } + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp == NULL) { + msg->err = ERR_MEM; + break; + } +#if LWIP_UDPLITE + if (msg->conn->type==NETCONN_UDPLITE) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } +#endif /* LWIP_UDPLITE */ + if (msg->conn->type==NETCONN_UDPNOCHKSUM) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(msg->conn->pcb.tcp == NULL) { + msg->err = ERR_MEM; + break; + } + setup_tcp(msg->conn); + break; +#endif /* LWIP_TCP */ + default: + /* Unsupported netconn type, e.g. protocol disabled */ + msg->err = ERR_VAL; + break; + } +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param msg the api_msg_msg describing the connection type + */ +void +do_newconn(struct api_msg_msg *msg) +{ + msg->err = ERR_OK; + if(msg->conn->pcb.tcp == NULL) { + pcb_new(msg); + } + /* Else? This "new" connection already has a PCB allocated. */ + /* Is this an error condition? Should it be deleted? */ + /* We currently just are happy and return. */ + + TCPIP_APIMSG_ACK(msg); +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is NOT created! + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn* +netconn_alloc(enum netconn_type t, netconn_callback callback) +{ + struct netconn *conn; + int size; + + conn = (struct netconn *)memp_malloc(MEMP_NETCONN); + if (conn == NULL) { + return NULL; + } + + conn->last_err = ERR_OK; + conn->type = t; + conn->pcb.tcp = NULL; + +#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ + (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) + size = DEFAULT_RAW_RECVMBOX_SIZE; +#else + switch(NETCONNTYPE_GROUP(t)) { +#if LWIP_RAW + case NETCONN_RAW: + size = DEFAULT_RAW_RECVMBOX_SIZE; + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + size = DEFAULT_UDP_RECVMBOX_SIZE; + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + size = DEFAULT_TCP_RECVMBOX_SIZE; + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); + break; + } +#endif + + if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { + memp_free(MEMP_NETCONN, conn); + return NULL; + } + if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { + sys_sem_free(&conn->op_completed); + memp_free(MEMP_NETCONN, conn); + return NULL; + } + +#if LWIP_TCP + sys_mbox_set_invalid(&conn->acceptmbox); +#endif + conn->state = NETCONN_NONE; +#if LWIP_SOCKET + /* initialize socket to -1 since 0 is a valid socket */ + conn->socket = -1; +#endif /* LWIP_SOCKET */ + conn->callback = callback; +#if LWIP_TCP + conn->current_msg = NULL; + conn->write_offset = 0; +#endif /* LWIP_TCP */ +#if LWIP_SO_RCVTIMEO + conn->recv_timeout = 0; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; + conn->recv_avail = 0; +#endif /* LWIP_SO_RCVBUF */ + conn->flags = 0; + return conn; +} + +/** + * Delete a netconn and all its resources. + * The pcb is NOT freed (since we might not be in the right thread context do this). + * + * @param conn the netconn to free + */ +void +netconn_free(struct netconn *conn) +{ + LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + LWIP_ASSERT("recvmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("acceptmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + + sys_sem_free(&conn->op_completed); + sys_sem_set_invalid(&conn->op_completed); + + memp_free(MEMP_NETCONN, conn); +} + +/** + * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in + * these mboxes + * + * @param conn the netconn to free + * @bytes_drained bytes drained from recvmbox + * @accepts_drained pending connections drained from acceptmbox + */ +static void +netconn_drain(struct netconn *conn) +{ + void *mem; +#if LWIP_TCP + struct pbuf *p; +#endif /* LWIP_TCP */ + + /* This runs in tcpip_thread, so we don't need to lock against rx packets */ + + /* Delete and drain the recvmbox. */ + if (sys_mbox_valid(&conn->recvmbox)) { + while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +#if LWIP_TCP + if (conn->type == NETCONN_TCP) { + if(mem != NULL) { + p = (struct pbuf*)mem; + /* pcb might be set to NULL already by err_tcp() */ + if (conn->pcb.tcp != NULL) { + tcp_recved(conn->pcb.tcp, p->tot_len); + } + pbuf_free(p); + } + } else +#endif /* LWIP_TCP */ + { + netbuf_delete((struct netbuf *)mem); + } + } + sys_mbox_free(&conn->recvmbox); + sys_mbox_set_invalid(&conn->recvmbox); + } + + /* Delete and drain the acceptmbox. */ +#if LWIP_TCP + if (sys_mbox_valid(&conn->acceptmbox)) { + while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { + struct netconn *newconn = (struct netconn *)mem; + /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ + /* pcb might be set to NULL already by err_tcp() */ + if (conn->pcb.tcp != NULL) { + tcp_accepted(conn->pcb.tcp); + } + /* drain recvmbox */ + netconn_drain(newconn); + if (newconn->pcb.tcp != NULL) { + tcp_abort(newconn->pcb.tcp); + newconn->pcb.tcp = NULL; + } + netconn_free(newconn); + } + sys_mbox_free(&conn->acceptmbox); + sys_mbox_set_invalid(&conn->acceptmbox); + } +#endif /* LWIP_TCP */ +} + +#if LWIP_TCP +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +static void +do_close_internal(struct netconn *conn) +{ + err_t err; + u8_t shut, shut_rx, shut_tx, close; + + LWIP_ASSERT("invalid conn", (conn != NULL)); + LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); + LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); + LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + + shut = conn->current_msg->msg.sd.shut; + shut_rx = shut & NETCONN_SHUT_RD; + shut_tx = shut & NETCONN_SHUT_WR; + /* shutting down both ends is the same as closing */ + close = shut == NETCONN_SHUT_RDWR; + + /* Set back some callback pointers */ + if (close) { + tcp_arg(conn->pcb.tcp, NULL); + } + if (conn->pcb.tcp->state == LISTEN) { + tcp_accept(conn->pcb.tcp, NULL); + } else { + /* some callbacks have to be reset if tcp_close is not successful */ + if (shut_rx) { + tcp_recv(conn->pcb.tcp, NULL); + tcp_accept(conn->pcb.tcp, NULL); + } + if (shut_tx) { + tcp_sent(conn->pcb.tcp, NULL); + } + if (close) { + tcp_poll(conn->pcb.tcp, NULL, 4); + tcp_err(conn->pcb.tcp, NULL); + } + } + /* Try to close the connection */ + if (shut == NETCONN_SHUT_RDWR) { + err = tcp_close(conn->pcb.tcp); + } else { + err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); + } + if (err == ERR_OK) { + /* Closing succeeded */ + conn->current_msg->err = ERR_OK; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + /* Set back some callback pointers as conn is going away */ + conn->pcb.tcp = NULL; + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ + if (close) { + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + } + if (shut_rx) { + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + if (shut_tx) { + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + /* wake up the application task */ + sys_sem_signal(&conn->op_completed); + } else { + /* Closing failed, restore some of the callbacks */ + /* Closing of listen pcb will never fail! */ + LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); + tcp_sent(conn->pcb.tcp, sent_tcp); + tcp_poll(conn->pcb.tcp, poll_tcp, 4); + tcp_err(conn->pcb.tcp, err_tcp); + tcp_arg(conn->pcb.tcp, conn); + /* don't restore recv callback: we don't want to receive any more data */ + } + /* If closing didn't succeed, we get called again either + from poll_tcp or from sent_tcp */ +} +#endif /* LWIP_TCP */ + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_delconn(struct api_msg_msg *msg) +{ + /* @todo TCP: abort running write/connect? */ + if ((msg->conn->state != NETCONN_NONE) && + (msg->conn->state != NETCONN_LISTEN) && + (msg->conn->state != NETCONN_CONNECT)) { + /* this only happens for TCP netconns */ + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else { + LWIP_ASSERT("blocking connect in progress", + (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + + if (msg->conn->pcb.tcp != NULL) { + + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp->recv_arg = NULL; + udp_remove(msg->conn->pcb.udp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + msg->conn->state = NETCONN_CLOSE; + msg->msg.sd.shut = NETCONN_SHUT_RDWR; + msg->conn->current_msg = msg; + do_close_internal(msg->conn); + /* API_EVENT is called inside do_close_internal, before releasing + the application thread, so we can return at this point! */ + return; +#endif /* LWIP_TCP */ + default: + break; + } + msg->conn->pcb.tcp = NULL; + } + /* tcp netconns don't come here! */ + + /* @todo: this lets select make the socket readable and writable, + which is wrong! errfd instead? */ + API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + } + if (sys_sem_valid(&msg->conn->op_completed)) { + sys_sem_signal(&msg->conn->op_completed); + } +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param msg the api_msg_msg pointing to the connection and containing + * the IP address and port to bind to + */ +void +do_bind(struct api_msg_msg *msg) +{ + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_VAL; + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); + break; +#endif /* LWIP_TCP */ + default: + break; + } + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * TCP callback function if a connection (opened by tcp_connect/do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t +do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct netconn *conn; + int was_blocking; + + LWIP_UNUSED_ARG(pcb); + + conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + + LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); + LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", + (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); + + if (conn->current_msg != NULL) { + conn->current_msg->err = err; + } + if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { + setup_tcp(conn); + } + was_blocking = !IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + if (!was_blocking) { + SYS_ARCH_DECL_PROTECT(lev); + SYS_ARCH_PROTECT(lev); + if (conn->last_err == ERR_INPROGRESS) { + conn->last_err = ERR_OK; + } + SYS_ARCH_UNPROTECT(lev); + } + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + if (was_blocking) { + sys_sem_signal(&conn->op_completed); + } + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param msg the api_msg_msg pointing to the connection and containing + * the IP address and port to connect to + */ +void +do_connect(struct api_msg_msg *msg) +{ + if (msg->conn->pcb.tcp == NULL) { + /* This may happen when calling netconn_connect() a second time */ + msg->err = ERR_CLSD; + } else { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + /* Prevent connect while doing any other action. */ + if (msg->conn->state != NETCONN_NONE) { + msg->err = ERR_ISCONN; + } else { + setup_tcp(msg->conn); + msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, + msg->msg.bc.port, do_connected); + if (msg->err == ERR_OK) { + u8_t non_blocking = netconn_is_nonblocking(msg->conn); + msg->conn->state = NETCONN_CONNECT; + SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); + if (non_blocking) { + msg->err = ERR_INPROGRESS; + } else { + msg->conn->current_msg = msg; + /* sys_sem_signal() is called from do_connected (or err_tcp()), + * when the connection is established! */ + return; + } + } + } + break; +#endif /* LWIP_TCP */ + default: + LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); + break; + } + } + sys_sem_signal(&msg->conn->op_completed); +} + +/** + * Connect a pcb contained inside a netconn + * Only used for UDP netconns. + * Called from netconn_disconnect. + * + * @param msg the api_msg_msg pointing to the connection to disconnect + */ +void +do_disconnect(struct api_msg_msg *msg) +{ +#if LWIP_UDP + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { + udp_disconnect(msg->conn->pcb.udp); + msg->err = ERR_OK; + } else +#endif /* LWIP_UDP */ + { + msg->err = ERR_VAL; + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_listen(struct api_msg_msg *msg) +{ + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + if (msg->conn->type == NETCONN_TCP) { + if (msg->conn->state == NETCONN_NONE) { +#if TCP_LISTEN_BACKLOG + struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else /* TCP_LISTEN_BACKLOG */ + struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ + if (lpcb == NULL) { + /* in this case, the old pcb is still allocated */ + msg->err = ERR_MEM; + } else { + /* delete the recvmbox and allocate the acceptmbox */ + if (sys_mbox_valid(&msg->conn->recvmbox)) { + /** @todo: should we drain the recvmbox here? */ + sys_mbox_free(&msg->conn->recvmbox); + sys_mbox_set_invalid(&msg->conn->recvmbox); + } + msg->err = ERR_OK; + if (!sys_mbox_valid(&msg->conn->acceptmbox)) { + msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); + } + if (msg->err == ERR_OK) { + msg->conn->state = NETCONN_LISTEN; + msg->conn->pcb.tcp = lpcb; + tcp_arg(msg->conn->pcb.tcp, msg->conn); + tcp_accept(msg->conn->pcb.tcp, accept_function); + } else { + /* since the old pcb is already deallocated, free lpcb now */ + tcp_close(lpcb); + msg->conn->pcb.tcp = NULL; + } + } + } + } + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_send(struct api_msg_msg *msg) +{ + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); + } else { + msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); + } + break; +#endif +#if LWIP_UDP + case NETCONN_UDP: +#if LWIP_CHECKSUM_ON_COPY + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } else { + msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, + &msg->msg.b->addr, msg->msg.b->port, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } +#else /* LWIP_CHECKSUM_ON_COPY */ + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); + } else { + msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + break; +#endif /* LWIP_UDP */ + default: + break; + } + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_recv(struct api_msg_msg *msg) +{ + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (msg->conn->type == NETCONN_TCP) { +#if TCP_LISTEN_BACKLOG + if (msg->conn->pcb.tcp->state == LISTEN) { + tcp_accepted(msg->conn->pcb.tcp); + } else +#endif /* TCP_LISTEN_BACKLOG */ + { + u32_t remaining = msg->msg.r.len; + do { + u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; + tcp_recved(msg->conn->pcb.tcp, recved); + remaining -= recved; + }while(remaining != 0); + } + } + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +static err_t +do_writemore(struct netconn *conn) +{ + err_t err = ERR_OK; + void *dataptr; + u16_t len, available; + u8_t write_finished = 0; + size_t diff; + u8_t dontblock = netconn_is_nonblocking(conn) || + (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); + u8_t apiflags = conn->current_msg->msg.w.apiflags; + + LWIP_ASSERT("conn != NULL", conn != NULL); + LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); + LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", + conn->write_offset < conn->current_msg->msg.w.len); + + dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; + diff = conn->current_msg->msg.w.len - conn->write_offset; + if (diff > 0xffffUL) { /* max_u16_t */ + len = 0xffff; +#if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; +#endif + apiflags |= TCP_WRITE_FLAG_MORE; + } else { + len = (u16_t)diff; + } + available = tcp_sndbuf(conn->pcb.tcp); + if (available < len) { + /* don't try to write more than sendbuf */ + len = available; +#if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; +#endif + apiflags |= TCP_WRITE_FLAG_MORE; + } + if (dontblock && (len < conn->current_msg->msg.w.len)) { + /* failed to send all data at once -> nonblocking write not possible */ + err = ERR_MEM; + } + if (err == ERR_OK) { + LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + } + if (dontblock && (err == ERR_MEM)) { + /* nonblocking write failed */ + write_finished = 1; + err = ERR_WOULDBLOCK; + /* let poll_tcp check writable space to mark the pcb + writable again */ + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + /* let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + } else { + /* if OK or memory error, check available space */ + if (((err == ERR_OK) || (err == ERR_MEM)) && + ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + } + + if (err == ERR_OK) { + conn->write_offset += len; + if (conn->write_offset == conn->current_msg->msg.w.len) { + /* everything was written */ + write_finished = 1; + conn->write_offset = 0; + } + tcp_output(conn->pcb.tcp); + } else if (err == ERR_MEM) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called + we do NOT return to the application thread, since ERR_MEM is + only a temporary error! */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + tcp_output(conn->pcb.tcp); + + #if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; + #endif + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + } + } + + if (write_finished) { + /* everything was written: set back connection state + and back to application task */ + conn->current_msg->err = err; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; +#if LWIP_TCPIP_CORE_LOCKING + if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) +#endif + { + sys_sem_signal(&conn->op_completed); + } + } +#if LWIP_TCPIP_CORE_LOCKING + else + return ERR_MEM; +#endif + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_write(struct api_msg_msg *msg) +{ + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + if (msg->conn->type == NETCONN_TCP) { +#if LWIP_TCP + if (msg->conn->state != NETCONN_NONE) { + /* netconn is connecting, closing or in blocking write */ + msg->err = ERR_INPROGRESS; + } else if (msg->conn->pcb.tcp != NULL) { + msg->conn->state = NETCONN_WRITE; + /* set all the variables used by do_writemore */ + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); + msg->conn->current_msg = msg; + msg->conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING + msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; + if (do_writemore(msg->conn) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(&msg->conn->op_completed, 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + do_writemore(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for both cases: if do_writemore was called, don't ACK the APIMSG + since do_writemore ACKs it! */ + return; + } else { + msg->err = ERR_CONN; + } +#else /* LWIP_TCP */ + msg->err = ERR_VAL; +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_getaddr(struct api_msg_msg *msg) +{ + if (msg->conn->pcb.ip != NULL) { + *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : + msg->conn->pcb.ip->remote_ip); + + msg->err = ERR_OK; + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (msg->msg.ad.local) { + *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; + } else { + /* return an error as connecting is only a helper for upper layers */ + msg->err = ERR_CONN; + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + if (msg->msg.ad.local) { + *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; + } else { + if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { + msg->err = ERR_CONN; + } else { + *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; + } + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("invalid netconn_type", 0); + break; + } + } else { + msg->err = ERR_CONN; + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * Close a TCP pcb contained in a netconn + * Called from netconn_close + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_close(struct api_msg_msg *msg) +{ +#if LWIP_TCP + /* @todo: abort running write/connect? */ + if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { + /* this only happens for TCP netconns */ + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { + if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { + /* LISTEN doesn't support half shutdown */ + msg->err = ERR_CONN; + } else { + if (msg->msg.sd.shut & NETCONN_SHUT_RD) { + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + } + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + msg->conn->state = NETCONN_CLOSE; + msg->conn->current_msg = msg; + do_close_internal(msg->conn); + /* for tcp netconns, do_close_internal ACKs the message */ + return; + } + } else +#endif /* LWIP_TCP */ + { + msg->err = ERR_VAL; + } + sys_sem_signal(&msg->conn->op_completed); +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_join_leave_group(struct api_msg_msg *msg) +{ + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); + } else { + msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); + } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ + } + } else { + msg->err = ERR_CONN; + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Callback function that is called when DNS name is resolved + * (or on timeout). A waiting application thread is waked up by + * signaling the semaphore. + */ +static void +do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg*)arg; + + LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); + LWIP_UNUSED_ARG(name); + + if (ipaddr == NULL) { + /* timeout or memory error */ + *msg->err = ERR_VAL; + } else { + /* address was resolved */ + *msg->err = ERR_OK; + *msg->addr = *ipaddr; + } + /* wake up the application task waiting in netconn_gethostbyname */ + sys_sem_signal(msg->sem); +} + +/** + * Execute a DNS query + * Called from netconn_gethostbyname + * + * @param arg the dns_api_msg pointing to the query + */ +void +do_gethostbyname(void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg*)arg; + + *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); + if (*msg->err != ERR_INPROGRESS) { + /* on error or immediate success, wake up the application + * task waiting in netconn_gethostbyname */ + sys_sem_signal(msg->sem); + } +} +#endif /* LWIP_DNS */ + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/err.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/err.c new file mode 100755 index 0000000000..b0a4eb3e15 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/err.c @@ -0,0 +1,75 @@ +/** + * @file + * Error Management module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/err.h" + +#ifdef LWIP_DEBUG + +static const char *err_strerr[] = { + "Ok.", /* ERR_OK 0 */ + "Out of memory error.", /* ERR_MEM -1 */ + "Buffer error.", /* ERR_BUF -2 */ + "Timeout.", /* ERR_TIMEOUT -3 */ + "Routing problem.", /* ERR_RTE -4 */ + "Operation in progress.", /* ERR_INPROGRESS -5 */ + "Illegal value.", /* ERR_VAL -6 */ + "Operation would block.", /* ERR_WOULDBLOCK -7 */ + "Connection aborted.", /* ERR_ABRT -8 */ + "Connection reset.", /* ERR_RST -9 */ + "Connection closed.", /* ERR_CLSD -10 */ + "Not connected.", /* ERR_CONN -11 */ + "Illegal argument.", /* ERR_ARG -12 */ + "Address in use.", /* ERR_USE -13 */ + "Low-level netif error.", /* ERR_IF -14 */ + "Already connected.", /* ERR_ISCONN -15 */ +}; + +/** + * Convert an lwip internal error to a string representation. + * + * @param err an lwip internal err_t + * @return a string representation for err + */ +const char * +lwip_strerr(err_t err) +{ + return err_strerr[-err]; + +} + +#endif /* LWIP_DEBUG */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netbuf.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netbuf.c new file mode 100755 index 0000000000..886f66b059 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netbuf.c @@ -0,0 +1,245 @@ +/** + * @file + * Network buffer management + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netbuf.h" +#include "lwip/memp.h" + +#include + +/** + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * ÉêÇëÒ»¸öеÄnetbuf¿Õ¼ä£¬µ«²»·ÖÅäÈκÎÊý¾Ý¿Õ¼ä + * @return a pointer to a new netbuf + * NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ + struct netbuf *buf; + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf != NULL) { + buf->p = NULL; + buf->ptr = NULL; + ip_addr_set_any(&buf->addr); + buf->port = 0; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + buf->flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ + buf->toport_chksum = 0; +#if LWIP_NETBUF_RECVINFO + ip_addr_set_any(&buf->toaddr); +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ + return buf; + } else { + return NULL; + } +} + +/** + * Deallocate a netbuf allocated by netbuf_new(). + * ÊÍ·ÅÒ»¸önetbuf¿Õ¼ä + * @param buf pointer to a netbuf allocated by netbuf_new() + */ +void +netbuf_delete(struct netbuf *buf) +{ + if (buf != NULL) { + if (buf->p != NULL) { + pbuf_free(buf->p); + buf->p = buf->ptr = NULL; + } + memp_free(MEMP_NETBUF, buf); + } +} + +/** + * Allocate memory for a packet buffer for a given netbuf. + *Ϊnetbuf½á¹¹·ÖÅäsize´óСµÄÊý¾Ý¿Õ¼ä + * @param buf the netbuf for which to allocate a packet buffer + * @param size the size of the packet buffer to allocate + * @return pointer to the allocated memory + * NULL if no memory could be allocated + */ +void * +netbuf_alloc(struct netbuf *buf, u16_t size) +{ + LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); + + /* Deallocate any previously allocated memory. */ + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (buf->p == NULL) { + return NULL; + } + LWIP_ASSERT("check that first pbuf can hold size", + (buf->p->len >= size)); + buf->ptr = buf->p; + return buf->p->payload; +} + +/** + * Free the packet buffer included in a netbuf + *ÊÍ·Ånetbuf½á¹¹Ö¸ÏòµÄÊý¾Ýpbuf + * @param buf pointer to the netbuf which contains the packet buffer to free + */ +void +netbuf_free(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = buf->ptr = NULL; +} + +/** + * Let a netbuf reference existing (non-volatile) data. + * + * @param buf netbuf which should reference the data + * @param dataptr pointer to the data to reference + * @param size size of the data + * @return ERR_OK if data is referenced + * ERR_MEM if data couldn't be referenced due to lack of memory + */ +err_t +netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) +{ + LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + if (buf->p == NULL) { + buf->ptr = NULL; + return ERR_MEM; + } + buf->p->payload = (void*)dataptr; + buf->p->len = buf->p->tot_len = size; + buf->ptr = buf->p; + return ERR_OK; +} + +/** + * Chain one netbuf to another (@see pbuf_chain) + * + * @param head the first netbuf + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning + */ +void +netbuf_chain(struct netbuf *head, struct netbuf *tail) +{ + LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); + LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); + pbuf_cat(head->p, tail->p); + head->ptr = head->p; + memp_free(MEMP_NETBUF, tail); +} + +/** + * Get the data pointer and length of the data inside a netbuf. + * + * @param buf netbuf to get the data from + * @param dataptr pointer to a void pointer where to store the data pointer + * @param len pointer to an u16_t where the length of the data is stored + * @return ERR_OK if the information was retreived, + * ERR_BUF on error. + */ +err_t +netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) +{ + LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); + + if (buf->ptr == NULL) { + return ERR_BUF; + } + *dataptr = buf->ptr->payload; + *len = buf->ptr->len; + return ERR_OK; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the next part. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + * @return -1 if there is no next part + * 1 if moved to the next part but now there is no next part + * 0 if moved to the next part and there are still more parts + */ +s8_t +netbuf_next(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); + if (buf->ptr->next == NULL) { + return -1; + } + buf->ptr = buf->ptr->next; + if (buf->ptr->next == NULL) { + return 1; + } + return 0; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the beginning of the packet. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + */ +void +netbuf_first(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); + buf->ptr = buf->p; +} + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netdb.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netdb.c new file mode 100755 index 0000000000..a7e4e06bca --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netdb.c @@ -0,0 +1,352 @@ +/** + * @file + * API functions for name resolving + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/netdb.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/err.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/api.h" +#include "lwip/dns.h" + +#include +#include + +/** helper struct for gethostbyname_r to access the char* buffer */ +struct gethostbyname_r_helper { + ip_addr_t *addrs; + ip_addr_t addr; + char *aliases; +}; + +/** h_errno is exported in netdb.h for access by applications. */ +#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + +/** define "hostent" variables storage: 0 if we use a static (but unprotected) + * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +#ifndef LWIP_DNS_API_HOSTENT_STORAGE +#define LWIP_DNS_API_HOSTENT_STORAGE 0 +#endif + +/** define "hostent" variables storage */ +#if LWIP_DNS_API_HOSTENT_STORAGE +#define HOSTENT_STORAGE +#else +#define HOSTENT_STORAGE static +#endif /* LWIP_DNS_API_STATIC_HOSTENT */ + +/** + * Returns an entry containing addresses of address family AF_INET + * for the host with name name. + * Due to dns_gethostbyname limitations, only one address is returned. + * + * @param name the hostname to resolve + * @return an entry containing addresses of address family AF_INET + * for the host with name name + */ +struct hostent* +lwip_gethostbyname(const char *name) +{ + err_t err; + ip_addr_t addr; + + /* buffer variables for lwip_gethostbyname() */ + HOSTENT_STORAGE struct hostent s_hostent; + HOSTENT_STORAGE char *s_aliases; + HOSTENT_STORAGE ip_addr_t s_hostent_addr; + HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; + + /* query host IP address */ + err = netconn_gethostbyname(name, &addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + h_errno = HOST_NOT_FOUND; + return NULL; + } + + /* fill hostent */ + s_hostent_addr = addr; + s_phostent_addr[0] = &s_hostent_addr; + s_phostent_addr[1] = NULL; + s_hostent.h_name = (char*)name; + s_hostent.h_aliases = &s_aliases; + s_hostent.h_addrtype = AF_INET; + s_hostent.h_length = sizeof(ip_addr_t); + s_hostent.h_addr_list = (char**)&s_phostent_addr; + +#if DNS_DEBUG + /* dump hostent */ + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases)); + if (s_hostent.h_aliases != NULL) { + u8_t idx; + for ( idx=0; s_hostent.h_aliases[idx]; idx++) { + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx])); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx])); + } + } + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list)); + if (s_hostent.h_addr_list != NULL) { + u8_t idx; + for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); + } + } +#endif /* DNS_DEBUG */ + +#if LWIP_DNS_API_HOSTENT_STORAGE + /* this function should return the "per-thread" hostent after copy from s_hostent */ + return sys_thread_hostent(&s_hostent); +#else + return &s_hostent; +#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ +} + +/** + * Thread-safe variant of lwip_gethostbyname: instead of using a static + * buffer, this function takes buffer and errno pointers as arguments + * and uses these for the result. + * + * @param name the hostname to resolve + * @param ret pre-allocated struct where to store the result + * @param buf pre-allocated buffer where to store additional data + * @param buflen the size of buf + * @param result pointer to a hostent pointer that is set to ret on success + * and set to zero on error + * @param h_errnop pointer to an int where to store errors (instead of modifying + * the global h_errno) + * @return 0 on success, non-zero on error, additional error information + * is stored in *h_errnop instead of h_errno to be thread-safe + */ +int +lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop) +{ + err_t err; + struct gethostbyname_r_helper *h; + char *hostname; + size_t namelen; + int lh_errno; + + if (h_errnop == NULL) { + /* ensure h_errnop is never NULL */ + h_errnop = &lh_errno; + } + + if (result == NULL) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + /* first thing to do: set *result to nothing */ + *result = NULL; + if ((name == NULL) || (ret == NULL) || (buf == 0)) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + + namelen = strlen(name); + if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { + /* buf can't hold the data needed + a copy of name */ + *h_errnop = ERANGE; + return -1; + } + + h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); + hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); + + /* query host IP address */ + err = netconn_gethostbyname(name, &(h->addr)); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + *h_errnop = ENSRNOTFOUND; + return -1; + } + + /* copy the hostname into buf */ + MEMCPY(hostname, name, namelen); + hostname[namelen] = 0; + + /* fill hostent */ + h->addrs = &(h->addr); + h->aliases = NULL; + ret->h_name = (char*)hostname; + ret->h_aliases = &(h->aliases); + ret->h_addrtype = AF_INET; + ret->h_length = sizeof(ip_addr_t); + ret->h_addr_list = (char**)&(h->addrs); + + /* set result != NULL */ + *result = ret; + + /* return success */ + return 0; +} + +/** + * Frees one or more addrinfo structures returned by getaddrinfo(), along with + * any additional storage associated with those structures. If the ai_next field + * of the structure is not null, the entire list of structures is freed. + * + * @param ai struct addrinfo to free + */ +void +lwip_freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + while (ai != NULL) { + next = ai->ai_next; + memp_free(MEMP_NETDB, ai); + ai = next; + } +} + +/** + * Translates the name of a service location (for example, a host name) and/or + * a service name and returns a set of socket addresses and associated + * information to be used in creating a socket with which to address the + * specified service. + * Memory for the result is allocated internally and must be freed by calling + * lwip_freeaddrinfo()! + * + * Due to a limitation in dns_gethostbyname, only the first address of a + * host is returned. + * Also, service names are not supported (only port numbers)! + * + * @param nodename descriptive name or address string of the host + * (may be NULL -> local address) + * @param servname port number as string of NULL + * @param hints structure containing input values that set socktype and protocol + * @param res pointer to a pointer where to store the result (set to NULL on failure) + * @return 0 on success, non-zero on failure + */ +int +lwip_getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + err_t err; + ip_addr_t addr; + struct addrinfo *ai; + struct sockaddr_in *sa = NULL; + int port_nr = 0; + size_t total_size; + size_t namelen = 0; + + if (res == NULL) { + return EAI_FAIL; + } + *res = NULL; + if ((nodename == NULL) && (servname == NULL)) { + return EAI_NONAME; + } + + if (servname != NULL) { + /* service name specified: convert to port number + * @todo?: currently, only ASCII integers (port numbers) are supported! */ + port_nr = atoi(servname); + if ((port_nr <= 0) || (port_nr > 0xffff)) { + return EAI_SERVICE; + } + } + + if (nodename != NULL) { + /* service location specified, try to resolve */ + err = netconn_gethostbyname(nodename, &addr); + if (err != ERR_OK) { + return EAI_FAIL; + } + } else { + /* service location specified, use loopback address */ + ip_addr_set_loopback(&addr); + } + + total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); + if (nodename != NULL) { + namelen = strlen(nodename); + LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); + total_size += namelen + 1; + } + /* If this fails, please report to lwip-devel! :-) */ + LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", + total_size <= NETDB_ELEM_SIZE); + ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); + if (ai == NULL) { + goto memerr; + } + memset(ai, 0, total_size); + sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo)); + /* set up sockaddr */ + inet_addr_from_ipaddr(&sa->sin_addr, &addr); + sa->sin_family = AF_INET; + sa->sin_len = sizeof(struct sockaddr_in); + sa->sin_port = htons((u16_t)port_nr); + + /* set up addrinfo */ + ai->ai_family = AF_INET; + if (hints != NULL) { + /* copy socktype & protocol from hints if specified */ + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + } + if (nodename != NULL) { + /* copy nodename to canonname if specified */ + ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); + MEMCPY(ai->ai_canonname, nodename, namelen); + ai->ai_canonname[namelen] = 0; + } + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_addr = (struct sockaddr*)sa; + + *res = ai; + + return 0; +memerr: + if (ai != NULL) { + memp_free(MEMP_NETDB, ai); + } + return EAI_MEMORY; +} + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netifapi.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netifapi.c new file mode 100755 index 0000000000..43e47203a9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/netifapi.c @@ -0,0 +1,160 @@ +/** + * @file + * Network Interface Sequential API module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netifapi.h" +#include "lwip/tcpip.h" + +/** + * Call netif_add() inside the tcpip_thread context. + */ +void +do_netifapi_netif_add(struct netifapi_msg_msg *msg) +{ + if (!netif_add( msg->netif, + msg->msg.add.ipaddr, + msg->msg.add.netmask, + msg->msg.add.gw, + msg->msg.add.state, + msg->msg.add.init, + msg->msg.add.input)) { + msg->err = ERR_IF; + } else { + msg->err = ERR_OK; + } + TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call netif_set_addr() inside the tcpip_thread context. + */ +void +do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg) +{ + netif_set_addr( msg->netif, + msg->msg.add.ipaddr, + msg->msg.add.netmask, + msg->msg.add.gw); + msg->err = ERR_OK; + TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the + * tcpip_thread context. + */ +void +do_netifapi_netif_common(struct netifapi_msg_msg *msg) +{ + if (msg->msg.common.errtfunc != NULL) { + msg->err = msg->msg.common.errtfunc(msg->netif); + } else { + msg->err = ERR_OK; + msg->msg.common.voidfunc(msg->netif); + } + TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call netif_add() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_add() + */ +err_t +netifapi_netif_add(struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, + void *state, + netif_init_fn init, + netif_input_fn input) +{ + struct netifapi_msg msg; + msg.function = do_netifapi_netif_add; + msg.msg.netif = netif; + msg.msg.msg.add.ipaddr = ipaddr; + msg.msg.msg.add.netmask = netmask; + msg.msg.msg.add.gw = gw; + msg.msg.msg.add.state = state; + msg.msg.msg.add.init = init; + msg.msg.msg.add.input = input; + TCPIP_NETIFAPI(&msg); + return msg.msg.err; +} + +/** + * Call netif_set_addr() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_set_addr() + */ +err_t +netifapi_netif_set_addr(struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw) +{ + struct netifapi_msg msg; + msg.function = do_netifapi_netif_set_addr; + msg.msg.netif = netif; + msg.msg.msg.add.ipaddr = ipaddr; + msg.msg.msg.add.netmask = netmask; + msg.msg.msg.add.gw = gw; + TCPIP_NETIFAPI(&msg); + return msg.msg.err; +} + +/** + * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe + * way by running that function inside the tcpip_thread context. + * + * @note use only for functions where there is only "netif" parameter. + */ +err_t +netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc) +{ + struct netifapi_msg msg; + msg.function = do_netifapi_netif_common; + msg.msg.netif = netif; + msg.msg.msg.common.voidfunc = voidfunc; + msg.msg.msg.common.errtfunc = errtfunc; + TCPIP_NETIFAPI(&msg); + return msg.msg.err; +} + +#endif /* LWIP_NETIF_API */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/sockets.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/sockets.c new file mode 100755 index 0000000000..f3afd63067 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/sockets.c @@ -0,0 +1,2343 @@ +/** + * @file + * Sockets BSD-Like API module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * Improved by Marc Boucher and David Haas + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sockets.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" +#include "lwip/pbuf.h" +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#include + +#define NUM_SOCKETS MEMP_NUM_NETCONN + +/** Contains all internal pointers and states used for a socket */ +struct lwip_sock { + /** sockets currently are built on netconns, each socket has one netconn */ + struct netconn *conn; + /** data that was left from the previous read */ + void *lastdata; + /** offset in the data that was left from the previous read */ + u16_t lastoffset; + /** number of times data was received, set by event_callback(), + tested by the receive and select functions */ + s16_t rcvevent; + /** number of times data was ACKed (free send buffer), set by event_callback(), + tested by select */ + u16_t sendevent; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; + /** last error that occurred on this socket */ + int err; + /** counter of how many threads are waiting for this socket using select */ + int select_waiting; +}; + +/** Description for a task waiting in select */ +struct lwip_select_cb { + /** Pointer to the next waiting task */ + struct lwip_select_cb *next; + /** Pointer to the previous waiting task */ + struct lwip_select_cb *prev; + /** readset passed to select */ + fd_set *readset; + /** writeset passed to select */ + fd_set *writeset; + /** unimplemented: exceptset passed to select */ + fd_set *exceptset; + /** don't signal the same semaphore twice: set to 1 when signalled */ + int sem_signalled; + /** semaphore to wake up a task waiting for select */ + sys_sem_t sem; +}; + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { + /** socket struct for which to change options */ + struct lwip_sock *sock; +#ifdef LWIP_DEBUG + /** socket index for which to change options */ + int s; +#endif /* LWIP_DEBUG */ + /** level of the option to process */ + int level; + /** name of the option to process */ + int optname; + /** set: value to set the option to + * get: value of the option is stored here */ + void *optval; + /** size of *optval */ + socklen_t *optlen; + /** if an error occures, it is temporarily stored here */ + err_t err; +}; + +/** The global array of available sockets */ +static struct lwip_sock sockets[NUM_SOCKETS]; +/** The global list of tasks waiting for select */ +static struct lwip_select_cb *select_cb_list; +/** This counter is increased from lwip_select when the list is chagned + and checked in event_callback to see if it has changed. */ +static volatile int select_cb_ctr; + +/** Table to quickly map an lwIP error (err_t) to a socket error + * by using -err as an index */ +static const int err_to_errno_table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + ENOMEM, /* ERR_MEM -1 Out of memory error. */ + ENOBUFS, /* ERR_BUF -2 Buffer error. */ + EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + EINVAL, /* ERR_VAL -6 Illegal value. */ + EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ + ECONNRESET, /* ERR_RST -9 Connection reset. */ + ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */ + ENOTCONN, /* ERR_CONN -11 Not connected. */ + EIO, /* ERR_ARG -12 Illegal argument. */ + EADDRINUSE, /* ERR_USE -13 Address in use. */ + -1, /* ERR_IF -14 Low-level netif error */ + -1, /* ERR_ISCONN -15 Already connected. */ +}; + +#define ERR_TO_ERRNO_TABLE_SIZE \ + (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) + +#define err_to_errno(err) \ + ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ + err_to_errno_table[-(err)] : EIO) + +#ifdef ERRNO +#ifndef set_errno +#define set_errno(err) errno = (err) +#endif +#else /* ERRNO */ +#define set_errno(err) +#endif /* ERRNO */ + +#define sock_set_errno(sk, e) do { \ + sk->err = (e); \ + set_errno(sk->err); \ +} while (0) + +/* Forward delcaration of some functions */ +static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +static void lwip_getsockopt_internal(void *arg); +static void lwip_setsockopt_internal(void *arg); + +/** + * Initialize this module. This function has to be called before any other + * functions in this module! + */ +void +lwip_socket_init(void) +{ +} + +/** + * Map a externally used socket index to the internal socket representation. + * + * @param s externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +get_socket(int s) +{ + struct lwip_sock *sock; + + if ((s < 0) || (s >= NUM_SOCKETS)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); + set_errno(EBADF); + return NULL; + } + + sock = &sockets[s]; + + if (!sock->conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); + set_errno(EBADF); + return NULL; + } + + return sock; +} + +/** + * Same as get_socket but doesn't set errno + * + * @param s externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +tryget_socket(int s) +{ + if ((s < 0) || (s >= NUM_SOCKETS)) { + return NULL; + } + if (!sockets[s].conn) { + return NULL; + } + return &sockets[s]; +} + +/** + * Allocate a new socket for a given netconn. + * + * @param newconn the netconn for which to allocate a socket + * @param accepted 1 if socket has been created by accept(), + * 0 if socket has been created by socket() + * @return the index of the new socket; -1 on error + */ +static int +alloc_socket(struct netconn *newconn, int accepted) +{ + int i; + SYS_ARCH_DECL_PROTECT(lev); + + /* allocate a new socket identifier */ + for (i = 0; i < NUM_SOCKETS; ++i) { + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + if (!sockets[i].conn) { + sockets[i].conn = newconn; + /* The socket is not yet known to anyone, so no need to protect + after having marked it as used. */ + SYS_ARCH_UNPROTECT(lev); + sockets[i].lastdata = NULL; + sockets[i].lastoffset = 0; + sockets[i].rcvevent = 0; + /* TCP sendbuf is empty, but the socket is not yet writable until connected + * (unless it has been created by accept()). */ + sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); + sockets[i].errevent = 0; + sockets[i].err = 0; + sockets[i].select_waiting = 0; + return i; + } + SYS_ARCH_UNPROTECT(lev); + } + return -1; +} + +/** Free a socket. The socket's netconn must have been + * delete before! + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + */ +static void +free_socket(struct lwip_sock *sock, int is_tcp) +{ + void *lastdata; + SYS_ARCH_DECL_PROTECT(lev); + + lastdata = sock->lastdata; + sock->lastdata = NULL; + sock->lastoffset = 0; + sock->err = 0; + + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + sock->conn = NULL; + SYS_ARCH_UNPROTECT(lev); + /* don't use 'sock' after this line, as another task might have allocated it */ + + if (lastdata != NULL) { + if (is_tcp) { + pbuf_free((struct pbuf *)lastdata); + } else { + netbuf_delete((struct netbuf *)lastdata); + } + } +} + +/* Below this, the well-known socket functions are implemented. + * Use google.com or opengroup.org to get a good description :-) + * + * Exceptions are documented! + */ + +int +lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + struct lwip_sock *sock, *nsock; + struct netconn *newconn; + ip_addr_t naddr; + u16_t port; + int newsock; + struct sockaddr_in sin; + err_t err; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); + sock_set_errno(sock, EWOULDBLOCK); + return -1; + } + + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + LWIP_ASSERT("newconn != NULL", newconn != NULL); + /* Prevent automatic window updates, we do this on our own! */ + netconn_set_noautorecved(newconn, 1); + + /* get the IP address and port of the remote host */ + err = netconn_peer(newconn, &naddr, &port); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); + netconn_delete(newconn); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + /* Note that POSIX only requires us to check addr is non-NULL. addrlen must + * not be NULL if addr is valid. + */ + if (NULL != addr) { + LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + + if (*addrlen > sizeof(sin)) + *addrlen = sizeof(sin); + + MEMCPY(addr, &sin, *addrlen); + } + + newsock = alloc_socket(newconn, 1); + if (newsock == -1) { + netconn_delete(newconn); + sock_set_errno(sock, ENFILE); + return -1; + } + LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); + LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); + nsock = &sockets[newsock]; + + /* See event_callback: If data comes in right away after an accept, even + * though the server task might not have created a new socket yet. + * In that case, newconn->socket is counted down (newconn->socket--), + * so nsock->rcvevent is >= 1 here! + */ + SYS_ARCH_PROTECT(lev); + nsock->rcvevent += (s16_t)(-1 - newconn->socket); + newconn->socket = newsock; + SYS_ARCH_UNPROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); + ip_addr_debug_print(SOCKETS_DEBUG, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); + + sock_set_errno(sock, 0); + return newsock; +} + +int +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + ip_addr_t local_addr; + u16_t local_port; + err_t err; + const struct sockaddr_in *name_in; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* check size, familiy and alignment of 'name' */ + LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && + ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + name_in = (const struct sockaddr_in *)(void*)name; + + inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); + local_port = name_in->sin_port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); + + err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_close(int s) +{ + struct lwip_sock *sock; + int is_tcp = 0; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if(sock->conn != NULL) { + is_tcp = netconn_type(sock->conn) == NETCONN_TCP; + } else { + LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); + } + + netconn_delete(sock->conn); + + free_socket(sock, is_tcp); + set_errno(0); + return 0; +} + +int +lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + err_t err; + const struct sockaddr_in *name_in; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* check size, familiy and alignment of 'name' */ + LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && + ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + name_in = (const struct sockaddr_in *)(void*)name; + + if (name_in->sin_family == AF_UNSPEC) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); + err = netconn_disconnect(sock->conn); + } else { + ip_addr_t remote_addr; + u16_t remote_port; + + inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); + remote_port = name_in->sin_port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); + + err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); + } + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + return 0; +} + +/** + * Set a socket into listen mode. + * The socket may not have been used for another connection previously. + * + * @param s the socket to set to listening mode + * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) + * @return 0 on success, non-zero on failure + */ +int +lwip_listen(int s, int backlog) +{ + struct lwip_sock *sock; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* limit the "backlog" parameter to fit in an u8_t */ + backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); + + err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + struct lwip_sock *sock; + void *buf = NULL; + struct pbuf *p; + u16_t buflen, copylen; + int off = 0; + ip_addr_t *addr; + u16_t port; + u8_t done = 0; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + do { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); + /* Check if there is data left from the last recv operation. */ + if (sock->lastdata) { + buf = sock->lastdata; + } else { + /* If this is non-blocking call, then check first */ + if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && + (sock->rcvevent <= 0)) { + if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); + sock_set_errno(sock, EWOULDBLOCK); + return -1; + } + + /* No data was left from the previous operation, so we try to get + some from the network. */ + if (netconn_type(sock->conn) == NETCONN_TCP) { + err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); + } else { + err = netconn_recv(sock->conn, (struct netbuf **)&buf); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", + err, buf)); + + if (err != ERR_OK) { + if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } + /* We should really do some error checking here. */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", + s, lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + if (err == ERR_CLSD) { + return 0; + } else { + return -1; + } + } + LWIP_ASSERT("buf != NULL", buf != NULL); + sock->lastdata = buf; + } + + if (netconn_type(sock->conn) == NETCONN_TCP) { + p = (struct pbuf *)buf; + } else { + p = ((struct netbuf *)buf)->p; + } + buflen = p->tot_len; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", + buflen, len, off, sock->lastoffset)); + + buflen -= sock->lastoffset; + + if (len > buflen) { + copylen = buflen; + } else { + copylen = (u16_t)len; + } + + /* copy the contents of the received buffer into + the supplied memory pointer mem */ + pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); + + off += copylen; + + if (netconn_type(sock->conn) == NETCONN_TCP) { + LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); + len -= copylen; + if ( (len <= 0) || + (p->flags & PBUF_FLAG_PUSH) || + (sock->rcvevent <= 0) || + ((flags & MSG_PEEK)!=0)) { + done = 1; + } + } else { + done = 1; + } + + /* Check to see from where the data was.*/ + if (done) { + ip_addr_t fromaddr; + if (from && fromlen) { + struct sockaddr_in sin; + + if (netconn_type(sock->conn) == NETCONN_TCP) { + addr = &fromaddr; + netconn_getaddr(sock->conn, addr, &port, 0); + } else { + addr = netbuf_fromaddr((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + inet_addr_from_ipaddr(&sin.sin_addr, addr); + + if (*fromlen > sizeof(sin)) { + *fromlen = sizeof(sin); + } + + MEMCPY(from, &sin, *fromlen); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); + } else { +#if SOCKETS_DEBUG + if (netconn_type(sock->conn) == NETCONN_TCP) { + addr = &fromaddr; + netconn_getaddr(sock->conn, addr, &port, 0); + } else { + addr = netbuf_fromaddr((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); +#endif /* SOCKETS_DEBUG */ + } + } + + /* If we don't peek the incoming message... */ + if ((flags & MSG_PEEK) == 0) { + /* If this is a TCP socket, check if there is data left in the + buffer. If so, it should be saved in the sock structure for next + time around. */ + if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { + sock->lastdata = buf; + sock->lastoffset += copylen; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); + } else { + sock->lastdata = NULL; + sock->lastoffset = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); + if (netconn_type(sock->conn) == NETCONN_TCP) { + pbuf_free((struct pbuf *)buf); + } else { + netbuf_delete((struct netbuf *)buf); + } + } + } + } while (!done); + + if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); + } + sock_set_errno(sock, 0); + return off; +} + +int +lwip_read(int s, void *mem, size_t len) +{ + return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +int +lwip_recv(int s, void *mem, size_t len, int flags) +{ + return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +int +lwip_send(int s, const void *data, size_t size, int flags) +{ + struct lwip_sock *sock; + err_t err; + u8_t write_flags; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", + s, data, size, flags)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn->type != NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) + return lwip_sendto(s, data, size, flags, NULL, 0); +#else /* (LWIP_UDP || LWIP_RAW) */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + + if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) { + if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) { + /* too much data to ever send nonblocking! */ + sock_set_errno(sock, EMSGSIZE); + return -1; + } + } + + write_flags = NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); + err = netconn_write(sock->conn, data, size, write_flags); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? (int)size : -1); +} + +int +lwip_sendto(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + struct lwip_sock *sock; + err_t err; + u16_t short_size; + const struct sockaddr_in *to_in; + u16_t remote_port; +#if !LWIP_TCPIP_CORE_LOCKING + struct netbuf buf; +#endif + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn->type == NETCONN_TCP) { +#if LWIP_TCP + return lwip_send(s, data, size, flags); +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(flags); + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* LWIP_TCP */ + } + + /* @todo: split into multiple sendto's? */ + LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); + short_size = (u16_t)size; + LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || + ((tolen == sizeof(struct sockaddr_in)) && + ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + to_in = (const struct sockaddr_in *)(void*)to; + +#if LWIP_TCPIP_CORE_LOCKING + /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ + { + struct pbuf* p; + ip_addr_t *remote_addr; + +#if LWIP_NETIF_TX_SINGLE_PBUF + p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); + if (p != NULL) { +#if LWIP_CHECKSUM_ON_COPY + u16_t chksum = 0; + if (sock->conn->type != NETCONN_RAW) { + chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + MEMCPY(p->payload, data, size); +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); + if (p != NULL) { + p->payload = (void*)data; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + if (to_in != NULL) { + inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + } else { + remote_addr = IP_ADDR_ANY; + remote_port = 0; + } + + LOCK_TCPIP_CORE(); + if (sock->conn->type == NETCONN_RAW) { + err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); + } else { +#if LWIP_UDP +#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF + err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, + remote_addr, remote_port, 1, chksum); +#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ + err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, + remote_addr, remote_port); +#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ +#else /* LWIP_UDP */ + err = ERR_ARG; +#endif /* LWIP_UDP */ + } + UNLOCK_TCPIP_CORE(); + + pbuf_free(p); + } else { + err = ERR_MEM; + } + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + /* initialize a buffer */ + buf.p = buf.ptr = NULL; +#if LWIP_CHECKSUM_ON_COPY + buf.flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ + if (to) { + inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + netbuf_fromport(&buf) = remote_port; + } else { + remote_port = 0; + ip_addr_set_any(&buf.addr); + netbuf_fromport(&buf) = 0; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", + s, data, short_size, flags)); + ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + + /* make the buffer point to the data that should be sent */ +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(&buf, short_size) == NULL) { + err = ERR_MEM; + } else { +#if LWIP_CHECKSUM_ON_COPY + if (sock->conn->type != NETCONN_RAW) { + u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); + netbuf_set_chksum(&buf, chksum); + err = ERR_OK; + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + err = netbuf_take(&buf, data, short_size); + } + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (err == ERR_OK) { + /* send the data */ + err = netconn_send(sock->conn, &buf); + } + + /* deallocated the buffer */ + netbuf_free(&buf); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? short_size : -1); +} + +int +lwip_socket(int domain, int type, int protocol) +{ + struct netconn *conn; + int i; + + LWIP_UNUSED_ARG(domain); + + /* create a netconn */ + switch (type) { + case SOCK_RAW: + conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_DGRAM: + conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? + NETCONN_UDPLITE : NETCONN_UDP, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_STREAM: + conn = netconn_new_with_callback(NETCONN_TCP, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + if (conn != NULL) { + /* Prevent automatic window updates, we do this on our own! */ + netconn_set_noautorecved(conn, 1); + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", + domain, type, protocol)); + set_errno(EINVAL); + return -1; + } + + if (!conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); + set_errno(ENOBUFS); + return -1; + } + + i = alloc_socket(conn, 0); + + if (i == -1) { + netconn_delete(conn); + set_errno(ENFILE); + return -1; + } + conn->socket = i; + LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); + set_errno(0); + return i; +} + +int +lwip_write(int s, const void *data, size_t size) +{ + return lwip_send(s, data, size, 0); +} + +/** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have + * the sockets enabled that had events. + * + * exceptset is not used for now!!! + * + * @param maxfdp1 the highest socket index in the sets + * @param readset_in: set of sockets to check for read events + * @param writeset_in: set of sockets to check for write events + * @param exceptset_in: set of sockets to check for error events + * @param readset_out: set of sockets that had read events + * @param writeset_out: set of sockets that had write events + * @param exceptset_out: set os sockets that had error events + * @return number of sockets that had events (read/write/exception) (>= 0) + */ +static int +lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, + fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) +{ + int i, nready = 0; + fd_set lreadset, lwriteset, lexceptset; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + FD_ZERO(&lreadset); + FD_ZERO(&lwriteset); + FD_ZERO(&lexceptset); + + /* Go through each socket in each list to count number of sockets which + currently match */ + for(i = 0; i < maxfdp1; i++) { + void* lastdata = NULL; + s16_t rcvevent = 0; + u16_t sendevent = 0; + u16_t errevent = 0; + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket(i); + if (sock != NULL) { + lastdata = sock->lastdata; + rcvevent = sock->rcvevent; + sendevent = sock->sendevent; + errevent = sock->errevent; + } + SYS_ARCH_UNPROTECT(lev); + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { + FD_SET(i, &lreadset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); + nready++; + } + /* See if netconn of this socket is ready for write */ + if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { + FD_SET(i, &lwriteset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); + nready++; + } + /* See if netconn of this socket had an error */ + if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; + } + } + /* copy local sets to the ones provided as arguments */ + *readset_out = lreadset; + *writeset_out = lwriteset; + *exceptset_out = lexceptset; + + LWIP_ASSERT("nready >= 0", nready >= 0); + return nready; +} + +/** + * Processing exceptset is not yet implemented. + */ +int +lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout) +{ + u32_t waitres = 0; + int nready; + fd_set lreadset, lwriteset, lexceptset; + u32_t msectimeout; + struct lwip_select_cb select_cb; + err_t err; + int i; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", + maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, + timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, + timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); + + /* Go through each socket in each list to count number of sockets which + currently match */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + + /* If we don't have any current events, then suspend if we are supposed to */ + if (!nready) { + if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; + } + + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables. */ + + select_cb.next = NULL; + select_cb.prev = NULL; + select_cb.readset = readset; + select_cb.writeset = writeset; + select_cb.exceptset = exceptset; + select_cb.sem_signalled = 0; + err = sys_sem_new(&select_cb.sem, 0); + if (err != ERR_OK) { + /* failed to create semaphore */ + set_errno(ENOMEM); + return -1; + } + + /* Protect the select_cb_list */ + SYS_ARCH_PROTECT(lev); + + /* Put this select_cb on top of list */ + select_cb.next = select_cb_list; + if (select_cb_list != NULL) { + select_cb_list->prev = &select_cb; + } + select_cb_list = &select_cb; + /* Increasing this counter tells even_callback that the list has changed. */ + select_cb_ctr++; + + /* Now we can safely unprotect */ + SYS_ARCH_UNPROTECT(lev); + + /* Increase select_waiting for each socket we are interested in */ + for(i = 0; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock = tryget_socket(i); + LWIP_ASSERT("sock != NULL", sock != NULL); + SYS_ARCH_PROTECT(lev); + sock->select_waiting++; + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + SYS_ARCH_UNPROTECT(lev); + } + } + + /* Call lwip_selscan again: there could have been events between + the last scan (whithout us on the list) and putting us on the list! */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout == 0) { + /* Wait forever */ + msectimeout = 0; + } else { + msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); + if (msectimeout == 0) { + /* Wait 1ms at least (0 means wait forever) */ + msectimeout = 1; + } + } + + waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); + } + /* Increase select_waiting for each socket we are interested in */ + for(i = 0; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock = tryget_socket(i); + LWIP_ASSERT("sock != NULL", sock != NULL); + SYS_ARCH_PROTECT(lev); + sock->select_waiting--; + LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); + SYS_ARCH_UNPROTECT(lev); + } + } + /* Take us off the list */ + SYS_ARCH_PROTECT(lev); + if (select_cb.next != NULL) { + select_cb.next->prev = select_cb.prev; + } + if (select_cb_list == &select_cb) { + LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); + select_cb_list = select_cb.next; + } else { + LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); + select_cb.prev->next = select_cb.next; + } + /* Increasing this counter tells even_callback that the list has changed. */ + select_cb_ctr++; + SYS_ARCH_UNPROTECT(lev); + + sys_sem_free(&select_cb.sem); + if (waitres == SYS_ARCH_TIMEOUT) { + /* Timeout */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; + } + + /* See what's set */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); +return_copy_fdsets: + set_errno(0); + if (readset) { + *readset = lreadset; + } + if (writeset) { + *writeset = lwriteset; + } + if (exceptset) { + *exceptset = lexceptset; + } + + + return nready; +} + +/** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. + */ +static void +event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) +{ + int s; + struct lwip_sock *sock; + struct lwip_select_cb *scb; + int last_select_cb_ctr; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_UNUSED_ARG(len); + + /* Get socket */ + if (conn) { + s = conn->socket; + if (s < 0) { + /* Data comes in right away after an accept, even though + * the server task might not have created a new socket yet. + * Just count down (or up) if that's the case and we + * will use the data later. Note that only receive events + * can happen before the new socket is set up. */ + SYS_ARCH_PROTECT(lev); + if (conn->socket < 0) { + if (evt == NETCONN_EVT_RCVPLUS) { + conn->socket--; + } + SYS_ARCH_UNPROTECT(lev); + return; + } + s = conn->socket; + SYS_ARCH_UNPROTECT(lev); + } + + sock = get_socket(s); + if (!sock) { + return; + } + } else { + return; + } + + SYS_ARCH_PROTECT(lev); + /* Set event as required */ + switch (evt) { + case NETCONN_EVT_RCVPLUS: + sock->rcvevent++; + break; + case NETCONN_EVT_RCVMINUS: + sock->rcvevent--; + break; + case NETCONN_EVT_SENDPLUS: + sock->sendevent = 1; + break; + case NETCONN_EVT_SENDMINUS: + sock->sendevent = 0; + break; + case NETCONN_EVT_ERROR: + sock->errevent = 1; + break; + default: + LWIP_ASSERT("unknown event", 0); + break; + } + + if (sock->select_waiting == 0) { + /* noone is waiting for this socket, no need to check select_cb_list */ + SYS_ARCH_UNPROTECT(lev); + return; + } + + /* Now decide if anyone is waiting for this socket */ + /* NOTE: This code goes through the select_cb_list list multiple times + ONLY IF a select was actually waiting. We go through the list the number + of waiting select calls + 1. This list is expected to be small. */ + + /* At this point, SYS_ARCH is still protected! */ +again: + for (scb = select_cb_list; scb != NULL; scb = scb->next) { + if (scb->sem_signalled == 0) { + /* semaphore not signalled yet */ + int do_signal = 0; + /* Test this select call for our socket */ + if (sock->rcvevent > 0) { + if (scb->readset && FD_ISSET(s, scb->readset)) { + do_signal = 1; + } + } + if (sock->sendevent != 0) { + if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { + do_signal = 1; + } + } + if (sock->errevent != 0) { + if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { + do_signal = 1; + } + } + if (do_signal) { + scb->sem_signalled = 1; + /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might + lead to the select thread taking itself off the list, invalidagin the semaphore. */ + sys_sem_signal(&scb->sem); + } + } + /* unlock interrupts with each step */ + last_select_cb_ctr = select_cb_ctr; + SYS_ARCH_UNPROTECT(lev); + /* this makes sure interrupt protection time is short */ + SYS_ARCH_PROTECT(lev); + if (last_select_cb_ctr != select_cb_ctr) { + /* someone has changed select_cb_list, restart at the beginning */ + goto again; + } + } + SYS_ARCH_UNPROTECT(lev); +} + +/** + * Unimplemented: Close one end of a full-duplex connection. + * Currently, the full connection is closed. + */ +int +lwip_shutdown(int s, int how) +{ + struct lwip_sock *sock; + err_t err; + u8_t shut_rx = 0, shut_tx = 0; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + if (netconn_type(sock->conn) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return EOPNOTSUPP; + } + } else { + sock_set_errno(sock, ENOTCONN); + return ENOTCONN; + } + + if (how == SHUT_RD) { + shut_rx = 1; + } else if (how == SHUT_WR) { + shut_tx = 1; + } else if(how == SHUT_RDWR) { + shut_rx = 1; + shut_tx = 1; + } else { + sock_set_errno(sock, EINVAL); + return EINVAL; + } + err = netconn_shutdown(sock->conn, shut_rx, shut_tx); + + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? 0 : -1); +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ + struct lwip_sock *sock; + struct sockaddr_in sin; + ip_addr_t naddr; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + + /* get the IP address and port */ + netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); + + sin.sin_port = htons(sin.sin_port); + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + + if (*namelen > sizeof(sin)) { + *namelen = sizeof(sin); + } + + MEMCPY(name, &sin, *namelen); + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 0); +} + +int +lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 1); +} + +int +lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + err_t err = ERR_OK; + struct lwip_sock *sock = get_socket(s); + struct lwip_setgetsockopt_data data; + + if (!sock) { + return -1; + } + + if ((NULL == optval) || (NULL == optlen)) { + sock_set_errno(sock, EFAULT); + return -1; + } + + /* Do length and type checks for the various options first, to keep it readable. */ + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + case SO_ACCEPTCONN: + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_ERROR: + case SO_KEEPALIVE: + /* UNIMPL case SO_CONTIMEO: */ + /* UNIMPL case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ + /* UNIMPL case SO_OOBINLINE: */ + /* UNIMPL case SO_SNDBUF: */ + /* UNIMPL case SO_RCVLOWAT: */ + /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE + case SO_REUSEADDR: + case SO_REUSEPORT: +#endif /* SO_REUSE */ + case SO_TYPE: + /* UNIMPL case SO_USELOOPBACK: */ + if (*optlen < sizeof(int)) { + err = EINVAL; + } + break; + + case SO_NO_CHECK: + if (*optlen < sizeof(int)) { + err = EINVAL; + } +#if LWIP_UDP + if ((sock->conn->type != NETCONN_UDP) || + ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { + /* this flag is only available for UDP, not for UDP lite */ + err = EAFNOSUPPORT; + } +#endif /* LWIP_UDP */ + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + /* UNIMPL case IP_HDRINCL: */ + /* UNIMPL case IP_RCVDSTADDR: */ + /* UNIMPL case IP_RCVIF: */ + case IP_TTL: + case IP_TOS: + if (*optlen < sizeof(int)) { + err = EINVAL; + } + break; +#if LWIP_IGMP + case IP_MULTICAST_TTL: + if (*optlen < sizeof(u8_t)) { + err = EINVAL; + } + break; + case IP_MULTICAST_IF: + if (*optlen < sizeof(struct in_addr)) { + err = EINVAL; + } + break; + case IP_MULTICAST_LOOP: + if (*optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; +#endif /* LWIP_IGMP */ + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if (*optlen < sizeof(int)) { + err = EINVAL; + break; + } + + /* If this is no TCP socket, ignore any options. */ + if (sock->conn->type != NETCONN_TCP) + return 0; + + switch (optname) { + case TCP_NODELAY: + case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + case TCP_KEEPINTVL: + case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + if (*optlen < sizeof(int)) { + err = EINVAL; + break; + } + + /* If this is no UDP lite socket, ignore any options. */ + if (sock->conn->type != NETCONN_UDPLITE) { + return 0; + } + + switch (optname) { + case UDPLITE_SEND_CSCOV: + case UDPLITE_RECV_CSCOV: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP && LWIP_UDPLITE*/ +/* UNDEFINED LEVEL */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + } /* switch */ + + + if (err != ERR_OK) { + sock_set_errno(sock, err); + return -1; + } + + /* Now do the actual option processing */ + data.sock = sock; +#ifdef LWIP_DEBUG + data.s = s; +#endif /* LWIP_DEBUG */ + data.level = level; + data.optname = optname; + data.optval = optval; + data.optlen = optlen; + data.err = err; + tcpip_callback(lwip_getsockopt_internal, &data); + sys_arch_sem_wait(&sock->conn->op_completed, 0); + /* maybe lwip_getsockopt_internal has changed err */ + err = data.err; + + sock_set_errno(sock, err); + return err ? -1 : 0; +} + +static void +lwip_getsockopt_internal(void *arg) +{ + struct lwip_sock *sock; +#ifdef LWIP_DEBUG + int s; +#endif /* LWIP_DEBUG */ + int level, optname; + void *optval; + struct lwip_setgetsockopt_data *data; + + LWIP_ASSERT("arg != NULL", arg != NULL); + + data = (struct lwip_setgetsockopt_data*)arg; + sock = data->sock; +#ifdef LWIP_DEBUG + s = data->s; +#endif /* LWIP_DEBUG */ + level = data->level; + optname = data->optname; + optval = data->optval; + + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + /* The option flags */ + case SO_ACCEPTCONN: + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE + case SO_REUSEADDR: + case SO_REUSEPORT: +#endif /* SO_REUSE */ + /*case SO_USELOOPBACK: UNIMPL */ + *(int*)optval = sock->conn->pcb.ip->so_options & optname; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", + s, optname, (*(int*)optval?"on":"off"))); + break; + + case SO_TYPE: + switch (NETCONNTYPE_GROUP(sock->conn->type)) { + case NETCONN_RAW: + *(int*)optval = SOCK_RAW; + break; + case NETCONN_TCP: + *(int*)optval = SOCK_STREAM; + break; + case NETCONN_UDP: + *(int*)optval = SOCK_DGRAM; + break; + default: /* unrecognized socket type */ + *(int*)optval = sock->conn->type; + LWIP_DEBUGF(SOCKETS_DEBUG, + ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", + s, *(int *)optval)); + } /* switch (sock->conn->type) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", + s, *(int *)optval)); + break; + + case SO_ERROR: + /* only overwrite ERR_OK or tempoary errors */ + if ((sock->err == 0) || (sock->err == EINPROGRESS)) { + sock_set_errno(sock, err_to_errno(sock->conn->last_err)); + } + *(int *)optval = sock->err; + sock->err = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: + *(int *)optval = netconn_get_recvtimeout(sock->conn); + break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + *(int *)optval = netconn_get_recvbufsize(sock->conn); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP + case SO_NO_CHECK: + *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; + break; +#endif /* LWIP_UDP*/ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + *(int*)optval = sock->conn->pcb.ip->ttl; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_TOS: + *(int*)optval = sock->conn->pcb.ip->tos; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", + s, *(int *)optval)); + break; +#if LWIP_IGMP + case IP_MULTICAST_TTL: + *(u8_t*)optval = sock->conn->pcb.ip->ttl; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_MULTICAST_IF: + inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", + s, *(u32_t *)optval)); + break; + case IP_MULTICAST_LOOP: + if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t*)optval = 1; + } else { + *(u8_t*)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_IGMP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + switch (optname) { + case TCP_NODELAY: + *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", + s, (*(int*)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPINTVL: + *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPCNT: + *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + switch (optname) { + case UDPLITE_SEND_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled level", 0); + break; + } /* switch (level) */ + sys_sem_signal(&sock->conn->op_completed); +} + +int +lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + struct lwip_sock *sock = get_socket(s); + err_t err = ERR_OK; + struct lwip_setgetsockopt_data data; + + if (!sock) { + return -1; + } + + if (NULL == optval) { + sock_set_errno(sock, EFAULT); + return -1; + } + + /* Do length and type checks for the various options first, to keep it readable. */ + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case case SO_CONTIMEO: */ + /* UNIMPL case case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ + /* UNIMPL case SO_OOBINLINE: */ + /* UNIMPL case SO_SNDBUF: */ + /* UNIMPL case SO_RCVLOWAT: */ + /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE + case SO_REUSEADDR: + case SO_REUSEPORT: +#endif /* SO_REUSE */ + /* UNIMPL case SO_USELOOPBACK: */ + if (optlen < sizeof(int)) { + err = EINVAL; + } + break; + case SO_NO_CHECK: + if (optlen < sizeof(int)) { + err = EINVAL; + } +#if LWIP_UDP + if ((sock->conn->type != NETCONN_UDP) || + ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { + /* this flag is only available for UDP, not for UDP lite */ + err = EAFNOSUPPORT; + } +#endif /* LWIP_UDP */ + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + /* UNIMPL case IP_HDRINCL: */ + /* UNIMPL case IP_RCVDSTADDR: */ + /* UNIMPL case IP_RCVIF: */ + case IP_TTL: + case IP_TOS: + if (optlen < sizeof(int)) { + err = EINVAL; + } + break; +#if LWIP_IGMP + case IP_MULTICAST_TTL: + if (optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_MULTICAST_IF: + if (optlen < sizeof(struct in_addr)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_MULTICAST_LOOP: + if (optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + if (optlen < sizeof(struct ip_mreq)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; +#endif /* LWIP_IGMP */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if (optlen < sizeof(int)) { + err = EINVAL; + break; + } + + /* If this is no TCP socket, ignore any options. */ + if (sock->conn->type != NETCONN_TCP) + return 0; + + switch (optname) { + case TCP_NODELAY: + case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + case TCP_KEEPINTVL: + case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + if (optlen < sizeof(int)) { + err = EINVAL; + break; + } + + /* If this is no UDP lite socket, ignore any options. */ + if (sock->conn->type != NETCONN_UDPLITE) + return 0; + + switch (optname) { + case UDPLITE_SEND_CSCOV: + case UDPLITE_RECV_CSCOV: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP && LWIP_UDPLITE */ +/* UNDEFINED LEVEL */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + } /* switch (level) */ + + + if (err != ERR_OK) { + sock_set_errno(sock, err); + return -1; + } + + + /* Now do the actual option processing */ + data.sock = sock; +#ifdef LWIP_DEBUG + data.s = s; +#endif /* LWIP_DEBUG */ + data.level = level; + data.optname = optname; + data.optval = (void*)optval; + data.optlen = &optlen; + data.err = err; + tcpip_callback(lwip_setsockopt_internal, &data); + sys_arch_sem_wait(&sock->conn->op_completed, 0); + /* maybe lwip_setsockopt_internal has changed err */ + err = data.err; + + sock_set_errno(sock, err); + return err ? -1 : 0; +} + +static void +lwip_setsockopt_internal(void *arg) +{ + struct lwip_sock *sock; +#ifdef LWIP_DEBUG + int s; +#endif /* LWIP_DEBUG */ + int level, optname; + const void *optval; + struct lwip_setgetsockopt_data *data; + + LWIP_ASSERT("arg != NULL", arg != NULL); + + data = (struct lwip_setgetsockopt_data*)arg; + sock = data->sock; +#ifdef LWIP_DEBUG + s = data->s; +#endif /* LWIP_DEBUG */ + level = data->level; + optname = data->optname; + optval = data->optval; + + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + /* The option flags */ + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE + case SO_REUSEADDR: + case SO_REUSEPORT: +#endif /* SO_REUSE */ + /* UNIMPL case SO_USELOOPBACK: */ + if (*(int*)optval) { + sock->conn->pcb.ip->so_options |= optname; + } else { + sock->conn->pcb.ip->so_options &= ~optname; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", + s, optname, (*(int*)optval?"on":"off"))); + break; +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: + netconn_set_recvtimeout(sock->conn, *(int*)optval); + break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + netconn_set_recvbufsize(sock->conn, *(int*)optval); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP + case SO_NO_CHECK: + if (*(int*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); + } + break; +#endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", + s, sock->conn->pcb.ip->ttl)); + break; + case IP_TOS: + sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", + s, sock->conn->pcb.ip->tos)); + break; +#if LWIP_IGMP + case IP_MULTICAST_TTL: + sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); + break; + case IP_MULTICAST_IF: + inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); + break; + case IP_MULTICAST_LOOP: + if (*(u8_t*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); + } + break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { + /* If this is a TCP or a RAW socket, ignore these options. */ + struct ip_mreq *imr = (struct ip_mreq *)optval; + ip_addr_t if_addr; + ip_addr_t multi_addr; + inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); + inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); + if(optname == IP_ADD_MEMBERSHIP){ + data->err = igmp_joingroup(&if_addr, &multi_addr); + } else { + data->err = igmp_leavegroup(&if_addr, &multi_addr); + } + if(data->err != ERR_OK) { + data->err = EADDRNOTAVAIL; + } + } + break; +#endif /* LWIP_IGMP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + switch (optname) { + case TCP_NODELAY: + if (*(int*)optval) { + tcp_nagle_disable(sock->conn->pcb.tcp); + } else { + tcp_nagle_enable(sock->conn->pcb.tcp); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", + s, (*(int *)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + case TCP_KEEPINTVL: + sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_intvl)); + break; + case TCP_KEEPCNT: + sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_cnt)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP*/ +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + switch (optname) { + case UDPLITE_SEND_CSCOV: + if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_tx = 8; + } else { + sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", + s, (*(int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_rx = 8; + } else { + sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", + s, (*(int*)optval)) ); + break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled level", 0); + break; + } /* switch (level) */ + sys_sem_signal(&sock->conn->op_completed); +} + +int +lwip_ioctl(int s, long cmd, void *argp) +{ + struct lwip_sock *sock = get_socket(s); + u8_t val; +#if LWIP_SO_RCVBUF + u16_t buflen = 0; + s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + if (!sock) { + return -1; + } + + switch (cmd) { +#if LWIP_SO_RCVBUF + case FIONREAD: + if (!argp) { + sock_set_errno(sock, EINVAL); + return -1; + } + + SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); + if (recv_avail < 0) { + recv_avail = 0; + } + *((u16_t*)argp) = (u16_t)recv_avail; + + /* Check if there is data left from the last recv operation. /maq 041215 */ + if (sock->lastdata) { + struct pbuf *p = (struct pbuf *)sock->lastdata; + if (netconn_type(sock->conn) != NETCONN_TCP) { + p = ((struct netbuf *)p)->p; + } + buflen = p->tot_len; + buflen -= sock->lastoffset; + + *((u16_t*)argp) += buflen; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); + sock_set_errno(sock, 0); + return 0; +#endif /* LWIP_SO_RCVBUF */ + + case FIONBIO: + val = 0; + if (argp && *(u32_t*)argp) { + val = 1; + } + netconn_set_nonblocking(sock->conn, val); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); + sock_set_errno(sock, 0); + return 0; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + return -1; + } /* switch (cmd) */ +} + +/** A minimal implementation of fcntl. + * Currently only the commands F_GETFL and F_SETFL are implemented. + * Only the flag O_NONBLOCK is implemented. + */ +int +lwip_fcntl(int s, int cmd, int val) +{ + struct lwip_sock *sock = get_socket(s); + int ret = -1; + + if (!sock || !sock->conn) { + return -1; + } + + switch (cmd) { + case F_GETFL: + ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; + break; + case F_SETFL: + if ((val & ~O_NONBLOCK) == 0) { + /* only O_NONBLOCK, all other bits are zero */ + netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); + ret = 0; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); + break; + } + return ret; +} + +#endif /* LWIP_SOCKET */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/tcpip.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/tcpip.c new file mode 100755 index 0000000000..01a49d5623 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/api/tcpip.c @@ -0,0 +1,460 @@ +/** + * @file + * Sequential API Main thread module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/tcpip.h" +#include "lwip/init.h" +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + +/* global variables */ +static tcpip_init_done_fn tcpip_init_done; +static void *tcpip_init_done_arg; +static sys_mbox_t mbox; + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +sys_mutex_t lock_tcpip_core; +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + +/** + * The main lwIP thread. This thread has exclusive access to lwIP core functions + * (unless access to them is not locked). Other threads communicate with this + * thread using message boxes. + * + * It also starts all the timers to make sure they are running in the right + * thread context. + * + * @param arg unused argument + */ +static void +tcpip_thread(void *arg) +{ + struct tcpip_msg *msg; + LWIP_UNUSED_ARG(arg); + + if (tcpip_init_done != NULL) {//Óû§×¢²áÁË×Ô¶¨Òå³õʼ»¯º¯Êý + tcpip_init_done(tcpip_init_done_arg); + } + + LOCK_TCPIP_CORE(); + while (1) { /* MAIN Loop */ + UNLOCK_TCPIP_CORE(); + LWIP_TCPIP_THREAD_ALIVE(); + /* wait for a message, timeouts are processed while waiting */ + sys_timeouts_mbox_fetch(&mbox, (void **)&msg); + LOCK_TCPIP_CORE(); + switch (msg->type) { +#if LWIP_NETCONN + case TCPIP_MSG_API://APIµ÷Óà + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); + msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); + break; +#endif /* LWIP_NETCONN */ + +#if !LWIP_TCPIP_CORE_LOCKING_INPUT + case TCPIP_MSG_INPKT://µ×²ãÊý¾Ý°üÊäÈë + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); +#if LWIP_ETHERNET + if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {//Ö§³ÖARP + ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);//½»¸øARP´¦Àí + } else +#endif /* LWIP_ETHERNET */ + { + ip_input(msg->msg.inp.p, msg->msg.inp.netif);//½»¸øIP´¦Àí + } + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + break; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ + +#if LWIP_NETIF_API + case TCPIP_MSG_NETIFAPI: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); + msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); + break; +#endif /* LWIP_NETIF_API */ + + case TCPIP_MSG_CALLBACK://Éϲã»Øµ÷·½Ê½Ö´ÐÐÒ»¸öº¯Êý + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + +#if LWIP_TCPIP_TIMEOUT + case TCPIP_MSG_TIMEOUT://Éϲã×¢²áÒ»¸ö¶¨Ê±Ê¼þ + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); + sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + case TCPIP_MSG_UNTIMEOUT://Éϲãɾ³ýÒ»¸ö¶¨Ê±Ê¼þ + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); + sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; +#endif /* LWIP_TCPIP_TIMEOUT */ + + default: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + break; + } + } +} + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the Ethernet header or + * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or + * NETIF_FLAG_ETHERNET flags) + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ +#if LWIP_TCPIP_CORE_LOCKING_INPUT + err_t ret; + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); + LOCK_TCPIP_CORE(); +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + ret = ethernet_input(p, inp); + } else +#endif /* LWIP_ETHERNET */ + { + ret = ip_input(p, inp); + } + UNLOCK_TCPIP_CORE(); + return ret; +#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ + struct tcpip_msg *msg; + + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_INPKT; + msg->msg.inp.p = p; + msg->msg.inp.netif = inp; + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + return ERR_MEM; + } + return ERR_OK; + } + return ERR_VAL; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ +} + +/** + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * + * @param f the function to call + * @param ctx parameter passed to f + * @param block 1 to block until the request is posted, 0 to non-blocking mode + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) +{ + struct tcpip_msg *msg; + + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_CALLBACK; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + if (block) { + sys_mbox_post(&mbox, msg); + } else { + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_API, msg); + return ERR_MEM; + } + } + return ERR_OK; + } + return ERR_VAL; +} + +#if LWIP_TCPIP_TIMEOUT +/** + * call sys_timeout in tcpip_thread + * + * @param msec time in milliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_TIMEOUT; + msg->msg.tmo.msecs = msecs; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&mbox, msg); + return ERR_OK; + } + return ERR_VAL; +} + +/** + * call sys_untimeout in tcpip_thread + * + * @param msec time in milliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_UNTIMEOUT; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&mbox, msg); + return ERR_OK; + } + return ERR_VAL; +} +#endif /* LWIP_TCPIP_TIMEOUT */ + +#if LWIP_NETCONN +/** + * Call the lower part of a netconn_* function + * This function is then running in the thread context + * of tcpip_thread and has exclusive access to lwIP core code. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_apimsg(struct api_msg *apimsg) +{ + struct tcpip_msg msg; +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->msg.err = ERR_VAL; +#endif + + if (sys_mbox_valid(&mbox)) {//ÄÚºËÓÊÏäÓÐЧ + msg.type = TCPIP_MSG_API; + msg.msg.apimsg = apimsg; + sys_mbox_post(&mbox, &msg);//ͶµÝÏûÏ¢ + sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);//µÈ´ýÏûÏ¢´¦ÀíÍê±Ï + return apimsg->msg.err; + } + return ERR_VAL; +} + +#if LWIP_TCPIP_CORE_LOCKING +/** + * Call the lower part of a netconn_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_apimsg()) + */ +err_t +tcpip_apimsg_lock(struct api_msg *apimsg) +{ +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->msg.err = ERR_VAL; +#endif + + LOCK_TCPIP_CORE(); + apimsg->function(&(apimsg->msg)); + UNLOCK_TCPIP_CORE(); + return apimsg->msg.err; + +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +#if LWIP_NETIF_API +#if !LWIP_TCPIP_CORE_LOCKING +/** + * Much like tcpip_apimsg, but calls the lower part of a netifapi_* + * function. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return error code given back by the function that was called + */ +err_t +tcpip_netifapi(struct netifapi_msg* netifapimsg) +{ + struct tcpip_msg msg; + + if (sys_mbox_valid(&mbox)) { + err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); + if (err != ERR_OK) { + netifapimsg->msg.err = err; + return err; + } + + msg.type = TCPIP_MSG_NETIFAPI; + msg.msg.netifapimsg = netifapimsg; + sys_mbox_post(&mbox, &msg); + sys_sem_wait(&netifapimsg->msg.sem); + sys_sem_free(&netifapimsg->msg.sem); + return netifapimsg->msg.err; + } + return ERR_VAL; +} +#else /* !LWIP_TCPIP_CORE_LOCKING */ +/** + * Call the lower part of a netifapi_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_netifapi()) + */ +err_t +tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) +{ + LOCK_TCPIP_CORE(); + netifapimsg->function(&(netifapimsg->msg)); + UNLOCK_TCPIP_CORE(); + return netifapimsg->msg.err; +} +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +/** + * Initialize this module: + * - initialize all sub modules + * - start the tcpip_thread + * + * @param initfunc a function to call when tcpip_thread is running and finished initializing + * @param arg argument to pass to initfunc + */ +void +tcpip_init(tcpip_init_done_fn initfunc, void *arg) +{ + lwip_init();//³õʼ»¯ÄÚºË + + tcpip_init_done = initfunc;//×¢²áÓû§×Ô¶¨Ò庯Êý + tcpip_init_done_arg = arg;//º¯Êý²ÎÊý + if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {//´´½¨ÄÚºËÓÊÏä + LWIP_ASSERT("failed to create tcpip_thread mbox", 0); + } +#if LWIP_TCPIP_CORE_LOCKING + if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { + LWIP_ASSERT("failed to create lock_tcpip_core", 0); + } +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);//´´½¨Äں˽ø³Ì +} + +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ + struct pbuf *q = (struct pbuf *)p; + pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ + return tcpip_callback_with_block(pbuf_free_int, p, 0); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ + return tcpip_callback_with_block(mem_free, m, 0); +} + +#endif /* !NO_SYS */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/Makefile new file mode 100755 index 0000000000..929da663dc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblwipapp.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/dhcpserver.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/dhcpserver.c new file mode 100755 index 0000000000..18dd6143fc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/dhcpserver.c @@ -0,0 +1,1179 @@ +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +//#include "crypto/common.h" +#include "osapi.h" +#include "lwip/app/dhcpserver.h" + +#ifndef LWIP_OPEN_SRC +#include "net80211/ieee80211_var.h" +#endif + +#include "user_interface.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +//////////////////////////////////////////////////////////////////////////////////// +//static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +//static u8_t old_xid[4] = {0}; +static const uint32 magic_cookie ICACHE_RODATA_ATTR = 0x63538263; +static struct udp_pcb *pcb_dhcps = NULL; +static struct ip_addr broadcast_dhcps; +static struct ip_addr server_address; +static struct ip_addr client_address;//added + +static struct dhcps_lease dhcps_lease; +//static bool dhcps_lease_flag = true; +static list_node *plist = NULL; +static uint8 offer = 0xFF; +static bool renew = false; +#define DHCPS_LEASE_TIME_DEF (120) +uint32 dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute + +void wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force); +uint32 wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip); + +/****************************************************************************** + * FunctionName : node_insert_to_list + * Description : insert the node to the list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR node_insert_to_list(list_node **phead, list_node* pinsert) +{ + list_node *plist = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + struct dhcps_pool *pdhcps_node = NULL; + if (*phead == NULL) + *phead = pinsert; + else { + plist = *phead; + pdhcps_node = pinsert->pnode; + pdhcps_pool = plist->pnode; + + if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist; + *phead = pinsert; + } else { + while (plist->pnext != NULL) { + pdhcps_pool = plist->pnext->pnode; + if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist->pnext; + plist->pnext = pinsert; + break; + } + plist = plist->pnext; + } + + if(plist->pnext == NULL) { + plist->pnext = pinsert; + } + } + } +// pinsert->pnext = NULL; +} + +/****************************************************************************** + * FunctionName : node_delete_from_list + * Description : remove the node from list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR node_remove_from_list(list_node **phead, list_node* pdelete) +{ + list_node *plist = NULL; + + plist = *phead; + if (plist == NULL){ + *phead = NULL; + } else { + if (plist == pdelete){ + *phead = plist->pnext; + pdelete->pnext = NULL; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete){ + plist->pnext = pdelete->pnext; + pdelete->pnext = NULL; + } + plist = plist->pnext; + } + } + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg��Ϣ�ṹ���������� + * + * @param optptr -- DHCP msg��Ϣλ�� + * @param type -- Ҫ��ӵ�����option + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_msg_type(uint8_t *optptr, uint8_t type) +{ + + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg�ṹ������offerӦ������ + * + * @param optptr -- DHCP msg��Ϣλ�� + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_offer_options(uint8_t *optptr) +{ + struct ip_addr ipadd; + + ipadd.addr = *( (uint32_t *) &server_address); + +#ifdef USE_CLASS_B_NET + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = 4; //length + *optptr++ = 255; + *optptr++ = 240; + *optptr++ = 0; + *optptr++ = 0; +#else + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = 4; + *optptr++ = 255; + *optptr++ = 255; + *optptr++ = 255; + *optptr++ = 0; +#endif + + *optptr++ = DHCP_OPTION_LEASE_TIME; + *optptr++ = 4; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF; + + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = ip4_addr4( &ipadd); + + if (dhcps_router_enabled(offer)){ + struct ip_info if_ip; + os_bzero(&if_ip, sizeof(struct ip_info)); + wifi_get_ip_info(SOFTAP_IF, &if_ip); + + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = 4; + *optptr++ = ip4_addr1( &if_ip.gw); + *optptr++ = ip4_addr2( &if_ip.gw); + *optptr++ = ip4_addr3( &if_ip.gw); + *optptr++ = ip4_addr4( &if_ip.gw); + } + +#ifdef USE_DNS + *optptr++ = DHCP_OPTION_DNS_SERVER; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = ip4_addr4( &ipadd); +#endif + +#ifdef CLASS_B_NET + *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = 255; + *optptr++ = 255; + *optptr++ = 255; +#else + *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = 255; +#endif + + *optptr++ = DHCP_OPTION_INTERFACE_MTU; + *optptr++ = 2; +#ifdef CLASS_B_NET + *optptr++ = 0x05; + *optptr++ = 0xdc; +#else + *optptr++ = 0x02; + *optptr++ = 0x40; +#endif + + *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY; + *optptr++ = 1; + *optptr++ = 0x00; + + *optptr++ = 43; + *optptr++ = 6; + + *optptr++ = 0x01; + *optptr++ = 4; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x02; + + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg�ṹ����ӽ����־���� + * + * @param optptr -- DHCP msg��Ϣλ�� + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_end(uint8_t *optptr) +{ + + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR create_msg(struct dhcps_msg *m) +{ + struct ip_addr client; + + client.addr = client_address.addr; + + m->op = DHCP_REPLY; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = 6; + m->hops = 0; +// os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid)); + m->secs = 0; + m->flags = htons(BOOTP_BROADCAST); + + os_memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); + + os_memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); + os_memset((char *) m->siaddr, 0, sizeof(m->siaddr)); + os_memset((char *) m->giaddr, 0, sizeof(m->giaddr)); + os_memset((char *) m->sname, 0, sizeof(m->sname)); + os_memset((char *) m->file, 0, sizeof(m->file)); + + os_memset((char *) m->options, 0, sizeof(m->options)); + +//For xiaomi crash bug + uint32 magic_cookie1 = magic_cookie; + os_memcpy((char *) m->options, &magic_cookie1, sizeof(magic_cookie1)); +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��OFFER + * + * @param -- m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m) +{ + uint8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + err_t SendOffer_err_t; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPOFFER); + end = add_offer_options(end); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_offer>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_offer>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>pbuf_alloc failed\n"); +#endif + return; + } + SendOffer_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>udp_sendto result %x\n",SendOffer_err_t); +#endif + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_offer>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��NAK��Ϣ + * + * @param m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_nak(struct dhcps_msg *m) +{ + + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + err_t SendNak_err_t; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPNAK); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_nak>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_nak>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_nak>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_nak>>pbuf_alloc failed\n"); +#endif + return; + } + SendNak_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); +#if DHCPS_DEBUG + os_printf("dhcps: send_nak>>udp_sendto result %x\n",SendNak_err_t); +#endif + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_nak>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��ACK��DHCP�ͻ��� + * + * @param m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m) +{ + + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + err_t SendAck_err_t; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPACK); + end = add_offer_options(end); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_ack>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_ack>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>pbuf_alloc failed\n"); +#endif + return; + } + SendAck_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ); +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t); +#endif + + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_ack>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ�� + * + * @param optptr DHCP msg��������� + * @param len ��������Ĵ��?(byte) + * + * @return uint8_t ���ش�����DHCP Server״ֵ̬ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t ICACHE_FLASH_ATTR parse_options(uint8_t *optptr, sint16_t len) +{ + struct ip_addr client; + bool is_dhcp_parse_end = false; + struct dhcps_state s; + + client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP + + u8_t *end = optptr + len; + u16_t type = 0; + + s.state = DHCPS_STATE_IDLE; + + while (optptr < end) { +#if DHCPS_DEBUG + os_printf("dhcps: (sint16_t)*optptr = %d\n", (sint16_t)*optptr); +#endif + switch ((sint16_t) *optptr) { + + case DHCP_OPTION_MSG_TYPE: //53 + type = *(optptr + 2); + break; + + case DHCP_OPTION_REQ_IPADDR://50 + //os_printf("dhcps:0x%08x,0x%08x\n",client.addr,*(uint32*)(optptr+2)); + if( os_memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) { +#if DHCPS_DEBUG + os_printf("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); +#endif + s.state = DHCPS_STATE_ACK; + }else { +#if DHCPS_DEBUG + os_printf("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); +#endif + s.state = DHCPS_STATE_NAK; + } + break; + case DHCP_OPTION_END: + { + is_dhcp_parse_end = true; + } + break; + } + + if(is_dhcp_parse_end){ + break; + } + + optptr += optptr[1] + 2; + } + + switch (type){ + case DHCPDISCOVER://1 + s.state = DHCPS_STATE_OFFER; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_OFFER\n"); +#endif + break; + + case DHCPREQUEST://3 + if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) { + if(renew == true) { + s.state = DHCPS_STATE_ACK; + } else { + s.state = DHCPS_STATE_NAK; + } +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_NAK\n"); +#endif + } + break; + + case DHCPDECLINE://4 + s.state = DHCPS_STATE_IDLE; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + + case DHCPRELEASE://7 + s.state = DHCPS_STATE_RELEASE; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + } +#if DHCPS_DEBUG + os_printf("dhcps: return s.state = %d\n", s.state); +#endif + return s.state; +} +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +static sint16_t ICACHE_FLASH_ATTR parse_msg(struct dhcps_msg *m, u16_t len) +{ + if(os_memcmp((char *)m->options, + &magic_cookie, + sizeof(magic_cookie)) == 0){ + struct ip_addr ip; + os_memcpy(&ip.addr,m->ciaddr,sizeof(ip.addr)); + client_address.addr = wifi_softap_dhcps_client_update(m->chaddr,&ip); + + sint16_t ret = parse_options(&m->options[4], len); + + if(ret == DHCPS_STATE_RELEASE) { + wifi_softap_dhcps_client_leave(m->chaddr,&ip,TRUE); // force to delete + client_address.addr = ip.addr; + } + + return ret; + } + return 0; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * DHCP ��������ݰ���մ���ص�����˺�����LWIP UDPģ������ʱ������ + * ��Ҫ����udp_recv()������LWIP����ע��. + * + * @param arg + * @param pcb ���յ�UDP��Ŀ��ƿ�? + * @param p ���յ���UDP��������? + * @param addr ���ʹ�UDP���Դ�����IP��ַ + * @param port ���ʹ�UDP���Դ�����UDPͨ���˿ں� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR handle_dhcp(void *arg, + struct udp_pcb *pcb, + struct pbuf *p, + struct ip_addr *addr, + uint16_t port) +{ + struct dhcps_msg *pmsg_dhcps = NULL; + sint16_t tlen = 0; + u16_t i = 0; + u16_t dhcps_msg_cnt = 0; + u8_t *p_dhcps_msg = NULL; + u8_t *data = NULL; + +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> receive a packet\n"); +#endif + if (p==NULL) return; + + pmsg_dhcps = (struct dhcps_msg *)os_zalloc(sizeof(struct dhcps_msg)); + if (NULL == pmsg_dhcps){ + pbuf_free(p); + return; + } + p_dhcps_msg = (u8_t *)pmsg_dhcps; + tlen = p->tot_len; + data = p->payload; + +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen); + os_printf("dhcps: handle_dhcp-> p->len = %d\n", p->len); +#endif + + for(i=0; ilen; i++){ + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; + } + + if(p->next != NULL) { +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> p->next != NULL\n"); + os_printf("dhcps: handle_dhcp-> p->next->tot_len = %d\n",p->next->tot_len); + os_printf("dhcps: handle_dhcp-> p->next->len = %d\n",p->next->len); +#endif + + data = p->next->payload; + for(i=0; inext->len; i++){ + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; + } + } + + /* + * DHCP �ͻ���������Ϣ���� + */ +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> parse_msg(p)\n"); +#endif + + switch(parse_msg(pmsg_dhcps, tlen - 240)) { + + case DHCPS_STATE_OFFER://1 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n"); +#endif + send_offer(pmsg_dhcps); + break; + case DHCPS_STATE_ACK://3 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n"); +#endif + send_ack(pmsg_dhcps); + break; + case DHCPS_STATE_NAK://4 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n"); +#endif + send_nak(pmsg_dhcps); + break; + default : + break; + } +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> pbuf_free(p)\n"); +#endif + pbuf_free(p); + os_free(pmsg_dhcps); + pmsg_dhcps = NULL; +} +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR wifi_softap_init_dhcps_lease(uint32 ip) +{ + uint32 softap_ip = 0,local_ip = 0; + uint32 start_ip = 0; + uint32 end_ip = 0; +// if (dhcps_lease_flag) { + if (dhcps_lease.enable == TRUE) { + softap_ip = htonl(ip); + start_ip = htonl(dhcps_lease.start_ip.addr); + end_ip = htonl(dhcps_lease.end_ip.addr); + /*config ip information can't contain local ip*/ + if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) { + dhcps_lease.enable = FALSE; + } else { + /*config ip information must be in the same segment as the local ip*/ + softap_ip >>= 8; + if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip)) + || (end_ip - start_ip > DHCPS_MAX_LEASE)) { + dhcps_lease.enable = FALSE; + } + } + } + + if (dhcps_lease.enable == FALSE) { + local_ip = softap_ip = htonl(ip); + softap_ip &= 0xFFFFFF00; + local_ip &= 0xFF; + if (local_ip >= 0x80) + local_ip -= DHCPS_MAX_LEASE; + else + local_ip ++; + + os_bzero(&dhcps_lease, sizeof(dhcps_lease)); + dhcps_lease.start_ip.addr = softap_ip | local_ip; + dhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1); + dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); + dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); + } +// dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); +// dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); +// os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip); +} +/////////////////////////////////////////////////////////////////////////////////// +void ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info) +{ + struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); + + if(apnetif->dhcps_pcb != NULL) { + udp_remove(apnetif->dhcps_pcb); + } + + pcb_dhcps = udp_new(); + if (pcb_dhcps == NULL || info ==NULL) { + os_printf("dhcps_start(): could not obtain pcb\n"); + } + + apnetif->dhcps_pcb = pcb_dhcps; + + IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255); + + server_address = info->ip; + wifi_softap_init_dhcps_lease(server_address.addr); + + udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT); + udp_recv(pcb_dhcps, handle_dhcp, NULL); +#if DHCPS_DEBUG + os_printf("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n"); +#endif + +} + +void ICACHE_FLASH_ATTR dhcps_stop(void) +{ + struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); + + udp_disconnect(pcb_dhcps); +// dhcps_lease_flag = true; + if(apnetif->dhcps_pcb != NULL) { + udp_remove(apnetif->dhcps_pcb); + apnetif->dhcps_pcb = NULL; + } + + //udp_remove(pcb_dhcps); + list_node *pnode = NULL; + list_node *pback_node = NULL; + struct dhcps_pool* dhcp_node = NULL; + struct ip_addr ip_zero; + + os_memset(&ip_zero,0x0,sizeof(ip_zero)); + pnode = plist; + while (pnode != NULL) { + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&plist, pback_node); + dhcp_node = (struct dhcps_pool*)pback_node->pnode; + //wifi_softap_dhcps_client_leave(dhcp_node->mac,&dhcp_node->ip,TRUE); // force to delete + wifi_softap_set_station_info(dhcp_node->mac, &ip_zero); + os_free(pback_node->pnode); + pback_node->pnode = NULL; + os_free(pback_node); + pback_node = NULL; + } +} + +/****************************************************************************** + * FunctionName : wifi_softap_set_dhcps_lease + * Description : set the lease information of DHCP server + * Parameters : please -- Additional argument to set the lease information, + * Little-Endian. + * Returns : true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease(struct dhcps_lease *please) +{ + struct ip_info info; + uint32 softap_ip = 0; + uint32 start_ip = 0; + uint32 end_ip = 0; + + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (please == NULL || wifi_softap_dhcps_status() == DHCP_STARTED) + return false; + + if(please->enable) { + os_bzero(&info, sizeof(struct ip_info)); + wifi_get_ip_info(SOFTAP_IF, &info); + softap_ip = htonl(info.ip.addr); + start_ip = htonl(please->start_ip.addr); + end_ip = htonl(please->end_ip.addr); + + /*config ip information can't contain local ip*/ + if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) + return false; + + /*config ip information must be in the same segment as the local ip*/ + softap_ip >>= 8; + if ((start_ip >> 8 != softap_ip) + || (end_ip >> 8 != softap_ip)) { + return false; + } + + if (end_ip - start_ip > DHCPS_MAX_LEASE) + return false; + + os_bzero(&dhcps_lease, sizeof(dhcps_lease)); +// dhcps_lease.start_ip.addr = start_ip; +// dhcps_lease.end_ip.addr = end_ip; + dhcps_lease.start_ip.addr = please->start_ip.addr; + dhcps_lease.end_ip.addr = please->end_ip.addr; + } + dhcps_lease.enable = please->enable; +// dhcps_lease_flag = false; + return true; +} + +/****************************************************************************** + * FunctionName : wifi_softap_get_dhcps_lease + * Description : get the lease information of DHCP server + * Parameters : please -- Additional argument to get the lease information, + * Little-Endian. + * Returns : true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease(struct dhcps_lease *please) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (NULL == please) + return false; + +// if (dhcps_lease_flag){ + if (dhcps_lease.enable == FALSE){ + if (wifi_softap_dhcps_status() == DHCP_STOPPED) + return false; + } else { +// os_bzero(please, sizeof(dhcps_lease)); +// if (wifi_softap_dhcps_status() == DHCP_STOPPED){ +// please->start_ip.addr = htonl(dhcps_lease.start_ip.addr); +// please->end_ip.addr = htonl(dhcps_lease.end_ip.addr); +// } + } + +// if (wifi_softap_dhcps_status() == DHCP_STARTED){ +// os_bzero(please, sizeof(dhcps_lease)); +// please->start_ip.addr = dhcps_lease.start_ip.addr; +// please->end_ip.addr = dhcps_lease.end_ip.addr; +// } + please->start_ip.addr = dhcps_lease.start_ip.addr; + please->end_ip.addr = dhcps_lease.end_ip.addr; + return true; +} + +static void ICACHE_FLASH_ATTR kill_oldest_dhcps_pool(void) +{ + list_node *pre = NULL, *p = NULL; + list_node *minpre = NULL, *minp = NULL; + struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; + pre = plist; + p = pre->pnext; + minpre = pre; + minp = p; + while (p != NULL){ + pdhcps_pool = p->pnode; + pmin_pool = minp->pnode; + if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){ + minp = p; + minpre = pre; + } + pre = p; + p = p->pnext; + } + minpre->pnext = minp->pnext;pdhcps_pool->state = DHCPS_STATE_OFFLINE; + os_free(minp->pnode); + minp->pnode = NULL; + os_free(minp); + minp = NULL; +} + +void ICACHE_FLASH_ATTR dhcps_coarse_tmr(void) +{ + uint8 num_dhcps_pool = 0; + list_node *pback_node = NULL; + list_node *pnode = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + pnode = plist; + while (pnode != NULL) { + pdhcps_pool = pnode->pnode; + if ( pdhcps_pool->type == DHCPS_TYPE_DYNAMIC) { + pdhcps_pool->lease_timer --; + } + if (pdhcps_pool->lease_timer == 0){ + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&plist,pback_node); + os_free(pback_node->pnode); + pback_node->pnode = NULL; + os_free(pback_node); + pback_node = NULL; + } else { + pnode = pnode ->pnext; + num_dhcps_pool ++; + } + } + + if (num_dhcps_pool >= MAX_STATION_NUM) + kill_oldest_dhcps_pool(); +} + +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg) +{ + bool offer_flag = true; + uint8 option = 0; + if (optarg == NULL && wifi_softap_dhcps_status() == false) + return false; + + if (level <= OFFER_START || level >= OFFER_END) + return false; + + switch (level){ + case OFFER_ROUTER: + offer = (*(uint8 *)optarg) & 0x01; + offer_flag = true; + break; + default : + offer_flag = false; + break; + } + return offer_flag; +} + +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease_time(uint32 minute) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (wifi_softap_dhcps_status() == DHCP_STARTED) { + return false; + } + + if(minute == 0) { + return false; + } + dhcps_lease_time = minute; + return true; +} + +bool ICACHE_FLASH_ATTR wifi_softap_reset_dhcps_lease_time(void) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (wifi_softap_dhcps_status() == DHCP_STARTED) { + return false; + } + dhcps_lease_time = DHCPS_LEASE_TIME_DEF; + return true; +} + +uint32 ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease_time(void) // minute +{ + return dhcps_lease_time; +} + +void ICACHE_FLASH_ATTR wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force) +{ + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pback_node = NULL; + + if ((bssid == NULL) || (ip == NULL)) { + return; + } + + for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ + if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { + if ((pdhcps_pool->type == DHCPS_TYPE_STATIC) || (force)) { + if(pback_node != NULL) { + node_remove_from_list(&plist,pback_node); + os_free(pback_node); + pback_node = NULL; + } + + if (pdhcps_pool != NULL) { + os_free(pdhcps_pool); + pdhcps_pool = NULL; + } + } else { + pdhcps_pool->state = DHCPS_STATE_OFFLINE; + } + + struct ip_addr ip_zero; + os_memset(&ip_zero,0x0,sizeof(ip_zero)); + wifi_softap_set_station_info(bssid, &ip_zero); + break; + } + } + } +} + +uint32 ICACHE_FLASH_ATTR wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip) +{ + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pback_node = NULL; + list_node *pmac_node = NULL; + list_node *pip_node = NULL; + bool flag = FALSE; + uint32 start_ip = dhcps_lease.start_ip.addr; + uint32 end_ip = dhcps_lease.end_ip.addr; + dhcps_type_t type = DHCPS_TYPE_DYNAMIC; + if (bssid == NULL) { + return IPADDR_ANY; + } + + if (ip) { + if (IPADDR_BROADCAST == ip->addr) { + return IPADDR_ANY; + } else if (IPADDR_ANY == ip->addr) { + ip = NULL; + } else { + type = DHCPS_TYPE_STATIC; + } + } + + renew = FALSE; + for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + //os_printf("mac:"MACSTR"bssid:"MACSTR"\r\n",MAC2STR(pdhcps_pool->mac),MAC2STR(bssid)); + if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ + pmac_node = pback_node; + if (ip == NULL) { + flag = TRUE; + break; + } + } + if (ip != NULL) { + if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { + pip_node = pback_node; + } + } else if (flag == FALSE){ + if (os_memcmp(&pdhcps_pool->ip.addr, &start_ip, sizeof(pdhcps_pool->ip.addr)) != 0) { + flag = TRUE; + } else { + start_ip = htonl((ntohl(start_ip) + 1)); + } + } + } + + if ((ip == NULL) && (flag == FALSE)) { + if (plist == NULL) { + if (start_ip <= end_ip) { + flag = TRUE; + } else { + return IPADDR_ANY; + } + } else { + if (start_ip > end_ip) { + return IPADDR_ANY; + } + //start_ip = htonl((ntohl(start_ip) + 1)); + flag = TRUE; + } + } + + if (pmac_node != NULL) { // update new ip + if (pip_node != NULL){ + pdhcps_pool = pip_node->pnode; + + if (pip_node != pmac_node) { + if(pdhcps_pool->state != DHCPS_STATE_OFFLINE) { // ip is used + return IPADDR_ANY; + } + + // mac exists and ip exists in other node,delete mac + node_remove_from_list(&plist,pmac_node); + os_free(pmac_node->pnode); + pmac_node->pnode = NULL; + os_free(pmac_node); + pmac_node = pip_node; + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + } else { + renew = true; + type = DHCPS_TYPE_DYNAMIC; + } + + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + + } else { + pdhcps_pool = pmac_node->pnode; + if (ip != NULL) { + pdhcps_pool->ip.addr = ip->addr; + } else if (flag == TRUE) { + pdhcps_pool->ip.addr = start_ip; + } else { // no ip to distribute + return IPADDR_ANY; + } + + node_remove_from_list(&plist,pmac_node); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + node_insert_to_list(&plist,pmac_node); + } + } else { // new station + if (pip_node != NULL) { // maybe ip has used + pdhcps_pool = pip_node->pnode; + if (pdhcps_pool->state != DHCPS_STATE_OFFLINE) { + return IPADDR_ANY; + } + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + } else { + pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool)); + if (ip != NULL) { + pdhcps_pool->ip.addr = ip->addr; + } else if (flag == TRUE) { + pdhcps_pool->ip.addr = start_ip; + } else { // no ip to distribute + os_free(pdhcps_pool); + return IPADDR_ANY; + } + if (pdhcps_pool->ip.addr > end_ip) { + os_free(pdhcps_pool); + return IPADDR_ANY; + } + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + pback_node = (list_node *)os_zalloc(sizeof(list_node )); + pback_node->pnode = pdhcps_pool; + pback_node->pnext = NULL; + node_insert_to_list(&plist,pback_node); + } + } + wifi_softap_set_station_info(bssid, &pdhcps_pool->ip); + + return pdhcps_pool->ip.addr; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn.c new file mode 100755 index 0000000000..4bd28e79bd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn.c @@ -0,0 +1,1366 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: espconn.c + * + * Description: espconn interface for user + * + * Modification history: + * 2014/3/31, v1.0 create this file. +*******************************************************************************/ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "ets_sys.h" +#include "os_type.h" +//#include "os.h" +#include "lwip/mem.h" + +#include "lwip/app/espconn_tcp.h" +#include "lwip/app/espconn_udp.h" +#include "lwip/app/espconn.h" +#include "user_interface.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +espconn_msg *plink_active = NULL; +espconn_msg *pserver_list = NULL; +remot_info premot[linkMax]; + +struct espconn_packet pktinfo[2]; +extern bool manual_set_flag ; + +static uint8 espconn_tcp_get_buf_count(espconn_buf *pesp_buf); +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source) +{ + pesp_dest->type = pesp_source->type; + pesp_dest->state = pesp_source->state; + if (pesp_source->type == ESPCONN_TCP){ + pesp_dest->proto.tcp->remote_port = pesp_source->proto.tcp->remote_port; + pesp_dest->proto.tcp->local_port = pesp_source->proto.tcp->local_port; + os_memcpy(pesp_dest->proto.tcp->remote_ip, pesp_source->proto.tcp->remote_ip, 4); + os_memcpy(pesp_dest->proto.tcp->local_ip, pesp_source->proto.tcp->local_ip, 4); + pesp_dest->proto.tcp->connect_callback = pesp_source->proto.tcp->connect_callback; + pesp_dest->proto.tcp->reconnect_callback = pesp_source->proto.tcp->reconnect_callback; + pesp_dest->proto.tcp->disconnect_callback = pesp_source->proto.tcp->disconnect_callback; + } else { + pesp_dest->proto.udp->remote_port = pesp_source->proto.udp->remote_port; + pesp_dest->proto.udp->local_port = pesp_source->proto.udp->local_port; + os_memcpy(pesp_dest->proto.udp->remote_ip, pesp_source->proto.udp->remote_ip, 4); + os_memcpy(pesp_dest->proto.udp->local_ip, pesp_source->proto.udp->local_ip, 4); + } + pesp_dest->recv_callback = pesp_source->recv_callback; + pesp_dest->sent_callback = pesp_source->sent_callback; + pesp_dest->link_cnt = pesp_source->link_cnt; + pesp_dest->reverse = pesp_source->reverse; +} + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert) +{ + espconn_msg *plist = NULL; +// espconn_msg *ptest = NULL; + if (*phead == NULL) + *phead = pinsert; + else { + plist = *phead; + while (plist->pnext != NULL) { + plist = plist->pnext; + } + plist->pnext = pinsert; + } + pinsert->pnext = NULL; + +/* ptest = *phead; + while(ptest != NULL){ + os_printf("espconn_list_creat %p\n", ptest); + ptest = ptest->pnext; + }*/ +} + +/****************************************************************************** + * FunctionName : espconn_list_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete) +{ + espconn_msg *plist = NULL; +// espconn_msg *ptest = NULL; + plist = *phead; + if (plist == NULL){ + *phead = NULL; + } else { + if (plist == pdelete){ + *phead = plist->pnext; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete){ + plist->pnext = pdelete->pnext; + } + plist = plist->pnext; + } + } + } +/* ptest = *phead; + while(ptest != NULL){ + os_printf("espconn_list_delete %p\n", ptest); + ptest = ptest->pnext; + }*/ +} + +/****************************************************************************** + * FunctionName : espconn_pbuf_create + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_pbuf_create(espconn_buf **phead, espconn_buf* pinsert) +{ + espconn_buf *plist = NULL; + + if (*phead == NULL) + *phead = pinsert; + else { + plist = *phead; + while (plist->pnext != NULL) { + plist = plist->pnext; + } + plist->pnext = pinsert; + } + pinsert->pnext = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_pbuf_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_pbuf_delete(espconn_buf **phead, espconn_buf* pdelete) +{ + espconn_buf *plist = NULL; + + plist = *phead; + if (plist == NULL){ + *phead = NULL; + } else { + if (plist == pdelete){ + *phead = plist->pnext; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete){ + plist->pnext = pdelete->pnext; + } + plist = plist->pnext; + } + } + } +} + +/****************************************************************************** + * FunctionName : espconn_find_connection + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : true or false + *******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode) +{ + espconn_msg *plist = NULL; + struct ip_addr ip_remot; + struct ip_addr ip_list; + + if (pespconn == NULL) + return false; + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (pespconn == plist->pespconn) { + *pnode = plist; + return true; + } + } + + /*find the active server node*/ + for (plist = pserver_list; plist != NULL; plist = plist->pnext){ + if (pespconn == plist->pespconn) { + if (pespconn->proto.tcp == NULL) + return false; + + IP4_ADDR(&ip_remot, pespconn->proto.tcp->remote_ip[0], + pespconn->proto.tcp->remote_ip[1], + pespconn->proto.tcp->remote_ip[2], + pespconn->proto.tcp->remote_ip[3]); + if ((ip_remot.addr == IPADDR_ANY) || (pespconn->proto.tcp->remote_port == 0)) + return false; + + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + IP4_ADDR(&ip_list, plist->pcommon.remote_ip[0], + plist->pcommon.remote_ip[1], plist->pcommon.remote_ip[2], + plist->pcommon.remote_ip[3]); + if ((ip_list.addr == ip_remot.addr) && (pespconn->proto.tcp->remote_port == plist->pcommon.remote_port)) { + *pnode = plist; + return true; + } + } + return false; + } + } + return false; +} + +/****************************************************************************** + * FunctionName : espconn_get_acticve_num + * Description : get the count of simulatenously active connections + * Parameters : type -- the type + * Returns : the count of simulatenously active connections + *******************************************************************************/ +static uint8 ICACHE_FLASH_ATTR +espconn_get_acticve_num(uint8 type) +{ + espconn_msg *plist = NULL; + uint8 num_tcp_active = 0; + + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if (plist->pespconn != NULL && plist->pespconn->type == type) { + num_tcp_active++; + } + } + + return num_tcp_active; +} + +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_connect(struct espconn *espconn) +{ + struct ip_addr ipaddr; + struct ip_info ipinfo; + uint8 connect_status = 0; + sint8 value = ESPCONN_OK; + espconn_msg *plist = NULL; + remot_info *pinfo = NULL; + + if (espconn == NULL) { + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Check the active node count whether is the limit or not*/ + if (espconn_get_acticve_num(ESPCONN_TCP) >= espconn_tcp_get_max_con()) + return ESPCONN_ISCONN; + + /*Check the IP address whether is zero or not in different mode*/ + if (wifi_get_opmode() == ESPCONN_STA){ + wifi_get_ip_info(STA_NETIF,&ipinfo); + if (ipinfo.ip.addr == 0){ + return ESPCONN_RTE; + } + } else if(wifi_get_opmode() == ESPCONN_AP){ + wifi_get_ip_info(AP_NETIF,&ipinfo); + if (ipinfo.ip.addr == 0){ + return ESPCONN_RTE; + } + } else if(wifi_get_opmode() == ESPCONN_AP_STA){ + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], + espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2], + espconn->proto.tcp->remote_ip[3]); + ipaddr.addr <<= 8; + wifi_get_ip_info(AP_NETIF,&ipinfo); + ipinfo.ip.addr <<= 8; + espconn_printf("softap_addr = %x, remote_addr = %x\n", ipinfo.ip.addr, ipaddr.addr); + + if (ipaddr.addr != ipinfo.ip.addr){ + connect_status = wifi_station_get_connect_status(); + if (connect_status == STATION_GOT_IP){ + wifi_get_ip_info(STA_NETIF,&ipinfo); + if (ipinfo.ip.addr == 0) + return ESPCONN_RTE; + } else if (connect_status == STATION_IDLE){ + return ESPCONN_RTE; + } else { + return connect_status; + } + } + } + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){ + if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){ + return ESPCONN_ISCONN; + } + } + } + + value = espconn_tcp_client(espconn); + + return value; +} + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_create(struct espconn *espconn) +{ + sint8 value = ESPCONN_OK; + espconn_msg *plist = NULL; + + if (espconn == NULL) { + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_UDP){ + return ESPCONN_ARG; + } + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (plist->pespconn && plist->pespconn->type == ESPCONN_UDP){ + if (espconn->proto.udp->local_port == plist->pespconn->proto.udp->local_port){ + return ESPCONN_ISCONN; + } + } + } + + value = espconn_udp_server(espconn); + + return value; +} + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length) +{ + espconn_msg *pnode = NULL; + bool value = false; + err_t error = ESPCONN_OK; + + if (espconn == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value){ + espconn ->state = ESPCONN_WRITE; + switch (espconn ->type) { + case ESPCONN_TCP: + /* calling sent function frequently,make sure last packet has been backup or sent fully*/ + if (pnode->pcommon.write_flag){ + espconn_buf *pbuf = NULL; + /*If total number of espconn_buf on the unsent lists exceeds the set maximum, return an error */ + if (espconn_copy_enabled(pnode)){ + if (espconn_tcp_get_buf_count(pnode->pcommon.pbuf) >= pnode ->pcommon.pbuf_num) + return ESPCONN_MAXNUM; + } else { + struct tcp_pcb *pcb = pnode->pcommon.pcb; + if (pcb->snd_queuelen >= TCP_SND_QUEUELEN) + return ESPCONN_MAXNUM; + } + + pbuf = (espconn_buf*) os_zalloc(sizeof(espconn_buf)); + if (pbuf == NULL) + return ESPCONN_MEM; + else { + /*Backup the application packet information for send more data*/ + pbuf->payload = psent; + pbuf->punsent = pbuf->payload; + pbuf->unsent = length; + pbuf->len = length; + /*insert the espconn_pbuf to the list*/ + espconn_pbuf_create(&pnode->pcommon.pbuf, pbuf); + if (pnode->pcommon.ptail == NULL) + pnode->pcommon.ptail = pbuf; + } + /*when set the data copy option. change the flag for next packet*/ + if (espconn_copy_disabled(pnode)) + pnode->pcommon.write_flag = false; + error = espconn_tcp_write(pnode); +// if (error != ESPCONN_OK){ +// /*send the application packet fail, +// * ensure that each allocated is deleted*/ +// espconn_pbuf_delete(&pnode->pcommon.pbuf, pbuf); +// os_free(pbuf); +// pbuf = NULL; +// } + return error; + } else + return ESPCONN_ARG; + break; + + case ESPCONN_UDP: + return espconn_udp_sent(pnode, psent, length); + break; + + default : + break; + } + } + return ESPCONN_ARG; +} + +sint16 ICACHE_FLASH_ATTR espconn_recv(struct espconn *espconn, void *mem, size_t len) +{ + espconn_msg *pnode = NULL; + bool value = false; + int bytes_used = 0; + struct tcp_pcb *tpcb = NULL; + if (espconn == NULL || mem == NULL || len == 0) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value && espconn->type == ESPCONN_TCP){ + if (pnode->readbuf != NULL){ + bytes_used = ringbuf_bytes_used(pnode->readbuf); + if (bytes_used != 0) { + if (len > bytes_used) { + len = bytes_used; + } + ringbuf_memcpy_from(mem, pnode->readbuf, len); + tpcb = pnode->pcommon.pcb; + if (tpcb && tpcb->state == ESTABLISHED) + tcp_recved(pnode->pcommon.pcb, len); + return len; + } else { + return ESPCONN_OK; + } + } else{ + return ESPCONN_MEM; + } + } else{ + return ESPCONN_ARG; + } + + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_sendto + * Description : send data for UDP + * Parameters : espconn -- espconn to set for UDP + * psent -- data to send + * length -- length of data to send + * Returns : error +*******************************************************************************/ +sint16 ICACHE_FLASH_ATTR +espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length) +{ + espconn_msg *pnode = NULL; + bool value = false; + err_t error = ESPCONN_OK; + + if (espconn == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value && espconn->type == ESPCONN_UDP) + return espconn_udp_sendto(pnode, psent, length); + else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_send + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length) __attribute__((alias("espconn_sent"))); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_wnd + * Description : get the window size of simulatenously active TCP connections + * Parameters : none + * Returns : the number of TCP_MSS active TCP connections +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_wnd(void) +{ + uint8 tcp_num = 0; + + tcp_num = (TCP_WND / TCP_MSS); + + return tcp_num; +} +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the window size simulatenously active TCP connections + * Parameters : num -- the number of TCP_MSS + * Returns : ESPCONN_ARG -- Illegal argument + * ESPCONN_OK -- No error +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_wnd(uint8 num) +{ + if (num == 0 || num > linkMax) + return ESPCONN_ARG; + + TCP_WND = (num * TCP_MSS); + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_mss + * Description : get the mss size of simulatenously active TCP connections + * Parameters : none + * Returns : the size of TCP_MSS active TCP connections +*******************************************************************************/ +uint16 ICACHE_FLASH_ATTR espconn_tcp_get_mss(void) +{ + uint16 tcp_num = 0; + + tcp_num = TCP_MSS; + + return tcp_num; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : espconn -- espconn to set the connect callback + * Returns : none +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con(void) +{ + uint8 tcp_num = 0; + + tcp_num = MEMP_NUM_TCP_PCB; + + return tcp_num; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : espconn -- espconn to set the connect callback + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con(uint8 num) +{ + if (num == 0 || num > linkMax) + return ESPCONN_ARG; + + MEMP_NUM_TCP_PCB = num; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_retran + * Description : get the Maximum number of retransmissions of data active TCP connections + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_retran(void) +{ + uint8 tcp_num = 0; + + tcp_num = TCP_MAXRTX; + + return tcp_num; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_retran + * Description : set the Maximum number of retransmissions of data active TCP connections + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_retran(uint8 num) +{ + if (num == 0 || num > 12) + return ESPCONN_ARG; + + TCP_MAXRTX = num; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_syn + * Description : get the Maximum number of retransmissions of SYN segments + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_syn(void) +{ + uint8 tcp_num = 0; + + tcp_num = TCP_SYNMAXRTX; + + return tcp_num; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_syn + * Description : set the Maximum number of retransmissions of SYN segments + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_syn(uint8 num) +{ + if (num == 0 || num > 12) + return ESPCONN_ARG; + + TCP_SYNMAXRTX = num; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con_allow(struct espconn *espconn) +{ + espconn_msg *pget_msg = NULL; + if ((espconn == NULL) || (espconn->type == ESPCONN_UDP)) + return ESPCONN_ARG; + + pget_msg = pserver_list; + while (pget_msg != NULL){ + if (pget_msg->pespconn == espconn){ + return pget_msg->count_opt; + } + pget_msg = pget_msg->pnext; + } + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num) +{ + espconn_msg *pset_msg = NULL; + if ((espconn == NULL) || (num > MEMP_NUM_TCP_PCB) || (espconn->type == ESPCONN_UDP)) + return ESPCONN_ARG; + + pset_msg = pserver_list; + while (pset_msg != NULL){ + if (pset_msg->pespconn == espconn){ + pset_msg->count_opt = num; + return ESPCONN_OK; + } + pset_msg = pset_msg->pnext; + } + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_set_buf_count + * Description : set the total number of espconn_buf on the unsent lists for one + * activate connection + * Parameters : espconn -- espconn to set the count + * num -- the total number of espconn_buf + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num) +{ + espconn_msg *plist = NULL; + if (espconn == NULL || (num > TCP_SND_QUEUELEN)) + return ESPCONN_ARG; + + /*find the node from the active connection list*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (plist->pespconn && plist->pespconn == espconn && espconn->type == ESPCONN_TCP){ + plist->pcommon.pbuf_num = num; + return ESPCONN_OK; + } + } + + if (plist == NULL) + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_get_buf_count + * Description : get the count of the current node which has espconn_buf + * Parameters : pesp_buf -- the list head of espconn_buf type + * Returns : the count of the current node which has espconn_buf +*******************************************************************************/ +static uint8 ICACHE_FLASH_ATTR espconn_tcp_get_buf_count(espconn_buf *pesp_buf) +{ + espconn_buf *pbuf_list = pesp_buf; + uint8 pbuf_num = 0; + + /*polling the list get the count of the current node*/ + while (pbuf_list != NULL){ + pbuf_list = pbuf_list->pnext; + pbuf_num ++; + } + return pbuf_num; +} + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->sent_callback = sent_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn) +{ + if (espconn == NULL || espconn ->proto.tcp == NULL || espconn->type == ESPCONN_UDP) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->write_finish_fn = write_finish_fn; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn->proto.tcp->connect_callback = connect_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->recv_callback = recv_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->reconnect_callback = recon_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb) +{ + if (espconn == NULL) { + return ESPCONN_ARG; + } + + espconn ->proto.tcp->disconnect_callback = discon_cb; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags) +{ + espconn_msg *plist = NULL; + + if (pespconn == NULL) + return ESPCONN_ARG; + + os_memset(premot, 0, sizeof(premot)); + pespconn->link_cnt = 0; + plist = plink_active; + switch (pespconn->type){ + case ESPCONN_TCP: + while(plist != NULL){ + if (plist->preverse == pespconn){ + premot[pespconn->link_cnt].state = plist->pespconn->state; + premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; + os_memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); + pespconn->link_cnt ++; + } + plist = plist->pnext; + } + + break; + case ESPCONN_UDP: + while(plist != NULL){ + if (plist->pespconn == pespconn){ + premot[pespconn->link_cnt].state = plist->pespconn->state; + premot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port; + os_memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4); + pespconn->link_cnt ++; + } + plist = plist->pnext; + } + break; + default: + break; + } + *pcon_info = premot; + if (pespconn->link_cnt == 0) + return ESPCONN_ARG; + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_accept(struct espconn *espconn) +{ + sint8 value = ESPCONN_OK; + espconn_msg *plist = NULL; + + if (espconn == NULL) { + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*check the active node information whether is the same as the entity or not*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){ + if (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){ + return ESPCONN_ISCONN; + } + } + } + value = espconn_tcp_server(espconn); + + return value; +} + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag) +{ + espconn_msg *pnode = NULL; + espconn_msg *ptime_msg = NULL; + bool value = false; + if ((espconn == NULL) || (type_flag > 0x01)) + return ESPCONN_ARG; + + if (type_flag == 0x01){ + /*set the timeout time for one active connection of the server*/ + value = espconn_find_connection(espconn, &pnode); + if (value){ + pnode->pcommon.timeout = interval; + return ESPCONN_OK; + } else + return ESPCONN_ARG; + } else { + /*set the timeout time for all active connection of the server*/ + ptime_msg = pserver_list; + while (ptime_msg != NULL){ + if (ptime_msg->pespconn == espconn){ + ptime_msg->pcommon.timeout = interval; + return ESPCONN_OK; + } + ptime_msg = ptime_msg->pnext; + } + } + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_disconnect(struct espconn *espconn) +{ + espconn_msg *pnode = NULL; + bool value = false; + + if (espconn == NULL) { + return ESPCONN_ARG;; + } else if (espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value){ + /*protect for redisconnection*/ + if (pnode->preverse == NULL && espconn->state == ESPCONN_CLOSE) + return ESPCONN_INPROGRESS; + espconn_tcp_disconnect(pnode,0); //1 force, 0 normal + return ESPCONN_OK; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_abort + * Description : Forcely abort with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_abort(struct espconn *espconn) +{ + espconn_msg *pnode = NULL; + bool value = false; + + if (espconn == NULL) { + return ESPCONN_ARG;; + } else if (espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value){ + /*protect for redisconnection*/ + if (espconn->state == ESPCONN_CLOSE) + return ESPCONN_INPROGRESS; + espconn_tcp_disconnect(pnode,1); //1 force, 0 normal + return ESPCONN_OK; + } else + return ESPCONN_ARG; +} + + +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg) +{ + espconn_msg *pnode = NULL; + err_t err; + bool value = false; + + if (espconn == NULL || infoarg == NULL) { + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value) { + struct tcp_pcb *pcb = pnode->pcommon.pcb; + if (pcb == NULL) + return ESPCONN_ARG; + + pnode->pcommon.packet_info.packseq_nxt = pcb->rcv_nxt; + pnode->pcommon.packet_info.packseqno = pcb->snd_nxt; + pnode->pcommon.packet_info.snd_buf_size = pcb->snd_buf; + pnode->pcommon.packet_info.total_queuelen = TCP_SND_QUEUELEN; + pnode->pcommon.packet_info.snd_queuelen = pnode->pcommon.packet_info.total_queuelen - pcb->snd_queuelen; + os_memcpy(infoarg,(void*)&pnode->pcommon.packet_info, sizeof(struct espconn_packet)); + return ESPCONN_OK; + } else { + switch (espconn->state){ + case ESPCONN_CLOSE: + os_memcpy(infoarg,(void*)&pktinfo[0], sizeof(struct espconn_packet)); + err = ESPCONN_OK; + break; + case ESPCONN_NONE: + os_memcpy(infoarg,(void*)&pktinfo[1], sizeof(struct espconn_packet)); + err = ESPCONN_OK; + break; + default: + err = ESPCONN_ARG; + break; + } + return err; + } +} + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : set the option for connections so that we don't end up bouncing + * all connections at the same time . + * Parameters : espconn -- the espconn used to set the connection + * opt -- the option for set + * Returns : the result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_set_opt(struct espconn *espconn, uint8 opt) +{ + espconn_msg *pnode = NULL; + struct tcp_pcb *tpcb; + bool value = false; + + if (espconn == NULL) { + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value) { + pnode->pcommon.espconn_opt |= opt; + tpcb = pnode->pcommon.pcb; + if (espconn_delay_disabled(pnode)) + tcp_nagle_disable(tpcb); + + if (espconn_keepalive_disabled(pnode)) + espconn_keepalive_enable(tpcb); + + return ESPCONN_OK; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_clear_opt + * Description : clear the option for connections so that we don't end up bouncing + * all connections at the same time . + * Parameters : espconn -- the espconn used to set the connection + * opt -- the option for clear + * Returns : the result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_clear_opt(struct espconn *espconn, uint8 opt) +{ + espconn_msg *pnode = NULL; + struct tcp_pcb *tpcb; + bool value = false; + + if (espconn == NULL) { + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value) { + pnode->pcommon.espconn_opt &= ~opt; + tpcb = pnode->pcommon.pcb; + if (espconn_keepalive_enabled(pnode)) + espconn_keepalive_disable(tpcb); + + if (espconn_delay_enabled(pnode)) + tcp_nagle_enable(tpcb); + + return ESPCONN_OK; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg) +{ + espconn_msg *pnode = NULL; + bool value = false; + sint8 ret = ESPCONN_OK; + + if (espconn == NULL || optarg == NULL) { + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value && espconn_keepalive_disabled(pnode)) { + struct tcp_pcb *pcb = pnode->pcommon.pcb; + switch (level){ + case ESPCONN_KEEPIDLE: + pcb->keep_idle = 1000 * (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + case ESPCONN_KEEPINTVL: + pcb->keep_intvl = 1000 * (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + case ESPCONN_KEEPCNT: + pcb->keep_cnt = (u32_t)(*(int*)optarg); + ret = ESPCONN_OK; + break; + default: + ret = ESPCONN_ARG; + break; + } + return ret; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg) +{ + espconn_msg *pnode = NULL; + bool value = false; + sint8 ret = ESPCONN_OK; + + if (espconn == NULL || optarg == NULL) { + return ESPCONN_ARG;; + } else if (espconn->type != ESPCONN_TCP) + return ESPCONN_ARG; + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + if (value && espconn_keepalive_disabled(pnode)) { + struct tcp_pcb *pcb = pnode->pcommon.pcb; + switch (level) { + case ESPCONN_KEEPIDLE: + *(int*)optarg = (int)(pcb->keep_idle/1000); + ret = ESPCONN_OK; + break; + case ESPCONN_KEEPINTVL: + *(int*)optarg = (int)(pcb->keep_intvl/1000); + ret = ESPCONN_OK; + break; + case ESPCONN_KEEPCNT: + *(int*)optarg = (int)(pcb->keep_cnt); + ret = ESPCONN_OK; + break; + default: + ret = ESPCONN_ARG; + break; + } + return ret; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_delete(struct espconn *espconn) +{ + espconn_msg *pnode = NULL; + bool value = false; + + if (espconn == NULL) { + return ESPCONN_ARG; + } else if (espconn ->type != ESPCONN_UDP) + return espconn_tcp_delete(espconn); + + /*Find the node depend on the espconn message*/ + value = espconn_find_connection(espconn, &pnode); + + if (value){ + espconn_udp_disconnect(pnode); + return ESPCONN_OK; + } else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +espconn_port(void) +{ + uint32 port = 0; + static uint32 randnum = 0; + + do { + port = os_random(); + + if (port < 0) { + port = os_random() - port; + } + + port %= 0xc350; + + if (port < 0x400) { + port += 0x400; + } + + } while (port == randnum); + + randnum = port; + + return port; +} + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if + * ESPCONN_OK is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found) +{ + return dns_gethostbyname(hostname, addr, found, pespconn); +} + +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver) +{ + + manual_set_flag = true; + if(dnsserver == NULL) { + ip_addr_t default_dns_server; + default_dns_server.addr = 0xDEDE43D0; + dns_setserver(0,&default_dns_server); + dns_setserver(1,&default_dns_server); + manual_set_flag = false; + return; + } + return dns_setserver(numdns,dnsserver); + +} + +/****************************************************************************** + * FunctionName : espconn_dns_getserver + * Description : get dns server. + * Parameters : numdns -- the index of the DNS server ,must + * be < DNS_MAX_SERVERS = 2 + * Returns : dnsserver -- struct ip_addr_t +*******************************************************************************/ +ip_addr_t ICACHE_FLASH_ATTR +espconn_dns_getserver(u8_t numdns) +{ + return dns_getserver(numdns); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_buf.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_buf.c new file mode 100644 index 0000000000..c013942b94 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_buf.c @@ -0,0 +1,222 @@ +/* + * espconn_buf.c + * + * Created on: May 25, 2016 + * Author: liuhan + */ + +#include "lwip/memp.h" +#include "lwip/def.h" +#include "ets_sys.h" +#include "os_type.h" +#include "lwip/app/espconn_buf.h" + + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#if (!defined(lwIP_unlikely)) +#define lwIP_unlikely(Expression) !!(Expression) +#endif + +#define lwIP_ASSERT(Expression) do{if(!(Expression)) {os_printf("%s %d\n", __func__, __LINE__);return;}}while(0) + +ringbuf_t ICACHE_FLASH_ATTR +ringbuf_new(size_t capacity) +{ + ringbuf_t rb = (ringbuf_t)os_zalloc(sizeof(struct ringbuf_t)); + if (rb){ + rb->size = capacity + 1; + rb->buf = (uint8*)os_zalloc(rb->size); + if (rb->buf){ + ringbuf_reset(rb); + }else{ + os_free(rb); + return NULL; + } + } + return rb; +} + +size_t ICACHE_FLASH_ATTR +ringbuf_buffer_size(const struct ringbuf_t *rb) +{ + return rb->size; +} + +void ICACHE_FLASH_ATTR +ringbuf_reset(ringbuf_t rb) +{ + rb ->head = rb->tail = rb->buf; +} + +void ICACHE_FLASH_ATTR +ringbuf_free(ringbuf_t *rb) +{ + lwIP_ASSERT(rb && *rb); + os_free((*rb)->buf); + os_free(*rb); + *rb = NULL; +} + +size_t ICACHE_FLASH_ATTR +ringbuf_capacity(const struct ringbuf_t *rb) +{ + return ringbuf_buffer_size(rb) - 1; +} + +static const uint8_t* ICACHE_FLASH_ATTR +ringbuf_end(const struct ringbuf_t *rb) +{ + return rb->buf + ringbuf_buffer_size(rb); +} + +size_t ICACHE_FLASH_ATTR +ringbuf_bytes_free(const struct ringbuf_t *rb) +{ + if (rb->head >= rb->tail){ + return ringbuf_capacity(rb) - (rb->head - rb->tail); + }else{ + return rb->tail - rb->head -1; + } +} + +size_t ICACHE_FLASH_ATTR +ringbuf_bytes_used(const struct ringbuf_t *rb) +{ + return ringbuf_capacity(rb) - ringbuf_bytes_free(rb); +} + +int ICACHE_FLASH_ATTR +ringbuf_is_full(const struct ringbuf_t *rb) +{ + return ringbuf_bytes_free(rb) == 0; +} + +int ICACHE_FLASH_ATTR +ringbuf_is_empty(const struct ringbuf_t *rb) +{ + return ringbuf_bytes_free(rb) == ringbuf_capacity(rb); +} + +const void* ICACHE_FLASH_ATTR +ringbuf_tail(const struct ringbuf_t *rb) +{ + return rb->tail; +} +const void* ICACHE_FLASH_ATTR +ringbuf_head(const struct ringbuf_t *rb) +{ + return rb->head; +} + +static uint8_t* ICACHE_FLASH_ATTR +ringbuf_nextp(ringbuf_t rb, const uint8_t *p) +{ + lwIP_ASSERT((p >= rb->buf) && (p < ringbuf_end(rb))); + return rb->buf + ((++p -rb->buf) % ringbuf_buffer_size(rb)); +} + +size_t ICACHE_FLASH_ATTR +ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset) +{ + const uint8_t *bufend = ringbuf_end(rb); + size_t bytes_used = ringbuf_bytes_used(rb); + if (offset >= bytes_used) + return bytes_used; + + const uint8_t *start = rb ->buf + (((rb->tail - rb->buf) + offset) % ringbuf_buffer_size(rb)); + lwIP_ASSERT(bufend > start); + size_t n = LWIP_MIN(bufend - start, bytes_used - offset); + const uint8_t *found = (const uint8_t *)memchr(start, c, n); + if (found) + return offset + (found - start); + else + return ringbuf_findchr(rb, c, offset + n); +} + +size_t ICACHE_FLASH_ATTR +ringbuf_memset(ringbuf_t dst, int c, size_t len) +{ + const uint8_t *bufend = ringbuf_end(dst); + size_t nwritten = 0; + size_t count = LWIP_MIN(len, ringbuf_buffer_size(dst)); + int overflow = count > ringbuf_bytes_free(dst); + + while (nwritten != count){ + + lwIP_ASSERT(bufend > dst->head); + size_t n = LWIP_MIN(bufend - dst->head, count - nwritten); + os_memset(dst->head, c, n); + dst->head += n; + nwritten += n; + + if (dst->head == bufend) + dst->head = dst->buf; + } + + if (overflow){ + dst->tail = ringbuf_nextp(dst, dst->head); + lwIP_ASSERT(ringbuf_is_full(dst)); + } + + return nwritten; +} + +void* ICACHE_FLASH_ATTR +ringbuf_memcpy_into(ringbuf_t dst,const void *src, size_t count) +{ + const uint8_t *u8src = src; + const uint8_t *bufend = ringbuf_end(dst); + int overflow = count > ringbuf_bytes_free(dst); + size_t nread = 0; + + while (nread != count){ + lwIP_ASSERT(bufend > dst->head); + size_t n = LWIP_MIN(bufend - dst->head, count - nread); + os_memcpy(dst->head, u8src + nread, n); + dst->head += n; + nread += n; + + if (dst->head == bufend) + dst->head = dst->buf; + } + + if (overflow) { + dst->tail = ringbuf_nextp(dst, dst->head); + lwIP_ASSERT(ringbuf_is_full(dst)); + } + + return dst->head; +} + +void* ICACHE_FLASH_ATTR +ringbuf_memcpy_from(void *dst,ringbuf_t src, size_t count) +{ + size_t bytes_used = ringbuf_bytes_used(src); + + if (count > bytes_used) + return NULL; + + const uint8_t *u8dst = dst; + const uint8_t *bufend = ringbuf_end(src); + size_t nwritten = 0; + + while (nwritten != count){ + lwIP_ASSERT(bufend > src->tail); + size_t n = LWIP_MIN(bufend - src->tail, count - nwritten); + os_memcpy((uint8_t*)u8dst + nwritten, src->tail, n); + src->tail += n; + nwritten += n; + + if (src->tail == bufend) + src->tail = src->buf; + } + + lwIP_ASSERT(count + ringbuf_bytes_used(src) == bytes_used); + return src->tail; +} + + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_mdns.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_mdns.c new file mode 100755 index 0000000000..a29c64a54b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_mdns.c @@ -0,0 +1,134 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: espconn_mdns.c + * + * Description: udp proto interface + * + * Modification history: + * 2014/3/31, v1.0 create this file. +*******************************************************************************/ + +#include "ets_sys.h" +#include "os_type.h" + +#include "lwip/mdns.h" + +/****************************************************************************** + * FunctionName : espconn_mdns_enable + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_enable(void) +{ + mdns_enable(); +} +/****************************************************************************** + * FunctionName : espconn_mdns_disable + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_disable(void) +{ + mdns_disable(); +} + +/****************************************************************************** + * FunctionName : espconn_mdns_set_hostname + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_set_hostname(char *name) +{ + mdns_set_hostname(name); +} + +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR +espconn_mdns_get_hostname(void) +{ + return (char *)mdns_get_hostname(); +} +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : join a multicast group + * Parameters : info -- the info of mdns + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_set_servername(const char *name) +{ + mdns_set_servername(name); +} +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : join a multicast group + * Parameters : info -- the info of mdns + * Returns : none +*******************************************************************************/ +char* ICACHE_FLASH_ATTR +espconn_mdns_get_servername(void) +{ + return (char *)mdns_get_servername(); +} +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : join a multicast group + * Parameters : info -- the info of mdns + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_server_register(void) +{ + mdns_server_register(); +} +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : join a multicast group + * Parameters : info -- the info of mdns + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_server_unregister(void) +{ + mdns_server_unregister(); +} +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_close(void) +{ + mdns_close(); +} +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +espconn_mdns_init(struct mdns_info *info) +{ + mdns_init(info); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_tcp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_tcp.c new file mode 100755 index 0000000000..3d58c2dc66 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_tcp.c @@ -0,0 +1,1553 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: espconn_tcp.c + * + * Description: tcp proto interface + * + * Modification history: + * 2014/3/31, v1.0 create this file. +*******************************************************************************/ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/tcp_impl.h" +#include "lwip/memp.h" + +#include "ets_sys.h" +#include "os_type.h" +//#include "os.h" +#include "lwip/mem.h" +#include "lwip/app/espconn_tcp.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +extern espconn_msg *plink_active; +extern espconn_msg *pserver_list; +extern struct espconn_packet pktinfo[2]; +extern struct tcp_pcb ** const tcp_pcb_lists[]; + +os_event_t espconn_TaskQueue[espconn_TaskQueueLen]; + +static err_t +espconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +static void +espconn_client_close(void *arg, struct tcp_pcb *pcb,u8 type); + +static err_t +espconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +static void +espconn_server_close(void *arg, struct tcp_pcb *pcb,u8 type); + +///////////////////////////////common function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_kill_oldest + * Description : kill the oldest TCP block + * Parameters : none + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_kill_oldest(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if (inactive != NULL) { + tcp_abort(inactive); + } + + /* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */ + inactivity = 0; + inactive = NULL; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == FIN_WAIT_1 || pcb->state == FIN_WAIT_2){ + if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + /*Purges the PCB, removes it from a PCB list and frees the memory*/ + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } + + /* Go through the list of LAST_ACK pcbs and get the oldest pcb. */ + inactivity = 0; + inactive = NULL; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == LAST_ACK) { + if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + /*Purges the PCB, removes it from a PCB list and frees the memory*/ + if (inactive != NULL) { + tcp_pcb_remove(&tcp_active_pcbs, inactive); + memp_free(MEMP_TCP_PCB, inactive); + } +} + +/****************************************************************************** + * FunctionName : espconn_kill_oldest_pcb + * Description : find the oldest TCP block by state + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_kill_oldest_pcb(void) +{ + struct tcp_pcb *cpcb = NULL; + uint8 i = 0; + uint8 num_tcp_fin = 0; + for(i = 2; i < 4; i ++){ + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->state == TIME_WAIT){ + num_tcp_fin ++; + if (num_tcp_fin == MEMP_NUM_TCP_PCB) + break; + } + + if (cpcb->state == FIN_WAIT_1 || cpcb->state == FIN_WAIT_2 || cpcb->state == LAST_ACK){ + num_tcp_fin++; + if (num_tcp_fin == MEMP_NUM_TCP_PCB) + break; + } + } + + if (num_tcp_fin == MEMP_NUM_TCP_PCB){ + num_tcp_fin = 0; + espconn_kill_oldest(); + } else if (cpcb == NULL){ + num_tcp_fin = 0; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_kill_pcb + * Description : kill all the TCP block by port + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_kill_pcb(u16_t port) +{ + struct tcp_pcb *cpcb = NULL; + uint8 i = 0; + struct tcp_pcb *inactive = NULL; + struct tcp_pcb *prev = NULL; + u8_t pcb_remove; + /* Check if the address already is in use (on all lists) */ + for (i = 1; i < 4; i++) { + cpcb = *tcp_pcb_lists[i]; + while(cpcb != NULL){ + pcb_remove = 0; + if (cpcb->local_port == port) { + ++pcb_remove; + } + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + /* Remove PCB from tcp_pcb_lists list. */ + inactive = cpcb; + cpcb = inactive->next; + tcp_pcb_remove(tcp_pcb_lists[i], inactive); + memp_free(MEMP_TCP_PCB, inactive); + } else { + cpcb = cpcb->next; + } + } + } +} + +/****************************************************************************** + * FunctionName : espconn_find_current_pcb + * Description : find the TCP block which option + * Parameters : pcurrent_msg -- the node in the list which active + * Returns : TCP block point +*******************************************************************************/ +struct tcp_pcb *ICACHE_FLASH_ATTR espconn_find_current_pcb(espconn_msg *pcurrent_msg) +{ + uint16 local_port = pcurrent_msg->pcommon.local_port; + uint32 local_ip = pcurrent_msg->pcommon.local_ip; + uint16 remote_port = pcurrent_msg->pcommon.remote_port; + uint32 remote_ip = *((uint32*)&pcurrent_msg->pcommon.remote_ip); + struct tcp_pcb *find_pcb = NULL; + if (pcurrent_msg ->preverse == NULL){/*Find the server's TCP block*/ + if (local_ip == 0|| local_port == 0) return pcurrent_msg->pcommon.pcb; + + for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) && + (find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip)) + return find_pcb; + } + + for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) && + (find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip)) + return find_pcb; + } + } else {/*Find the client's TCP block*/ + if (remote_ip == 0|| remote_port == 0) return pcurrent_msg->pcommon.pcb; + + for (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip)) + return find_pcb; + } + + for (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){ + if ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip)) + return find_pcb; + } + } + return NULL; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_memp_free + * Description : frees the connection memory in the server mode + * Parameters : arg -- Additional argument to pass to the function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_tcp_memp_free(espconn_msg *pmemp) +{ + struct espconn *espconn = NULL; + if (pmemp == NULL) + return; + + /*Enable block option for fetches the data proactive*/ + if (espconn_manual_recv_disabled(pmemp)) + espconn_list_delete(&plink_active, pmemp); + + if (pmemp->espconn_mode == ESPCONN_TCPSERVER_MODE){ + if (pmemp->pespconn != NULL && pmemp->pespconn->proto.tcp != NULL) + os_free(pmemp->pespconn->proto.tcp); + pmemp->pespconn->proto.tcp = NULL; + + os_free(pmemp->pespconn); + pmemp->pespconn = NULL; + } + + if (pmemp->readbuf != NULL){ + ringbuf_free(&pmemp->readbuf); + } + os_free(pmemp); + pmemp = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_reconnect + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_tcp_reconnect(void *arg) +{ + espconn_msg *precon_cb = arg; + sint8 re_err = 0; + espconn_buf *perr_buf = NULL; + espconn_buf *perr_back = NULL; + espconn_kill_oldest_pcb(); + if (precon_cb != NULL) { + struct espconn *espconn = precon_cb->preverse; + + re_err = precon_cb->pcommon.err; + if (precon_cb->pespconn != NULL){ + if (espconn != NULL){/*Process the server's message block*/ + if (precon_cb->pespconn->proto.tcp != NULL){ + espconn_copy_partial(espconn, precon_cb->pespconn); + } + } else {/*Process the client's message block*/ + espconn = precon_cb->pespconn; + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + perr_buf = precon_cb->pcommon.pbuf; + while (perr_buf != NULL){ + perr_back = perr_buf; + perr_buf = perr_back->pnext; + espconn_pbuf_delete(&precon_cb->pcommon.pbuf,perr_back); + os_free(perr_back); + perr_back = NULL; + } + os_bzero(&pktinfo[1], sizeof(struct espconn_packet)); + os_memcpy(&pktinfo[1], (void*)&precon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); + + if (espconn && espconn->proto.tcp && espconn->proto.tcp->reconnect_callback != NULL) { + espconn->proto.tcp->reconnect_callback(espconn, re_err); + } + + /*frees the connection memory*/ + espconn_tcp_memp_free(precon_cb); + } else { + espconn_printf("espconn_tcp_reconnect err\n"); + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_disconnect + * Description : disconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_tcp_disconnect_successful(void *arg) +{ + espconn_msg *pdiscon_cb = arg; + sint8 dis_err = 0; + espconn_buf *pdis_buf = NULL; + espconn_buf *pdis_back = NULL; + espconn_kill_oldest_pcb(); + if (pdiscon_cb != NULL) { + struct espconn *espconn = pdiscon_cb->preverse; + + dis_err = pdiscon_cb->pcommon.err; + if (pdiscon_cb->pespconn != NULL){ + struct tcp_pcb *pcb = NULL; + if (espconn != NULL){/*Process the server's message block*/ + if (pdiscon_cb->pespconn->proto.tcp != NULL && espconn->proto.tcp){ + espconn_copy_partial(espconn, pdiscon_cb->pespconn); + } + } else {/*Process the client's message block*/ + espconn = pdiscon_cb->pespconn; + } + + /*process the current TCP block*/ + pcb = espconn_find_current_pcb(pdiscon_cb); + if (pcb != NULL){ + if (espconn_reuse_disabled(pdiscon_cb)) { + struct tcp_pcb *cpcb = NULL; + struct tcp_pcb *prev = NULL; + u8_t pcb_remove; + espconn_printf("espconn_tcp_disconnect_successful %d, %d\n", pcb->state, pcb->local_port); + cpcb = tcp_tw_pcbs; + while (cpcb != NULL) { + pcb_remove = 0; + if (cpcb->local_port == pcb->local_port) { + ++pcb_remove; + } + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *backup_pcb = NULL; + tcp_pcb_purge(cpcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("espconn_tcp_delete: middle cpcb != tcp_tw_pcbs",cpcb != tcp_tw_pcbs); + prev->next = cpcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("espconn_tcp_delete: first cpcb == tcp_tw_pcbs",tcp_tw_pcbs == cpcb); + tcp_tw_pcbs = cpcb->next; + } + backup_pcb = cpcb; + cpcb = cpcb->next; + memp_free(MEMP_TCP_PCB, backup_pcb); + } else { + prev = cpcb; + cpcb = cpcb->next; + } + } + + } else { + tcp_arg(pcb, NULL); + tcp_err(pcb, NULL); + } + } + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + pdis_buf = pdiscon_cb->pcommon.pbuf; + while (pdis_buf != NULL) { + pdis_back = pdis_buf; + pdis_buf = pdis_back->pnext; + espconn_pbuf_delete(&pdiscon_cb->pcommon.pbuf, pdis_back); + os_free(pdis_back); + pdis_back = NULL; + } + os_bzero(&pktinfo[0], sizeof(struct espconn_packet)); + os_memcpy(&pktinfo[0], (void*)&pdiscon_cb->pcommon.packet_info, sizeof(struct espconn_packet)); + + if (espconn->proto.tcp && espconn->proto.tcp->disconnect_callback != NULL) { + espconn->proto.tcp->disconnect_callback(espconn); + } + + /*frees the connection memory*/ + espconn_tcp_memp_free(pdiscon_cb); + } else { + espconn_printf("espconn_tcp_disconnect err\n"); + } +} + +/****************************************************************************** + * FunctionName : espconn_Task + * Description : espconn processing task + * Parameters : events -- contain the espconn processing data + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_Task(os_event_t *events) +{ + espconn_msg *plist = NULL; + bool active_flag = false; + espconn_msg *task_msg = NULL; + struct espconn *pespconn = NULL; + + task_msg = (espconn_msg *) events->par; + /*find the active connection node*/ + for (plist = plink_active; plist != NULL; plist = plist->pnext){ + if (task_msg == plist) { + active_flag = true; + break; + } + } + + if (active_flag){ + switch (events->sig) { + case SIG_ESPCONN_WRITE: { + pespconn = task_msg->pespconn; + if (pespconn == NULL) { + return; + } + + if (pespconn->proto.tcp->write_finish_fn != NULL) { + pespconn->proto.tcp->write_finish_fn(pespconn); + } + } + break; + case SIG_ESPCONN_ERRER: + /*remove the node from the client's active connection list*/ + if (espconn_manual_recv_enabled(task_msg)) + espconn_list_delete(&plink_active, task_msg); + espconn_tcp_reconnect(task_msg); + break; + case SIG_ESPCONN_CLOSE: + /*remove the node from the client's active connection list*/ + if (espconn_manual_recv_enabled(task_msg)) + espconn_list_delete(&plink_active, task_msg); + espconn_tcp_disconnect_successful(task_msg); + break; + default: + break; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_tcp_sent(void *arg, uint8 *psent, uint16 length) +{ + espconn_msg *ptcp_sent = arg; + struct tcp_pcb *pcb = NULL; + err_t err = 0; + u16_t len = 0; + u8_t data_to_send = false; + + espconn_printf("espconn_tcp_sent ptcp_sent %p psent %p length %d\n", ptcp_sent, psent, length); + + /*Check the parameters*/ + if (ptcp_sent == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + /*Set the packet length depend on the sender buffer space*/ + pcb = ptcp_sent->pcommon.pcb; + if (tcp_sndbuf(pcb) < length) { + len = tcp_sndbuf(pcb); + } else { + len = length; + LWIP_ASSERT("length did not fit into uint16!", (len == length)); + } + + if (len > (2*pcb->mss)) { + len = 2*pcb->mss; + } + + /*Write data for sending, but does not send it immediately*/ + do { + espconn_printf("espconn_tcp_sent writing %d bytes %p\n", len, pcb); + if (espconn_copy_disabled(ptcp_sent)) + err = tcp_write(pcb, psent, len, 1); + else + err = tcp_write(pcb, psent, len, 0); + + if (err == ERR_MEM) { + if(len < 3) + len--; + else + len /= 2; + } + + } while (err == ERR_MEM && len > 0); + + /*Find out what we can send and send it, offset the buffer point for next send*/ + if (err == ERR_OK) { + ptcp_sent->pcommon.ptail->punsent = psent + len; + ptcp_sent->pcommon.ptail->unsent = length - len; + err = tcp_output(pcb); + /*If enable the copy option, change the flag for next write*/ + if (espconn_copy_disabled(ptcp_sent)){ + if (ptcp_sent->pcommon.ptail->unsent == 0) { + ptcp_sent->pcommon.write_flag = true; + ets_post(espconn_TaskPrio, SIG_ESPCONN_WRITE, (uint32_t)ptcp_sent); + } + } + espconn_printf("espconn_tcp_sent %d\n", err); + } + return err; +} + +/****************************************************************************** + * FunctionName : espconn_close + * Description : The connection has been successfully closed. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type) +{ + if (pdiscon != NULL){ + /*disconnect with the host by send the FIN frame*/ + if (pdiscon->preverse != NULL) + espconn_server_close(pdiscon, pdiscon->pcommon.pcb,type); + else + espconn_client_close(pdiscon, pdiscon->pcommon.pcb,type); + } else{ + espconn_printf("espconn_tcp_disconnect err.\n"); + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_recv + * Description : Data has been received on this pcb. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which received data + * p -- The received data (or NULL when the connection has been closed!) + * err -- An error code if there has been an error receiving + * Returns : ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_tcp_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + espconn_msg *precv_cb = arg; + struct pbuf *pthis = NULL; + uint8_t *ring = NULL; + size_t bytes_used = 0; + + tcp_arg(pcb, arg); + + if (precv_cb->readbuf == NULL) { + precv_cb->readbuf = ringbuf_new(TCP_WND); + if (precv_cb->readbuf == NULL) + return ESPCONN_MEM; + } + + if (err == ERR_OK) { + precv_cb->pcommon.recv_check = 0; + if (p != NULL) { + /*store the data to the adapter for application fetches it proactive*/ + for (pthis = p; pthis != NULL ; pthis = pthis->next) { + ring = ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); + if (ring) + pbuf_free(pthis); + else + break; + } + bytes_used = ringbuf_bytes_used(precv_cb->readbuf); + + /*switch the state of espconn for application process*/ + precv_cb->pespconn->state = ESPCONN_READ; + precv_cb->pcommon.pcb = pcb; + if (precv_cb->pespconn->recv_callback != NULL) { + precv_cb->pespconn->recv_callback(precv_cb->pespconn, NULL, bytes_used); + } + + /*switch the state of espconn for next packet copy*/ + if (pcb->state == ESTABLISHED) + precv_cb->pespconn->state = ESPCONN_CONNECT; + } else { + if (precv_cb->preverse) { + espconn_server_close(precv_cb, pcb, 0); + } else { + espconn_client_close(precv_cb, pcb, 0); + } + } + } + + return ERR_OK; +} + +///////////////////////////////client function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_client_close + * Description : The connection shall be actively closed. + * Parameters : pcb -- Additional argument to pass to the callback function + * pcb -- the pcb to close + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_client_close(void *arg, struct tcp_pcb *pcb, u8 type) +{ + err_t err; + espconn_msg *pclose = arg; + + pclose->pcommon.pcb = pcb; + /*avoid recalling the disconnect function*/ + tcp_recv(pcb, NULL); + + if(type == 0) + err = tcp_close(pcb); + else { + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + tcp_abort(pcb); + err = ERR_OK; + } + + if (err != ERR_OK) { + /* closing failed, try again later */ + tcp_recv(pcb, espconn_client_recv); + } else { + /* closing succeeded */ + if (type == 0) { + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + } + /*switch the state of espconn for application process*/ + pclose->pespconn->state = ESPCONN_CLOSE; + ets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)pclose); + } +} + +//***********Code for WIFI_BLOCK from upper************** +sint8 ICACHE_FLASH_ATTR +espconn_recv_hold(struct espconn *pespconn) +{ + //1st, according to espconn code, have to find out the escpconn_msg by pespconn; + espconn_msg *pnode = NULL; + bool value = false; + if (pespconn == NULL) { + return ESPCONN_ARG; + } + value = espconn_find_connection(pespconn, &pnode); + if(value != true) + { + os_printf("RecvHold, By pespconn,find conn_msg fail\n"); + return ESPCONN_ARG; + } + + //2nd, the actual operation + if(pnode->recv_hold_flag == 0) + { + pnode->recv_hold_flag = 1; + pnode->recv_holded_buf_Len = 0; + } + return ESPCONN_OK; +} + +sint8 ICACHE_FLASH_ATTR +espconn_recv_unhold(struct espconn *pespconn) +{ + //1st, according to espconn code, have to find out the escpconn_msg by pespconn; + espconn_msg *pnode = NULL; + bool value = false; + if (pespconn == NULL) { + return ESPCONN_ARG; + } + value = espconn_find_connection(pespconn, &pnode); + if(value != true) + { + os_printf("RecvHold, By pespconn,find conn_msg fail\n"); + return ESPCONN_ARG; + } + + //2nd, the actual operation + if(pnode->recv_hold_flag == 1) + { + if(pespconn->type == ESPCONN_TCP) { + tcp_recved(pnode->pcommon.pcb, pnode->recv_holded_buf_Len); + } + pnode->recv_holded_buf_Len = 0; + pnode->recv_hold_flag = 0; + } + return ESPCONN_OK; +} + +//***********Code for WIFI_BLOCK from upper************** +sint8 ICACHE_FLASH_ATTR +espconn_lock_recv(espconn_msg *plockmsg) +{ + if (plockmsg == NULL || plockmsg->pespconn == NULL) { + return ESPCONN_ARG; + } + + if (plockmsg->pespconn->recv_callback == NULL){ + if (plockmsg->readbuf == NULL){ + plockmsg->readbuf = ringbuf_new(TCP_WND); + if (plockmsg->readbuf == NULL) + return ESPCONN_MEM; + } + return espconn_recv_hold(plockmsg->pespconn); + } + + return ESPCONN_OK; +} + +sint8 ICACHE_FLASH_ATTR +espconn_unlock_recv(espconn_msg *punlockmsg) +{ + if (punlockmsg == NULL || punlockmsg->pespconn == NULL) { + return ESPCONN_ARG; + } + + if (punlockmsg->pespconn->recv_callback != NULL) + return espconn_recv_unhold(punlockmsg->pespconn); + + return ESPCONN_OK; +} +/****************************************************************************** + * FunctionName : espconn_client_recv + * Description : Data has been received on this pcb. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which received data + * p -- The received data (or NULL when the connection has been closed!) + * err -- An error code if there has been an error receiving + * Returns : ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + espconn_msg *precv_cb = arg; + + tcp_arg(pcb, arg); + /*lock the window because of application layer don't need the data*/ + espconn_lock_recv(precv_cb); + + if (p != NULL) { + /*To update and advertise a larger window*/ + if(precv_cb->recv_hold_flag == 0) + tcp_recved(pcb, p->tot_len); + else + precv_cb->recv_holded_buf_Len += p->tot_len; + } + + if (precv_cb->pespconn->recv_callback != NULL){ + if (err == ERR_OK && p != NULL) { + char *pdata = NULL; + u16_t length = 0; + /*Copy the contents of a packet buffer to an application buffer. + *to prevent memory leaks, ensure that each allocated is deleted*/ + pdata = (char *)os_zalloc(p ->tot_len + 1); + length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); + pbuf_free(p); + + if (length != 0) { + /*switch the state of espconn for application process*/ + precv_cb->pespconn ->state = ESPCONN_READ; + precv_cb->pcommon.pcb = pcb; + precv_cb->pespconn->recv_callback(precv_cb->pespconn, pdata, length); + + /*switch the state of espconn for next packet copy*/ + if (pcb->state == ESTABLISHED) + precv_cb->pespconn ->state = ESPCONN_CONNECT; + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pdata); + pdata = NULL; + } + } else{ + /*unregister receive function*/ + struct pbuf *pthis = NULL; + for (pthis = p; pthis != NULL; pthis = pthis->next) { + ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); + pbuf_free(pthis); + } + } + + if (err == ERR_OK && p == NULL) { + espconn_client_close(precv_cb, pcb,0); + } + + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_write + * Description : write the packet which in the active connection's list. + * Parameters : arg -- the node pointer which reverse the packet + * Returns : ESPCONN_MEM: memory error + * ESPCONN_OK:have enough space for write packet +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR espconn_tcp_write(void *arg) +{ + espconn_msg *pwrite = arg; + err_t err = ERR_OK; + struct tcp_pcb *pcb = pwrite->pcommon.pcb; + /*for one active connection,limit the sender buffer space*/ + if (tcp_nagle_disabled(pcb) && (pcb->snd_queuelen >= TCP_SND_QUEUELEN)) + return ESPCONN_MEM; + + while (tcp_sndbuf(pcb) != 0){ + if (pwrite->pcommon.ptail != NULL) { + /*Find the node whether in the list's tail or not*/ + if (pwrite->pcommon.ptail->unsent == 0) { + pwrite->pcommon.ptail = pwrite->pcommon.ptail->pnext; + continue; + } + + /*Send the packet for the active connection*/ + err = espconn_tcp_sent(pwrite, pwrite->pcommon.ptail->punsent,pwrite->pcommon.ptail->unsent); + if (err != ERR_OK) + break; + } else + break; + } + return err; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_reconnect + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR espconn_tcp_finish(void *arg) +{ + espconn_msg *pfinish = arg; + espconn_buf *premove = NULL; + uint16 len = 0; + espconn_tcp_write(pfinish); + while (pfinish->pcommon.pbuf != NULL){ + premove = pfinish->pcommon.pbuf; + pfinish->pcommon.pbuf->tot_len += len; + /*application packet has been sent and acknowledged by the remote host, + * to prevent memory leaks, ensure that each allocated is deleted*/ + if (premove->tot_len >= premove->len){ + espconn_pbuf_delete(&pfinish->pcommon.pbuf,premove); + len = premove->tot_len - premove->len; + pfinish->pcommon.packet_info.sent_length = premove->len; + os_free(premove); + premove = NULL; + pfinish->pespconn->state = ESPCONN_CONNECT; + if (pfinish->pespconn->sent_callback != NULL) { + pfinish->pespconn->sent_callback(pfinish->pespconn); + } + pfinish->pcommon.packet_info.sent_length = len; + } else + break; + } +} + +/****************************************************************************** + * FunctionName : espconn_client_sent + * Description : Data has been sent and acknowledged by the remote host. + * This means that more data can be sent. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * len -- The amount of bytes acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + espconn_msg *psent_cb = arg; + + psent_cb->pcommon.pcb = pcb; + psent_cb->pcommon.pbuf->tot_len += len; + psent_cb->pcommon.packet_info.sent_length = len; + + /*Send more data for one active connection*/ + espconn_tcp_finish(psent_cb); + + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_client_err + * Description : The pcb had an error and is already deallocated. + * The argument might still be valid (if != NULL). + * Parameters : arg -- Additional argument to pass to the callback function + * err -- Error code to indicate why the pcb has been closed + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_client_err(void *arg, err_t err) +{ + espconn_msg *perr_cb = arg; + struct tcp_pcb *pcb = NULL; + LWIP_UNUSED_ARG(err); + + if (perr_cb != NULL) { + pcb = perr_cb->pcommon.pcb; + perr_cb->pespconn->state = ESPCONN_CLOSE; + espconn_printf("espconn_client_err %d %d %d\n", pcb->state, pcb->nrtx, err); + +// /*remove the node from the client's active connection list*/ +// espconn_list_delete(&plink_active, perr_cb); + + /*Set the error code depend on the error type and control block state*/ + if (err == ERR_ABRT) { + switch (pcb->state) { + case SYN_SENT: + if (pcb->nrtx == TCP_SYNMAXRTX) { + perr_cb->pcommon.err = ESPCONN_CONN; + } else { + perr_cb->pcommon.err = err; + } + + break; + + case ESTABLISHED: + if (pcb->nrtx == TCP_MAXRTX) { + perr_cb->pcommon.err = ESPCONN_TIMEOUT; + } else { + perr_cb->pcommon.err = err; + } + break; + + case FIN_WAIT_1: + if (pcb->nrtx == TCP_MAXRTX) { + perr_cb->pcommon.err = ESPCONN_CLSD; + } else { + perr_cb->pcommon.err = err; + } + break; + case FIN_WAIT_2: + perr_cb->pcommon.err = ESPCONN_CLSD; + break; + case CLOSED: + perr_cb->pcommon.err = ESPCONN_CONN; + break; + } + } else { + perr_cb->pcommon.err = err; + } + /*post the singer to the task for processing the connection*/ + ets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)perr_cb); + } +} + +/****************************************************************************** + * FunctionName : espconn_client_connect + * Description : A new incoming connection has been connected. + * Parameters : arg -- Additional argument to pass to the callback function + * tpcb -- The connection pcb which is connected + * err -- An unused error code, always ERR_OK currently + * Returns : connection result +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_client_connect(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + espconn_msg *pcon = arg; + + espconn_printf("espconn_client_connect pcon %p tpcb %p\n", pcon, tpcb); + if (err == ERR_OK){ + /*Reserve the remote information for current active connection*/ + pcon->pespconn->state = ESPCONN_CONNECT; + pcon->pcommon.err = err; + pcon->pcommon.pcb = tpcb; + pcon->pcommon.local_port = tpcb->local_port; + pcon->pcommon.local_ip = tpcb->local_ip.addr; + pcon->pcommon.remote_port = tpcb->remote_port; + pcon->pcommon.remote_ip[0] = ip4_addr1_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[1] = ip4_addr2_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[2] = ip4_addr3_16(&tpcb->remote_ip); + pcon->pcommon.remote_ip[3] = ip4_addr4_16(&tpcb->remote_ip); + pcon->pcommon.write_flag = true; + tcp_arg(tpcb, (void *) pcon); + + /*Set the specify function that should be called + * when TCP data has been successfully delivered, + * when active connection receives data*/ + tcp_sent(tpcb, espconn_client_sent); + tcp_recv(tpcb, espconn_client_recv); + /*Disable Nagle algorithm default*/ + tcp_nagle_disable(tpcb); + /*Default set the total number of espconn_buf on the unsent lists for one*/ + espconn_tcp_set_buf_count(pcon->pespconn, 1); + + if (pcon->pespconn->proto.tcp->connect_callback != NULL) { + pcon->pespconn->proto.tcp->connect_callback(pcon->pespconn); + } + + /*Enable block option for fetches the data proactive*/ + if (espconn_manual_recv_disabled(pcon)) + tcp_recv(tpcb, espconn_tcp_recv); + + /*Enable keep alive option*/ + if (espconn_keepalive_disabled(pcon)) + espconn_keepalive_enable(tpcb); + +// /*lock the window because of application layer don't need the data*/ +// espconn_lock_recv(pcon); + } else{ + os_printf("err in host connected (%s)\n",lwip_strerr(err)); + } + return err; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_tcp_client(struct espconn *espconn) +{ + struct tcp_pcb *pcb = NULL; + struct ip_addr ipaddr; + espconn_msg *pclient = NULL; + + /*Creates a new client control message*/ + pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); + if (pclient == NULL){ + return ESPCONN_MEM; + } + + /*Set an IP address given for Little-endian.*/ + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], + espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2], + espconn->proto.tcp->remote_ip[3]); + + /*Creates a new TCP protocol control block*/ + pcb = tcp_new(); + + if (pcb == NULL) { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pclient); + pclient = NULL; + return ESPCONN_MEM; + } else { + + /*insert the node to the active connection list*/ + espconn_list_creat(&plink_active, pclient); + tcp_arg(pcb, (void *)pclient); + tcp_err(pcb, espconn_client_err); + pclient->preverse = NULL; + pclient->pespconn = espconn; + pclient->pespconn->state = ESPCONN_WAIT; + pclient->pcommon.pcb = pcb; + tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); +#if 0 + pclient->pcommon.err = tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port); + if (pclient->pcommon.err != ERR_OK){ + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, pclient); + memp_free(MEMP_TCP_PCB, pcb); + os_free(pclient); + pclient = NULL; + return ERR_USE; + } +#endif + /*Establish the connection*/ + pclient->espconn_mode = ESPCONN_TCPCLIENT_MODE; + pclient->pcommon.err = tcp_connect(pcb, &ipaddr, + pclient->pespconn->proto.tcp->remote_port, espconn_client_connect); + if (pclient->pcommon.err == ERR_RTE){ + /*remove the node from the client's active connection list*/ + espconn_list_delete(&plink_active, pclient); + espconn_kill_pcb(pcb->local_port); + os_free(pclient); + pclient = NULL; + return ESPCONN_RTE; + } + return pclient->pcommon.err; + } +} + +///////////////////////////////server function///////////////////////////////// +/****************************************************************************** + * FunctionName : espconn_server_close + * Description : The connection shall be actively closed. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- the pcb to close + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_server_close(void *arg, struct tcp_pcb *pcb,u8 type) +{ + err_t err; + espconn_msg *psclose = arg; + + psclose->pcommon.pcb = pcb; + /*avoid recalling the disconnect function*/ + tcp_recv(pcb, NULL); + + if(type ==0) + err = tcp_close(pcb); + else { + tcp_poll(pcb, NULL, 0); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + tcp_abort(pcb); + err = ERR_OK; + } + + if (err != ERR_OK) { + /* closing failed, try again later */ + tcp_recv(pcb, espconn_server_recv); + } else { + /* closing succeeded */ + if (type == 0) { + tcp_poll(pcb, NULL, 0); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + } + /*switch the state of espconn for application process*/ + psclose->pespconn->state = ESPCONN_CLOSE; + ets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)psclose); + } +} + +/****************************************************************************** + * FunctionName : espconn_server_recv + * Description : Data has been received on this pcb. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which received data + * p -- The received data (or NULL when the connection has been closed!) + * err -- An error code if there has been an error receiving + * Returns : ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + espconn_msg *precv_cb = arg; + + tcp_arg(pcb, arg); + espconn_printf("server has application data received: %d\n", system_get_free_heap_size()); + /*lock the window because of application layer don't need the data*/ + espconn_lock_recv(precv_cb); + + if (p != NULL) { + /*To update and advertise a larger window*/ + if(precv_cb->recv_hold_flag == 0) + tcp_recved(pcb, p->tot_len); + else + precv_cb->recv_holded_buf_Len += p->tot_len; + } + + /*register receive function*/ + if (precv_cb->pespconn->recv_callback != NULL) { + if (err == ERR_OK && p != NULL) { + u8_t *data_ptr = NULL; + u32_t data_cntr = 0; + /*clear the count for connection timeout*/ + precv_cb->pcommon.recv_check = 0; + /*Copy the contents of a packet buffer to an application buffer. + *to prevent memory leaks, ensure that each allocated is deleted*/ + data_ptr = (u8_t *) os_zalloc(p ->tot_len + 1); + data_cntr = pbuf_copy_partial(p, data_ptr, p->tot_len, 0); + pbuf_free(p); + + if (data_cntr != 0) { + /*switch the state of espconn for application process*/ + precv_cb->pespconn->state = ESPCONN_READ; + precv_cb->pcommon.pcb = pcb; + precv_cb->pespconn->recv_callback(precv_cb->pespconn, data_ptr, data_cntr); + + /*switch the state of espconn for next packet copy*/ + if (pcb->state == ESTABLISHED) + precv_cb->pespconn->state = ESPCONN_CONNECT; + } + + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(data_ptr); + data_ptr = NULL; + espconn_printf("server's application data has been processed: %d\n", system_get_free_heap_size()); + } + } else { + /*unregister receive function*/ + struct pbuf *pthis = NULL; + for (pthis = p; pthis != NULL; pthis = pthis->next) { + ringbuf_memcpy_into(precv_cb->readbuf, pthis->payload, pthis->len); + pbuf_free(pthis); + } + } + + if (err == ERR_OK && p == NULL) { + espconn_server_close(precv_cb, pcb, 0); + } + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_server_sent + * Description : Data has been sent and acknowledged by the remote host. + * This means that more data can be sent. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * len -- The amount of bytes acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + espconn_msg *psent_cb = arg; + + psent_cb->pcommon.pcb = pcb; + psent_cb->pcommon.recv_check = 0; + psent_cb->pcommon.pbuf->tot_len += len; + psent_cb->pcommon.packet_info.sent_length = len; + + /*Send more data for one active connection*/ + espconn_tcp_finish(psent_cb); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_server_poll + * Description : The poll function is called every 3nd second. + * If there has been no data sent (which resets the retries) in 3 seconds, close. + * If the last portion of a file has not been sent in 3 seconds, close. + * + * This could be increased, but we don't want to waste resources for bad connections. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb for which data has been acknowledged + * Returns : ERR_OK: try to send some data by calling tcp_output + * ERR_ABRT: if you have called tcp_abort from within the function! +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_server_poll(void *arg, struct tcp_pcb *pcb) +{ + espconn_msg *pspoll_cb = arg; + + /*exception calling abandon the connection for send a RST frame*/ + if (arg == NULL) { + tcp_abandon(pcb, 0); + tcp_poll(pcb, NULL, 0); + return ERR_OK; + } + + espconn_printf("espconn_server_poll %d %d\n", pspoll_cb->pcommon.recv_check, pcb->state); + pspoll_cb->pcommon.pcb = pcb; + if (pcb->state == ESTABLISHED) { + pspoll_cb->pcommon.recv_check++; + if (pspoll_cb->pcommon.timeout != 0){/*no data sent in one active connection's set timeout, close.*/ + if (pspoll_cb->pcommon.recv_check >= pspoll_cb->pcommon.timeout) { + pspoll_cb->pcommon.recv_check = 0; + espconn_server_close(pspoll_cb, pcb,0); + } + } else { + espconn_msg *ptime_msg = pserver_list; + while (ptime_msg != NULL) { + if (ptime_msg->pespconn == pspoll_cb->preverse){ + if (ptime_msg->pcommon.timeout != 0){/*no data sent in server's set timeout, close.*/ + if (pspoll_cb->pcommon.recv_check >= ptime_msg->pcommon.timeout){ + pspoll_cb->pcommon.recv_check = 0; + espconn_server_close(pspoll_cb, pcb,0); + } + } else {/*don't close for ever*/ + pspoll_cb->pcommon.recv_check = 0; + } + break; + } + ptime_msg = ptime_msg->pnext; + } + } + } else { + espconn_server_close(pspoll_cb, pcb,0); + } + + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : esponn_server_err + * Description : The pcb had an error and is already deallocated. + * The argument might still be valid (if != NULL). + * Parameters : arg -- Additional argument to pass to the callback function + * err -- Error code to indicate why the pcb has been closed + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +esponn_server_err(void *arg, err_t err) +{ + espconn_msg *pserr_cb = arg; + struct tcp_pcb *pcb = NULL; + if (pserr_cb != NULL) { + + pcb = pserr_cb->pcommon.pcb; + pserr_cb->pespconn->state = ESPCONN_CLOSE; + +// /*remove the node from the server's active connection list*/ +// espconn_list_delete(&plink_active, pserr_cb); + + /*Set the error code depend on the error type and control block state*/ + if (err == ERR_ABRT) { + switch (pcb->state) { + case SYN_RCVD: + if (pcb->nrtx == TCP_SYNMAXRTX) { + pserr_cb->pcommon.err = ESPCONN_CONN; + } else { + pserr_cb->pcommon.err = err; + } + + break; + + case ESTABLISHED: + if (pcb->nrtx == TCP_MAXRTX) { + pserr_cb->pcommon.err = ESPCONN_TIMEOUT; + } else { + pserr_cb->pcommon.err = err; + } + + break; + + case CLOSE_WAIT: + if (pcb->nrtx == TCP_MAXRTX) { + pserr_cb->pcommon.err = ESPCONN_CLSD; + } else { + pserr_cb->pcommon.err = err; + } + break; + case LAST_ACK: + pserr_cb->pcommon.err = ESPCONN_CLSD; + break; + + case CLOSED: + pserr_cb->pcommon.err = ESPCONN_CONN; + break; + default : + break; + } + } else { + pserr_cb->pcommon.err = err; + } + /*post the singer to the task for processing the connection*/ + ets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)pserr_cb); + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_accept + * Description : A new incoming connection has been accepted. + * Parameters : arg -- Additional argument to pass to the callback function + * pcb -- The connection pcb which is accepted + * err -- An unused error code, always ERR_OK currently + * Returns : acception result +*******************************************************************************/ +static err_t ICACHE_FLASH_ATTR +espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct espconn *espconn = arg; + espconn_msg *paccept = NULL; + remot_info *pinfo = NULL; + LWIP_UNUSED_ARG(err); + + if (!espconn || !espconn->proto.tcp) { + return ERR_ARG; + } + + tcp_arg(pcb, paccept); + tcp_err(pcb, esponn_server_err); + /*Ensure the active connection is less than the count of active connections on the server*/ + espconn_get_connection_info(espconn, &pinfo , 0); + espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt); + if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn)) + return ERR_ISCONN; + + /*Creates a new active connect control message*/ + paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); + tcp_arg(pcb, paccept); + + if (paccept == NULL) + return ERR_MEM; + /*Insert the node to the active connection list*/ + espconn_list_creat(&plink_active, paccept); + + paccept->preverse = espconn; + paccept->espconn_mode = ESPCONN_TCPSERVER_MODE; + paccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); + if (paccept->pespconn == NULL) + return ERR_MEM; + paccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + if (paccept->pespconn->proto.tcp == NULL) + return ERR_MEM; + + /*Reserve the remote information for current active connection*/ + paccept->pcommon.pcb = pcb; + + paccept->pcommon.remote_port = pcb->remote_port; + paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip); + paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip); + paccept->pcommon.write_flag = true; + + os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4); + espconn->proto.tcp->remote_port = pcb->remote_port; + espconn->state = ESPCONN_CONNECT; + espconn_copy_partial(paccept->pespconn, espconn); + + /*Set the specify function that should be called + * when TCP data has been successfully delivered, + * when active connection receives data, + * or periodically from active connection*/ + tcp_sent(pcb, espconn_server_sent); + tcp_recv(pcb, espconn_server_recv); + tcp_poll(pcb, espconn_server_poll, 4); /* every 1 seconds */ + /*Disable Nagle algorithm default*/ + tcp_nagle_disable(pcb); + /*Default set the total number of espconn_buf on the unsent lists for one*/ + espconn_tcp_set_buf_count(paccept->pespconn, 1); + + if (paccept->pespconn->proto.tcp->connect_callback != NULL) { + paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn); + } + + /*Enable block option for fetches the data proactive*/ + if (espconn_manual_recv_disabled(paccept)) + tcp_recv(pcb, espconn_tcp_recv); + + /*Enable keep alive option*/ + if (espconn_keepalive_disabled(paccept)) + espconn_keepalive_enable(pcb); + +// /*lock the window because of application layer don't need the data*/ +// espconn_lock_recv(paccept); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : espconn_tcp_server + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_tcp_server(struct espconn *espconn) +{ + struct tcp_pcb *pcb = NULL; + espconn_msg *pserver = NULL; + + /*Creates a new server control message*/ + pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); + if (pserver == NULL){ + return ESPCONN_MEM; + } + + /*Creates a new TCP protocol control block*/ + pcb = tcp_new(); + if (pcb == NULL) { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + os_free(pserver); + pserver = NULL; + return ESPCONN_MEM; + } else { + struct tcp_pcb *lpcb = NULL; + /*Binds the connection to a local port number and any IP address*/ + tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port); + lpcb = pcb; + /*malloc and set the state of the connection to be LISTEN*/ + pcb = tcp_listen(pcb); + if (pcb != NULL) { + /*insert the node to the active connection list*/ + espconn_list_creat(&pserver_list, pserver); + pserver->preverse = pcb; + pserver->pespconn = espconn; + pserver->count_opt = MEMP_NUM_TCP_PCB; + pserver->pcommon.timeout = 0x0a; + espconn ->state = ESPCONN_LISTEN; + /*set the specify argument that should be passed callback function*/ + tcp_arg(pcb, (void *)espconn); + /*accept callback function to call for this control block*/ + tcp_accept(pcb, espconn_tcp_accept); + return ESPCONN_OK; + } else { + /*to prevent memory leaks, ensure that each allocated is deleted*/ + memp_free(MEMP_TCP_PCB,lpcb); + os_free(pserver); + pserver = NULL; + return ESPCONN_MEM; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_tcp_delete + * Description : delete the server: delete a listening PCB and free it + * Parameters : pdeletecon -- the espconn used to delete a server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon) +{ + err_t err; + remot_info *pinfo = NULL; + espconn_msg *pdelete_msg = NULL; + struct tcp_pcb *pcb = NULL; + + if (pdeletecon == NULL) + return ESPCONN_ARG; + + espconn_get_connection_info(pdeletecon, &pinfo , 0); + /*make sure all the active connection have been disconnect*/ + if (pdeletecon->link_cnt != 0) + return ESPCONN_INPROGRESS; + else { + espconn_printf("espconn_tcp_delete %p\n",pdeletecon); + pdelete_msg = pserver_list; + while (pdelete_msg != NULL){ + if (pdelete_msg->pespconn == pdeletecon){ + /*remove the node from the client's active connection list*/ + espconn_list_delete(&pserver_list, pdelete_msg); + pcb = pdelete_msg->preverse; + os_printf("espconn_tcp_delete %d, %d\n",pcb->state, pcb->local_port); + espconn_kill_pcb(pcb->local_port); + err = tcp_close(pcb); + os_free(pdelete_msg); + pdelete_msg = NULL; + break; + } + pdelete_msg = pdelete_msg->pnext; + } + if (err == ERR_OK) + return err; + else + return ESPCONN_ARG; + } +} + +/****************************************************************************** + * FunctionName : espconn_init + * Description : used to init the function that should be used when + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_init(void) +{ + ets_task(espconn_Task, espconn_TaskPrio, espconn_TaskQueue, espconn_TaskQueueLen); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_udp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_udp.c new file mode 100755 index 0000000000..f5a6f7326e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/espconn_udp.c @@ -0,0 +1,425 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: espconn_udp.c + * + * Description: udp proto interface + * + * Modification history: + * 2014/3/31, v1.0 create this file. +*******************************************************************************/ + +#include "ets_sys.h" +#include "os_type.h" +//#include "os.h" + +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/tcp_impl.h" +#include "lwip/udp.h" + +#include "lwip/app/espconn_udp.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +extern espconn_msg *plink_active; +extern uint8 default_interface; + +enum send_opt{ + ESPCONN_SENDTO, + ESPCONN_SEND +}; +static void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn *pespconn) +{ + if (pespconn == NULL) { + return; + } + + if (pespconn->sent_callback != NULL) { + pespconn->sent_callback(pespconn); + } +} + +static void ICACHE_FLASH_ATTR espconn_data_sent(void *arg, enum send_opt opt) +{ + espconn_msg *psent = arg; + + if (psent == NULL) { + return; + } + + if (psent->pcommon.cntr == 0) { + psent->pespconn->state = ESPCONN_CONNECT; + if (psent->pcommon.err == 0) + espconn_data_sentcb(psent->pespconn); + } else { + if (opt == ESPCONN_SEND){ + espconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); + } else { + espconn_udp_sendto(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr); + } + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_udp_sent(void *arg, uint8 *psent, uint16 length) +{ + espconn_msg *pudp_sent = arg; + struct udp_pcb *upcb = pudp_sent->pcommon.pcb; + struct pbuf *p, *q ,*p_temp; + u8_t *data = NULL; + u16_t cnt = 0; + u16_t datalen = 0; + u16_t i = 0; + err_t err; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); + + if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + if ((IP_FRAG_MAX_MTU - 20 - 8) < length) { + datalen = IP_FRAG_MAX_MTU - 20 - 8; + } else { + datalen = length; + } + + p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + + if (p != NULL) { + q = p; + + while (q != NULL) { + data = (u8_t *)q->payload; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t *) psent)[cnt++]; + } + + q = q->next; + } + } else { + return ESPCONN_MEM; + } + + upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port; + IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0], + pudp_sent->pespconn->proto.udp->remote_ip[1], + pudp_sent->pespconn->proto.udp->remote_ip[2], + pudp_sent->pespconn->proto.udp->remote_ip[3]); + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); + + struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00); + struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01); + + if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) + { + if(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \ + ip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \ + ip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) { + + p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + if (pbuf_copy (p_temp,p) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent: copying to new pbuf failed\n")); + return ESPCONN_ARG; + } + netif_set_default(sta_netif); + err = udp_send(upcb, p_temp); + pbuf_free(p_temp); + netif_set_default(ap_netif); + } + } + err = udp_send(upcb, p); + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err)); + + if (p->ref != 0) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + pbuf_free(p); + pudp_sent->pcommon.ptrbuf = psent + datalen; + pudp_sent->pcommon.cntr = length - datalen; + pudp_sent->pcommon.err = err; + espconn_data_sent(pudp_sent, ESPCONN_SEND); + if (err > 0) + return ESPCONN_IF; + return err; + } else { + pbuf_free(p); + return ESPCONN_RTE; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_sendto + * Description : sent data for UDP + * Parameters : void *arg -- UDP to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +err_t ICACHE_FLASH_ATTR +espconn_udp_sendto(void *arg, uint8 *psent, uint16 length) +{ + espconn_msg *pudp_sent = arg; + struct udp_pcb *upcb = pudp_sent->pcommon.pcb; + struct espconn *pespconn = pudp_sent->pespconn; + struct pbuf *p, *q ,*p_temp; + struct ip_addr dst_ip; + u16_t dst_port; + u8_t *data = NULL; + u16_t cnt = 0; + u16_t datalen = 0; + u16_t i = 0; + err_t err; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb)); + + if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) { + return ESPCONN_ARG; + } + + if ((IP_FRAG_MAX_MTU - 20 - 8) < length) { + datalen = IP_FRAG_MAX_MTU - 20 - 8; + } else { + datalen = length; + } + + p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p)); + + if (p != NULL) { + q = p; + + while (q != NULL) { + data = (u8_t *)q->payload; + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data)); + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t *) psent)[cnt++]; + } + + q = q->next; + } + } else { + return ESPCONN_MEM; + } + + dst_port = pespconn->proto.udp->remote_port; + IP4_ADDR(&dst_ip, pespconn->proto.udp->remote_ip[0], + pespconn->proto.udp->remote_ip[1], pespconn->proto.udp->remote_ip[2], + pespconn->proto.udp->remote_ip[3]); + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port)); + + struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00); + struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01); + + if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL) + { + if( netif_is_up(sta_netif) && \ + netif_is_up(ap_netif) && \ + ip_addr_isbroadcast(&dst_ip, sta_netif) && \ + ip_addr_isbroadcast(&dst_ip, ap_netif)) { + + p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + if (pbuf_copy (p_temp,p) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sendto: copying to new pbuf failed\n")); + return ESPCONN_ARG; + } + netif_set_default(sta_netif); + err = udp_sendto(upcb, p_temp, &dst_ip, dst_port); + pbuf_free(p_temp); + netif_set_default(ap_netif); + } + } + err = udp_sendto(upcb, p, &dst_ip, dst_port); + + if (p->ref != 0) { + pbuf_free(p); + pudp_sent->pcommon.ptrbuf = psent + datalen; + pudp_sent->pcommon.cntr = length - datalen; + pudp_sent->pcommon.err = err; + espconn_data_sent(pudp_sent, ESPCONN_SENDTO); + + if (err > 0) + return ESPCONN_IF; + return err; + } else { + pbuf_free(p); + return ESPCONN_RTE; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_server_recv + * Description : This callback will be called when receiving a datagram. + * Parameters : arg -- user supplied argument + * upcb -- the udp_pcb which received data + * p -- the packet buffer that was received + * addr -- the remote IP address from which the packet was received + * port -- the remote port from which the packet was received + * Returns : none +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +espconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, + struct ip_addr *addr, u16_t port) +{ + espconn_msg *precv = arg; + struct pbuf *q = NULL; + u8_t *pdata = NULL; + u16_t length = 0; + struct ip_info ipconfig; + + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_server_recv %d %p\n", __LINE__, upcb)); + + precv->pcommon.remote_ip[0] = ip4_addr1_16(addr); + precv->pcommon.remote_ip[1] = ip4_addr2_16(addr); + precv->pcommon.remote_ip[2] = ip4_addr3_16(addr); + precv->pcommon.remote_ip[3] = ip4_addr4_16(addr); + precv->pcommon.remote_port = port; + precv->pcommon.pcb = upcb; + + if (wifi_get_opmode() != 1) { + wifi_get_ip_info(1, &ipconfig); + + if (!ip_addr_netcmp(addr, &ipconfig.ip, &ipconfig.netmask)) { + wifi_get_ip_info(0, &ipconfig); + } + } else { + wifi_get_ip_info(0, &ipconfig); + } + + precv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&ipconfig.ip); + precv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&ipconfig.ip); + + if (p != NULL) { + pdata = (u8_t *)os_zalloc(p ->tot_len + 1); + length = pbuf_copy_partial(p, pdata, p ->tot_len, 0); + precv->pcommon.pcb = upcb; + pbuf_free(p); + if (length != 0) { + if (precv->pespconn->recv_callback != NULL) { + precv->pespconn->recv_callback(precv->pespconn, pdata, length); + } + } + os_free(pdata); + } else { + return; + } +} + +/****************************************************************************** + * FunctionName : espconn_udp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg *pdiscon) +{ + if (pdiscon == NULL) { + return; + } + + struct udp_pcb *upcb = pdiscon->pcommon.pcb; + + udp_disconnect(upcb); + + udp_remove(upcb); + + espconn_list_delete(&plink_active, pdiscon); + + os_free(pdiscon); + pdiscon = NULL; +} + +/****************************************************************************** + * FunctionName : espconn_udp_server + * Description : Initialize the server: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_udp_server(struct espconn *pespconn) +{ + struct udp_pcb *upcb = NULL; + espconn_msg *pserver = NULL; + upcb = udp_new(); + + if (upcb == NULL) { + return ESPCONN_MEM; + } else { + pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); + + if (pserver == NULL) { + udp_remove(upcb); + return ESPCONN_MEM; + } + + pserver->pcommon.pcb = upcb; + pserver->pespconn = pespconn; + espconn_list_creat(&plink_active, pserver); + udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port); + udp_recv(upcb, espconn_udp_recv, (void *)pserver); + return ESPCONN_OK; + } +} + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip) +{ + if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_leave_multigrup failed!\n")); + return -1; + }; + + return ESPCONN_OK; +} + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip) +{ + if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) { + LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n")); + return -1; + }; + + /* join to any IP address at the port */ + return ESPCONN_OK; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/netio.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/netio.c new file mode 100755 index 0000000000..47b3599341 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/netio.c @@ -0,0 +1,369 @@ +/** + * @file + * MetIO Server + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#include "lwip/opt.h" + +#if LWIP_TCP +#include "lwip/tcp.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/* + * This implements a netio server. + * The client sends a command word (4 bytes) then a data length word (4 bytes). + * If the command is "receive", the server is to consume "data length" bytes into + * a circular buffer until the first byte is non-zero, then it is to consume + * another command/data pair. + * If the command is "send", the server is to send "data length" bytes from a circular + * buffer with the first byte being zero, until "some time" (6 seconds in the + * current netio126.zip download) has passed and then send one final buffer with + * the first byte being non-zero. Then it is to consume another command/data pair. + */ + +/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */ + +/* implementation options */ +#define NETIO_BUF_SIZE (4 * 1024) +#define NETIO_USE_STATIC_BUF 0 + +/* NetIO server state definition */ +#define NETIO_STATE_WAIT_FOR_CMD 0 +#define NETIO_STATE_RECV_DATA 1 +#define NETIO_STATE_SEND_DATA 2 +#define NETIO_STATE_SEND_DATA_LAST 3 +#define NETIO_STATE_DONE 4 + +struct netio_state { + u32_t state; + u32_t cmd; + u32_t data_len; + u32_t cntr; + u8_t * buf_ptr; + u32_t buf_pos; + u32_t first_byte; + u32_t time_stamp; +}; + +/* NetIO command protocol definition */ +#define NETIO_CMD_QUIT 0 +#define NETIO_CMD_C2S 1 +#define NETIO_CMD_S2C 2 +#define NETIO_CMD_RES 3 + +static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); + +static void ICACHE_FLASH_ATTR +netio_close(void *arg, struct tcp_pcb *pcb) +{ + err_t err; + + struct netio_state *ns = arg; + ns->state = NETIO_STATE_DONE; + tcp_recv(pcb, NULL); + err = tcp_close(pcb); + + if (err != ERR_OK) { + /* closing failed, try again later */ + tcp_recv(pcb, netio_recv); + } else { + /* closing succeeded */ +#if NETIO_USE_STATIC_BUF != 1 + if(ns->buf_ptr != NULL){ + mem_free(ns->buf_ptr); + } +#endif + tcp_arg(pcb, NULL); + tcp_poll(pcb, NULL, 0); + tcp_sent(pcb, NULL); + if (arg != NULL) { + mem_free(arg); + } + } +} + +static err_t ICACHE_FLASH_ATTR +netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct netio_state *ns = arg; + u8_t * data_ptr; + u32_t data_cntr; + struct pbuf *q = p; + u16_t len; + + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + } + + if (err == ERR_OK && q != NULL) { + + while (q != NULL) { + data_cntr = q->len; + data_ptr = q->payload; + while (data_cntr--) { + if (ns->state == NETIO_STATE_DONE){ + netio_close(ns, pcb); + break; + } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) { + if (ns->cntr < 4) { + /* build up the CMD field */ + ns->cmd <<= 8; + ns->cmd |= *data_ptr++; + ns->cntr++; + } else if (ns->cntr < 8) { + /* build up the DATA field */ + ns->data_len <<= 8; + ns->data_len |= *data_ptr++; + ns->cntr++; + + if (ns->cntr == 8) { + /* now we have full command and data words */ + ns->cntr = 0; + ns->buf_pos = 0; + ns->buf_ptr[0] = 0; + if (ns->cmd == NETIO_CMD_C2S) { + ns->state = NETIO_STATE_RECV_DATA; + } else if (ns->cmd == NETIO_CMD_S2C) { + ns->state = NETIO_STATE_SEND_DATA; + /* start timer */ + ns->time_stamp = sys_now(); + /* send first round of data */ + + len = tcp_sndbuf(pcb); + len = LWIP_MIN(len, ns->data_len - ns->cntr); + len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos); + + do { + err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY); + if (err == ERR_MEM) { + len /= 2; + } + } while ((err == ERR_MEM) && (len > 1)); + + ns->buf_pos += len; + ns->cntr += len; + + } else { + /* unrecognized command, punt */ + ns->cntr = 0; + ns->buf_pos = 0; + ns->buf_ptr[0] = 0; + netio_close(ns, pcb); + break; + } + } + } else { + /* in trouble... shouldn't be in this state! */ + } + + } else if (ns->state == NETIO_STATE_RECV_DATA) { + + if(ns->cntr == 0){ + /* save the first byte of this new round of data + * this will not match ns->buf_ptr[0] in the case that + * NETIO_BUF_SIZE is less than ns->data_len. + */ + ns->first_byte = *data_ptr; + } + + ns->buf_ptr[ns->buf_pos++] = *data_ptr++; + ns->cntr++; + + if (ns->buf_pos == NETIO_BUF_SIZE) { + /* circularize the buffer */ + ns->buf_pos = 0; + } + + if(ns->cntr == ns->data_len){ + ns->cntr = 0; + if (ns->first_byte != 0) { + /* if this last round did not start with 0, + * go look for another command */ + ns->state = NETIO_STATE_WAIT_FOR_CMD; + ns->data_len = 0; + ns->cmd = 0; + /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */ + } else { + /* stay here and wait on more data */ + } + } + + } else if (ns->state == NETIO_STATE_SEND_DATA + || ns->state == NETIO_STATE_SEND_DATA_LAST) { + /* I don't think this should happen... */ + } else { + /* done / quit */ + netio_close(ns, pcb); + break; + } /* end of ns->state condition */ + } /* end of while data still in this pbuf */ + + q = q->next; + } + + pbuf_free(p); + + } else { + + /* error or closed by other side */ + if (p != NULL) { + pbuf_free(p); + } + + /* close the connection */ + netio_close(ns, pcb); + + } + return ERR_OK; + +} + +static err_t ICACHE_FLASH_ATTR +netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct netio_state *ns = arg; + err_t err = ERR_OK; + + if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) { + /* done with this round of sending */ + ns->buf_pos = 0; + ns->cntr = 0; + + /* check if timer expired */ + if (sys_now() - ns->time_stamp > 600) { + ns->buf_ptr[0] = 1; + ns->state = NETIO_STATE_SEND_DATA_LAST; + } else { + ns->buf_ptr[0] = 0; + } + } + + if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){ + len = tcp_sndbuf(pcb); + len = LWIP_MIN(len, ns->data_len - ns->cntr); + len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos); + + if(ns->cntr < ns->data_len){ + do { + err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY); + if (err == ERR_MEM) { + len /= 2; + } + } while ((err == ERR_MEM) && (len > 1)); + + ns->buf_pos += len; + if(ns->buf_pos >= NETIO_BUF_SIZE){ + ns->buf_pos = 0; + } + + ns->cntr += len; + } + } + + if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){ + /* we have buffered up all our data to send this last round, go look for a command */ + ns->state = NETIO_STATE_WAIT_FOR_CMD; + ns->cntr = 0; + /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */ + } + + return ERR_OK; +} + +static err_t ICACHE_FLASH_ATTR +netio_poll(void *arg, struct tcp_pcb *pcb) +{ + struct netio_state * ns = arg; + if(ns->state == NETIO_STATE_SEND_DATA){ + + } else if(ns->state == NETIO_STATE_DONE){ + netio_close(ns, pcb); + } + + return ERR_OK; + +} + +#if NETIO_USE_STATIC_BUF == 1 +static u8_t netio_buf[NETIO_BUF_SIZE]; +#endif + +static err_t ICACHE_FLASH_ATTR +netio_accept(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct netio_state * ns; + + LWIP_UNUSED_ARG(err); + + ns = (struct netio_state *)mem_malloc(sizeof(struct netio_state)); + + if(ns == NULL){ + return ERR_MEM; + } + + ns->state = NETIO_STATE_WAIT_FOR_CMD; + ns->data_len = 0; + ns->cmd = 0; + ns->cntr = 0; + ns->buf_pos = 0; +#if NETIO_USE_STATIC_BUF == 1 + ns->buf_ptr = netio_buf; +#else + ns->buf_ptr = (u8_t *)mem_malloc(NETIO_BUF_SIZE); + + if(ns->buf_ptr == NULL){ + mem_free(ns); + return ERR_MEM; + } +#endif + + ns->buf_ptr[0] = 0; + + tcp_arg(pcb, ns); + tcp_sent(pcb, netio_sent); + tcp_recv(pcb, netio_recv); + tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */ + return ERR_OK; +} + +void ICACHE_FLASH_ATTR netio_init(void) +{ + struct tcp_pcb *pcb; + + pcb = tcp_new(); + tcp_bind(pcb, IP_ADDR_ANY, 18767); + pcb = tcp_listen(pcb); + tcp_accept(pcb, netio_accept); +} + +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/ping.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/ping.c new file mode 100755 index 0000000000..6bd6f0ea07 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/app/ping.c @@ -0,0 +1,329 @@ +/** + * @file + * Ping sender module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/** + * This is an example of a "ping" sender (with raw API and socket API). + * It can be used as a start point to maintain opened a network connection, or + * like a network "watchdog" for your device. + * + */ + +/* + * copyright (c) 2010 - 2011 Espressif System + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +#include "lwip/raw.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/inet_chksum.h" +#include "os_type.h" +#include "osapi.h" + +#include "lwip/app/ping.h" + +#if PING_USE_SOCKETS +#include "lwip/sockets.h" +#include "lwip/inet.h" +#endif /* PING_USE_SOCKETS */ + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/* ping variables */ +static u16_t ping_seq_num = 0; +static u32_t ping_time; + +static void ICACHE_FLASH_ATTR ping_timeout(void* arg) +{ + struct ping_msg *pingmsg = (struct ping_msg *)arg; + pingmsg->timeout_count ++; + if (pingmsg->ping_opt->recv_function == NULL){ + os_printf("ping timeout\n"); + } else { + struct ping_resp pingresp; + os_bzero(&pingresp, sizeof(struct ping_resp)); + pingresp.ping_err = -1; + pingmsg->ping_opt->recv_function(pingmsg->ping_opt, (void*)&pingresp); + } +} + +/** Prepare a echo ICMP request */ +static void ICACHE_FLASH_ATTR +ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) +{ + size_t i = 0; + size_t data_len = len - sizeof(struct icmp_echo_hdr); + + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + ++ ping_seq_num; + if (ping_seq_num == 0x7fff) + ping_seq_num = 0; + + iecho->seqno = htons(ping_seq_num); + + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, len); +} + +static void ICACHE_FLASH_ATTR +ping_prepare_er(struct icmp_echo_hdr *iecho, u16_t len) +{ + + ICMPH_TYPE_SET(iecho, ICMP_ER); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + + iecho->chksum = inet_chksum(iecho, len); +} + +/* Ping using the raw ip */ +static u8_t ICACHE_FLASH_ATTR +ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) +{ + struct icmp_echo_hdr *iecho = NULL; + static u16_t seqno = 0; + struct ping_msg *pingmsg = (struct ping_msg*)arg; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_ASSERT("p != NULL", p != NULL); + + if (pbuf_header( p, -PBUF_IP_HLEN)==0) { + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) { + LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); + if (iecho->seqno != seqno){ + /* do some ping result processing */ + { + struct ip_hdr *iphdr = NULL; + char ipaddrstr[16]; + ip_addr_t source_ip; + sys_untimeout(ping_timeout, pingmsg); + os_bzero(&source_ip, sizeof(ip_addr_t)); + os_bzero(ipaddrstr, sizeof(ipaddrstr)); + uint32 delay = system_relative_time(pingmsg->ping_sent); + delay /= PING_COARSE; + iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN); + source_ip.addr = iphdr->src.addr; + ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr)); + if (pingmsg->ping_opt->recv_function == NULL){ + os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno)); + } else { + struct ping_resp pingresp; + os_bzero(&pingresp, sizeof(struct ping_resp)); + pingresp.bytes = PING_DATA_SIZE; + pingresp.resp_time = delay; + pingresp.seqno = ntohs(iecho->seqno); + pingresp.ping_err = 0; + pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); + } + } + seqno = iecho->seqno; + } + + PING_RESULT(1); + pbuf_free(p); + return 1; /* eat the packet */ + } +// } else if(iecho->type == ICMP_ECHO){ +// struct pbuf *q = NULL; +// os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno)); +// q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM); +// if (q!=NULL) { +// pbuf_copy(q, p); +// iecho = (struct icmp_echo_hdr *)q->payload; +// ping_prepare_er(iecho, q->tot_len); +// raw_sendto(pcb, q, addr); +// pbuf_free(q); +// } +// pbuf_free(p); +// return 1; +// } + } + + return 0; /* don't eat the packet */ +} + +static void ICACHE_FLASH_ATTR +ping_send(struct raw_pcb *raw, ip_addr_t *addr) +{ + struct pbuf *p = NULL; + struct icmp_echo_hdr *iecho = NULL; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + + LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF( PING_DEBUG, ("\n")); + LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); + + p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); + if (!p) { + return; + } + if ((p->len == p->tot_len) && (p->next == NULL)) { + iecho = (struct icmp_echo_hdr *)p->payload; + + ping_prepare_echo(iecho, (u16_t)ping_size); + + raw_sendto(raw, p, addr); + ping_time = sys_now(); + } + pbuf_free(p); +} + +static void ICACHE_FLASH_ATTR +ping_coarse_tmr(void *arg) +{ + struct ping_msg *pingmsg = (struct ping_msg*)arg; + struct ping_option *ping_opt= NULL; + struct ping_resp pingresp; + ip_addr_t ping_target; + + LWIP_ASSERT("ping_timeout: no pcb given!", pingmsg != NULL); + ping_target.addr = pingmsg->ping_opt->ip; + ping_opt = pingmsg->ping_opt; + if (--pingmsg->sent_count != 0){ + pingmsg ->ping_sent = system_get_time(); + ping_send(pingmsg->ping_pcb, &ping_target); + + sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg); + sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg); + } else { + uint32 delay = system_relative_time(pingmsg->ping_start); + delay /= PING_COARSE; +// ping_seq_num = 0; + if (ping_opt->sent_function == NULL){ + os_printf("ping %d, timeout %d, total payload %d bytes, %d ms\n", + pingmsg->max_count, pingmsg->timeout_count, PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count),delay); + } else { + os_bzero(&pingresp, sizeof(struct ping_resp)); + pingresp.total_count = pingmsg->max_count; + pingresp.timeout_count = pingmsg->timeout_count; + pingresp.total_bytes = PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count); + pingresp.total_time = delay; + pingresp.ping_err = 0; + } + sys_untimeout(ping_coarse_tmr, pingmsg); + raw_remove(pingmsg->ping_pcb); + os_free(pingmsg); + if (ping_opt->sent_function != NULL) + ping_opt->sent_function(ping_opt,(uint8*)&pingresp); + } +} + +static bool ICACHE_FLASH_ATTR +ping_raw_init(struct ping_msg *pingmsg) +{ + if (pingmsg == NULL) + return false; + + ip_addr_t ping_target; + pingmsg->ping_pcb = raw_new(IP_PROTO_ICMP); + LWIP_ASSERT("ping_pcb != NULL", pingmsg->ping_pcb != NULL); + + raw_recv(pingmsg->ping_pcb, ping_recv, pingmsg); + raw_bind(pingmsg->ping_pcb, IP_ADDR_ANY); + + ping_target.addr = pingmsg->ping_opt->ip; + pingmsg ->ping_sent = system_get_time(); + ping_send(pingmsg->ping_pcb, &ping_target); + + sys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg); + sys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg); + return true; +} + +bool ICACHE_FLASH_ATTR +ping_start(struct ping_option *ping_opt) +{ + struct ping_msg *pingmsg = NULL; + pingmsg = (struct ping_msg *)os_zalloc(sizeof(struct ping_msg)); + if (pingmsg == NULL || ping_opt == NULL) + return false; + + pingmsg->ping_opt = ping_opt; + if (ping_opt->count != 0) + pingmsg->max_count = ping_opt->count; + else + pingmsg->max_count = DEFAULT_PING_MAX_COUNT; + + if (ping_opt->coarse_time != 0) + pingmsg->coarse_time = ping_opt->coarse_time * PING_COARSE; + else + pingmsg->coarse_time = PING_COARSE; + + pingmsg->ping_start = system_get_time(); + pingmsg->sent_count = pingmsg->max_count; + return ping_raw_init(pingmsg); +} + +bool ICACHE_FLASH_ATTR +ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv) +{ + if (ping_opt == NULL) + return false; + + ping_opt ->recv_function = ping_recv; + return true; +} + +bool ICACHE_FLASH_ATTR +ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent) +{ + if (ping_opt == NULL) + return false; + + ping_opt ->sent_function = ping_sent; + return true; +} + +#endif /* LWIP_RAW */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/Makefile new file mode 100755 index 0000000000..99159101e2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblwipcore.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/def.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/def.c new file mode 100755 index 0000000000..352b55241a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/def.c @@ -0,0 +1,108 @@ +/** + * @file + * Common functions used throughout the stack. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/def.h" + +/** + * These are reference implementations of the byte swapping functions. + * Again with the aim of being simple, correct and fully portable. + * Byte swapping is the second thing you would want to optimize. You will + * need to port it to your architecture and in your cc.h: + * + * #define LWIP_PLATFORM_BYTESWAP 1 + * #define LWIP_PLATFORM_HTONS(x) + * #define LWIP_PLATFORM_HTONL(x) + * + * Note ntohs() and ntohl() are merely references to the htonx counterparts. + */ + +#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) + +/** + * Convert an u16_t from host- to network byte order. + * + * @param n u16_t in host byte order + * @return n in network byte order + */ +u16_t +lwip_htons(u16_t n) +{ + return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + +/** + * Convert an u16_t from network- to host byte order. + * + * @param n u16_t in network byte order + * @return n in host byte order + */ +u16_t +lwip_ntohs(u16_t n) +{ + return lwip_htons(n); +} + +/** + * Convert an u32_t from host- to network byte order. + * + * @param n u32_t in host byte order + * @return n in network byte order + */ +u32_t +lwip_htonl(u32_t n) +{ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000UL) >> 8) | + ((n & 0xff000000UL) >> 24); +} + +/** + * Convert an u32_t from network- to host byte order. + * + * @param n u32_t in network byte order + * @return n in host byte order + */ +u32_t +lwip_ntohl(u32_t n) +{ + return lwip_htonl(n); +} + +#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dhcp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dhcp.c new file mode 100755 index 0000000000..8c79ecafa1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dhcp.c @@ -0,0 +1,1818 @@ +/** + * @file + * Dynamic Host Configuration Protocol client + * + */ + +/* + * + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. + * + * Author: Leon Woestenberg + * + * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform + * with RFC 2131 and RFC 2132. + * + * TODO: + * - Support for interfaces other than Ethernet (SLIP, PPP, ...) + * + * Please coordinate changes and requests with Leon Woestenberg + * + * + * Integration with your code: + * + * In lwip/dhcp.h + * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) + * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) + * + * Then have your application call dhcp_coarse_tmr() and + * dhcp_fine_tmr() on the defined intervals. + * + * dhcp_start(struct netif *netif); + * starts a DHCP client instance which configures the interface by + * obtaining an IP address lease and maintaining it. + * + * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) + * to remove the DHCP client. + * + */ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/dns.h" +#include "netif/etharp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" + * #define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * MTU is checked to be big enough in dhcp_start */ +#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) +#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 +/** Minimum length for reply before packet is parsed */ +#define DHCP_MIN_REPLY_LEN 44 + +#define REBOOT_TRIES 2 + +/** Option handling: options are parsed in dhcp_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +#define DHCP_OPTION_IDX_OVERLOAD 0 +#define DHCP_OPTION_IDX_MSG_TYPE 1 +#define DHCP_OPTION_IDX_SERVER_ID 2 +#define DHCP_OPTION_IDX_LEASE_TIME 3 +#define DHCP_OPTION_IDX_T1 4 +#define DHCP_OPTION_IDX_T2 5 +#define DHCP_OPTION_IDX_SUBNET_MASK 6 +#define DHCP_OPTION_IDX_ROUTER 7 +#define DHCP_OPTION_IDX_DNS_SERVER 8 +#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) + +/** Holds the decoded option values, only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; +/** Holds a flag which option was received and is contained in dhcp_rx_options_val, + only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; + +#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (os_memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) + +bool manual_set_flag = false; /* add for AT by tzx*/ + +/* DHCP client state machine functions */ +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_bind(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +static err_t dhcp_decline(struct netif *netif); +#endif /* DHCP_DOES_ARP_CHECK */ +static err_t dhcp_rebind(struct netif *netif); +static err_t dhcp_reboot(struct netif *netif); +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); + +/* receive, unfold, parse and free incoming messages */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); + +/* set the DHCP timers */ +static void dhcp_timeout(struct netif *netif); +static void dhcp_t1_timeout(struct netif *netif); +static void dhcp_t2_timeout(struct netif *netif); + +/* build outgoing messages */ +/* create a DHCP message, fill in common headers */ +static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); +/* free a DHCP request */ +static void dhcp_delete_msg(struct dhcp *dhcp); +/* add a DHCP option (type, then length in bytes) */ +static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); +/* add option values */ +static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); +static void dhcp_option_short(struct dhcp *dhcp, u16_t value); +static void dhcp_option_long(struct dhcp *dhcp, u32_t value); +/* always add the DHCP options trailer to end and pad */ +static void dhcp_option_trailer(struct dhcp *dhcp); + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We clear any existing set IP address and restart DHCP negotiation + * afresh (as per RFC2131 3.2.3). + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_handle_nak(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* Set the interface down since the address must no longer be used, as per RFC2131 */ + netif_set_down(netif); + /* remove IP address from interface */ + netif_set_ipaddr(netif, IP_ADDR_ANY); + netif_set_gw(netif, IP_ADDR_ANY); + netif_set_netmask(netif, IP_ADDR_ANY); + /* Change to a defined state */ + dhcp_set_state(dhcp, DHCP_BACKING_OFF); + /* We can immediately restart discovery */ + dhcp_discover(netif); +} + +#if DHCP_DOES_ARP_CHECK +/** + * Checks if the offered IP address is already in use. + * + * It does so by sending an ARP request for the offered address and + * entering CHECKING state. If no ARP reply is received within a small + * interval, the address is assumed to be free for use by us. + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_check(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], + (s16_t)netif->name[1])); + dhcp_set_state(dhcp, DHCP_CHECKING); + /* create an ARP query for the offered IP address, expecting that no host + responds, as the IP address should not be in use. */ + result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); + if (result != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); + } + dhcp->tries++; + msecs = 500; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); +} +#endif /* DHCP_DOES_ARP_CHECK */ + +/** + * Remember the configuration offered by a DHCP server. + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_handle_offer(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* obtain the server address */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { + ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->server_ip_addr))); + /* remember offered address */ + ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); + } +} + +/** + * Select a DHCP server offer out of all offers. + * + * Simply select the first offer received. + * + * @param netif the netif under DHCP control + * @return lwIP specific error (see error.h) + */ +static err_t ICACHE_FLASH_ATTR +dhcp_select(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + dhcp_set_state(dhcp, DHCP_REQUESTING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + + /* MUST request the offered IP address */ + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr))); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/); + dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); + dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); + dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS); + dhcp_option_byte(dhcp, DHCP_OPTION_PRD); + dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_VSN); + +#if LWIP_NETIF_HOSTNAME + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)os_strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } + } +#endif /* LWIP_NETIF_HOSTNAME */ + + dhcp_option_trailer(dhcp); + /* shrink the pbuf to the actual content length */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* send broadcast to any DHCP server */ + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * The DHCP timer that checks for lease renewal/rebind timeouts. + */ +void ICACHE_FLASH_ATTR +dhcp_coarse_tmr() +{ + struct netif *netif = netif_list; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); + /* iterate through all network interfaces */ + while (netif != NULL) { + /* only act on DHCP configured interfaces */ + if (netif->dhcp != NULL) { + /* timer is active (non zero), and triggers (zeroes) now? */ + if (netif->dhcp->t2_timeout-- == 1) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); + /* this clients' rebind timeout triggered */ + dhcp_t2_timeout(netif); + /* timer is active (non zero), and triggers (zeroes) now */ + } else if (netif->dhcp->t1_timeout-- == 1) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); + /* this clients' renewal timeout triggered */ + dhcp_t1_timeout(netif); + } + } + /* proceed to next netif */ + netif = netif->next; + } +} + +/** + * DHCP transaction timeout handling + * + * A DHCP server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCP request is timed out. + */ +void ICACHE_FLASH_ATTR +dhcp_fine_tmr() +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + /* only act on DHCP configured interfaces */ + if (netif->dhcp != NULL) { + /*add DHCP retries processing by LiuHan*/ + if (DHCP_MAXRTX != 0) { + if (netif->dhcp->tries >= DHCP_MAXRTX){ + os_printf("DHCP timeout\n"); + if (netif->dhcp_event != NULL) + netif->dhcp_event(); + break; + } + } + /* timer is active (non zero), and is about to trigger now */ + if (netif->dhcp->request_timeout > 1) { + netif->dhcp->request_timeout--; + } + else if (netif->dhcp->request_timeout == 1) { + netif->dhcp->request_timeout--; + /* { netif->dhcp->request_timeout == 0 } */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); + /* this client's request timeout triggered */ + dhcp_timeout(netif); + } + } + /* proceed to next network interface */ + netif = netif->next; + } + +} + +/** + * A DHCP negotiation transaction, or ARP request, has timed out. + * + * The timer that was started with the DHCP or ARP request has + * timed out, indicating no response was received in time. + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); + /* back-off period has passed, or server selection timed out */ + if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); + dhcp_discover(netif); + /* receiving the requested lease timed out */ + } else if (dhcp->state == DHCP_REQUESTING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); + if (dhcp->tries <= 5) { + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); + dhcp_release(netif); + dhcp_discover(netif); + } +#if DHCP_DOES_ARP_CHECK + /* received no ARP reply for the offered address (which is good) */ + } else if (dhcp->state == DHCP_CHECKING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); + if (dhcp->tries <= 1) { + dhcp_check(netif); + /* no ARP replies on the offered address, + looks like the IP address is indeed free */ + } else { + /* bind the interface to the offered address */ + dhcp_bind(netif); + } +#endif /* DHCP_DOES_ARP_CHECK */ + } + /* did not get response to renew request? */ + else if (dhcp->state == DHCP_RENEWING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); + /* just retry renewal */ + /* note that the rebind timer will eventually time-out if renew does not work */ + dhcp_renew(netif); + /* did not get response to rebind request? */ + } else if (dhcp->state == DHCP_REBINDING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); + if (dhcp->tries <= 8) { + dhcp_rebind(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); + dhcp_release(netif); + dhcp_discover(netif); + } + } else if (dhcp->state == DHCP_REBOOTING) { + if (dhcp->tries < REBOOT_TRIES) { + dhcp_reboot(netif); + } else { + dhcp_discover(netif); + } + } +} + +/** + * The renewal period has timed out. + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_t1_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || + (dhcp->state == DHCP_RENEWING)) { + /* just retry to renew - note that the rebind timer (t2) will + * eventually time-out if renew tries fail. */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t1_timeout(): must renew\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_RENEWING, not DHCP_BOUND */ + dhcp_renew(netif); + } +} + +/** + * The rebind period has timed out. + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_t2_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || + (dhcp->state == DHCP_RENEWING)) { + /* just retry to rebind */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t2_timeout(): must rebind\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_REBINDING, not DHCP_BOUND */ + dhcp_rebind(netif); + } +} + +/** + * Handle a DHCP ACK packet + * + * @param netif the netif under DHCP control + */ +static void ICACHE_FLASH_ATTR +dhcp_handle_ack(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; +#if LWIP_DNS + u8_t n; +#endif /* LWIP_DNS */ + + /* clear options we might not get from the ACK */ + ip_addr_set_zero(&dhcp->offered_sn_mask); + ip_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* lease time given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { + /* remember offered lease time */ + dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); + } + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { + /* remember given renewal period */ + dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); + } else { + /* calculate safe periods for renewal */ + dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; + } + + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { + /* remember given rebind period */ + dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); + } else { + /* calculate safe periods for rebinding */ + dhcp->offered_t2_rebind = dhcp->offered_t0_lease; + } + + /* (y)our internet address */ + ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); + +#if LWIP_DHCP_BOOTP_FILE + /* copy boot server address, + boot file name copied in dhcp_parse_reply if not overloaded */ + ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* subnet mask given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { + /* remember given subnet mask */ + ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); + dhcp->subnet_mask_given = 1; + } else { + dhcp->subnet_mask_given = 0; + } + + /* gateway router */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { + ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); + } + +#if LWIP_DNS + /* DNS servers */ + n = 0; + if(manual_set_flag == false) { + while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) { + ip_addr_t dns_addr; + ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); + dns_setserver(n, &dns_addr); + n++; + } + } +#endif /* LWIP_DNS */ +} + +/** Set a statically allocated struct dhcp to work with. + * Using this prevents dhcp_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct dhcp + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void ICACHE_FLASH_ATTR +dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp != NULL", dhcp != NULL); + LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); + + /* clear data structure */ + os_memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_OFF); */ + netif->dhcp = dhcp; +} + +/** Removes a struct dhcp from a netif. + * + * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the + * struct dhcp since the memory is passed back to the heap. + * + * @param netif the netif from which to remove the struct dhcp + */ +void ICACHE_FLASH_ATTR dhcp_cleanup(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + + if (netif->dhcp != NULL) { + mem_free(netif->dhcp); + netif->dhcp = NULL; + } +} + +/** + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + */ +err_t ICACHE_FLASH_ATTR +dhcp_start(struct netif *netif) +{ + struct dhcp *dhcp; + err_t result = ERR_OK; + LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); + dhcp = netif->dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* Remove the flag that says this netif is handled by DHCP, + it is set when we succeeded starting. */ + netif->flags &= ~NETIF_FLAG_DHCP; + + /* check hwtype of the netif */ + if ((netif->flags & NETIF_FLAG_ETHARP) == 0) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n")); + return ERR_ARG; + } + + /* check MTU of the netif */ + if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); + return ERR_MEM; + } + + /* no DHCP client attached yet? */ + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); + dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); + return ERR_MEM; + } + /* store this dhcp client in the netif */ + netif->dhcp = dhcp; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); + /* already has DHCP client attached */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); + if (dhcp->pcb != NULL) { + udp_remove(dhcp->pcb); + } + LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); + } + + /* clear data structure */ + os_memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_OFF); */ + /* allocate UDP PCB */ + dhcp->pcb = udp_new(); + if (dhcp->pcb == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); + return ERR_MEM; + } + dhcp->pcb->so_options |= SOF_BROADCAST; + /* set up local and remote port for the pcb */ + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + /* set up the recv callback and argument */ + udp_recv(dhcp->pcb, dhcp_recv, netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); + /* (re)start the DHCP negotiation */ + result = dhcp_discover(netif); + if (result != ERR_OK) { + /* free resources allocated above */ + dhcp_stop(netif); + return ERR_MEM; + } + /* Set the flag that says this netif is handled by DHCP. */ + netif->flags |= NETIF_FLAG_DHCP; + return result; +} + +/** + * Inform a DHCP server of our manual configuration. + * + * This informs DHCP servers of our fixed IP address configuration + * by sending an INFORM message. It does not involve DHCP address + * configuration, it is just here to be nice to the network. + * + * @param netif The lwIP network interface + */ +void ICACHE_FLASH_ATTR +dhcp_inform(struct netif *netif) +{ + struct dhcp dhcp; + err_t result = ERR_OK; + struct udp_pcb *pcb; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + os_memset(&dhcp, 0, sizeof(struct dhcp)); + dhcp_set_state(&dhcp, DHCP_INFORM); + + if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) { + /* re-use existing pcb */ + pcb = netif->dhcp->pcb; + } else { + pcb = udp_new(); + if (pcb == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); + return; + } + dhcp.pcb = pcb; + dhcp.pcb->so_options |= SOF_BROADCAST; + udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); + } + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); + if (result == ERR_OK) { + dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); + + dhcp_option_trailer(&dhcp); + + pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); + udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(&dhcp); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); + } + + if (dhcp.pcb != NULL) { + /* otherwise, the existing pcb was used */ + udp_remove(dhcp.pcb); + } +} + +/** Handle a possible change in the network configuration. + * + * This enters the REBOOTING state to verify that the currently bound + * address is still valid. + */ +void ICACHE_FLASH_ATTR +dhcp_network_changed(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + if (!dhcp) + return; + switch (dhcp->state) { + case DHCP_REBINDING: + case DHCP_RENEWING: + case DHCP_BOUND: + case DHCP_REBOOTING: + netif_set_down(netif); + dhcp->tries = 0; + dhcp_reboot(netif); + break; + case DHCP_OFF: + /* stay off */ + break; + default: + dhcp->tries = 0; +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + dhcp_discover(netif); + break; + } +} + +#if DHCP_DOES_ARP_CHECK +/** + * Match an ARP reply with the offered IP address. + * + * @param netif the network interface on which the reply was received + * @param addr The IP address we received a reply from + */ +void ICACHE_FLASH_ATTR dhcp_arp_reply(struct netif *netif, ip_addr_t *addr) +{ + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); + /* is a DHCP client doing an ARP check? */ + if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", + ip4_addr_get_u32(addr))); + /* did a host respond with the address we + were offered by the DHCP server? */ + if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { + /* we will not accept the offered address */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); + dhcp_decline(netif); + } + } +} + +/** + * Decline an offered lease. + * + * Tell the DHCP server we do not accept the offered address. + * One reason to decline the lease is when we find out the address + * is already in use by another host (through ARP). + * + * @param netif the netif under DHCP control + */ +static err_t ICACHE_FLASH_ATTR +dhcp_decline(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result = ERR_OK; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); + dhcp_set_state(dhcp, DHCP_BACKING_OFF); + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option_trailer(dhcp); + /* resize pbuf to reflect true size of options */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* per section 4.4.4, broadcast DECLINE messages */ + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_decline: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = 10*1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} +#endif /* DHCP_DOES_ARP_CHECK */ + + +/** + * Start the DHCP process, discover a DHCP server. + * + * @param netif the netif under DHCP control + */ +static err_t ICACHE_FLASH_ATTR +dhcp_discover(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result = ERR_OK; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); + ip_addr_set_any(&dhcp->offered_ip_addr); + dhcp_set_state(dhcp, DHCP_SELECTING); + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); + if (result == ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)os_strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } + } +#endif /* LWIP_NETIF_HOSTNAME */ + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/); + dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); + dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); + dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT); + dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS); + dhcp_option_byte(dhcp, DHCP_OPTION_PRD); + dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER); + dhcp_option_byte(dhcp, DHCP_OPTION_VSN); + + dhcp_option_trailer(dhcp); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); + } + dhcp->tries++; +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; + autoip_start(netif); + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * Bind the interface to the offered IP address. + * + * @param netif network interface to bind to the offered address + */ +static void ICACHE_FLASH_ATTR +dhcp_bind(struct netif *netif) +{ + u32_t timeout; + struct dhcp *dhcp; + ip_addr_t sn_mask, gw_addr; + LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); + dhcp = netif->dhcp; + LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* temporary DHCP lease? */ + if (dhcp->offered_t1_renew != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); + timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if(timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t1_timeout = (u16_t)timeout; + if (dhcp->t1_timeout == 0) { + dhcp->t1_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); + } + /* set renewal period timer */ + if (dhcp->offered_t2_rebind != 0xffffffffUL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); + timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if(timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t2_timeout = (u16_t)timeout; + if (dhcp->t2_timeout == 0) { + dhcp->t2_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); + } + + /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. modify by ives at 2014.4.22*/ + if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { + dhcp->t1_timeout = 0; + } + + if (dhcp->subnet_mask_given) { + /* copy offered network mask */ + ip_addr_copy(sn_mask, dhcp->offered_sn_mask); + } else { + /* subnet mask not given, choose a safe subnet mask given the network class */ + u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); + if (first_octet <= 127) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000)); + } else if (first_octet >= 192) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00)); + } else { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000)); + } + } + + ip_addr_copy(gw_addr, dhcp->offered_gw_addr); + /* gateway address not given? */ + if (ip_addr_isany(&gw_addr)) { + /* copy network address */ + ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); + /* use first host address on network as gateway */ + ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001)); + } + +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + // wjg:back up old ip/netmask/gw + ip_addr_t ip, mask, gw; + ip = netif->ip_addr; + mask = netif->netmask; + gw = netif->gw; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); + netif_set_ipaddr(netif, &dhcp->offered_ip_addr); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", + ip4_addr_get_u32(&sn_mask))); + netif_set_netmask(netif, &sn_mask); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", + ip4_addr_get_u32(&gw_addr))); + netif_set_gw(netif, &gw_addr); + + /* bring the interface up */ + netif_set_up(netif); + + // wjg: use old ip/mask/gw to check whether ip/mask/gw changed + system_station_got_ip_set(&ip, &mask, &gw); + + /* netif is now bound to DHCP leased address */ + dhcp_set_state(dhcp, DHCP_BOUND); +} + +/** + * Renew an existing DHCP lease at the involved DHCP server. + * + * @param netif network interface which must renew its lease + */ +err_t ICACHE_FLASH_ATTR +dhcp_renew(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); + dhcp_set_state(dhcp, DHCP_RENEWING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)os_strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } + } +#endif /* LWIP_NETIF_HOSTNAME */ + +#if 1 + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); +#endif + +#if 1 + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + /* append DHCP message trailer */ + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); + } + dhcp->tries++; + /* back-off on retries, but to a maximum of 20 seconds */ + msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Rebind with a DHCP server for an existing DHCP lease. + * + * @param netif network interface which must rebind with a DHCP server + */ +static err_t ICACHE_FLASH_ATTR +dhcp_rebind(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); + dhcp_set_state(dhcp, DHCP_REBINDING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)os_strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } + } + } +#endif /* LWIP_NETIF_HOSTNAME */ + +#if 1 + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* broadcast to server */ + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Enter REBOOTING state to verify an existing lease + * + * @param netif network interface which must reboot + */ +static err_t ICACHE_FLASH_ATTR +dhcp_reboot(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); + dhcp_set_state(dhcp, DHCP_REBOOTING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* broadcast to server */ + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * Release a DHCP lease. + * + * @param netif network interface which must release its lease + */ +err_t ICACHE_FLASH_ATTR +dhcp_release(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); + if (dhcp == NULL) { + return ERR_ARG; + } + + /* idle DHCP client */ + dhcp_set_state(dhcp, DHCP_OFF); + /* clean old DHCP offer */ + ip_addr_set_zero(&dhcp->server_ip_addr); + ip_addr_set_zero(&dhcp->offered_ip_addr); + ip_addr_set_zero(&dhcp->offered_sn_mask); + ip_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); + if (result == ERR_OK) { + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); + /* bring the interface down */ + netif_set_down(netif); + /* remove IP address from interface */ + netif_set_ipaddr(netif, IP_ADDR_ANY); + netif_set_gw(netif, IP_ADDR_ANY); + netif_set_netmask(netif, IP_ADDR_ANY); + + return result; +} + +/** + * Remove the DHCP client from the interface. + * + * @param netif The network interface to stop DHCP on + */ +void ICACHE_FLASH_ATTR +dhcp_stop(struct netif *netif) +{ + struct dhcp *dhcp; + LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); + dhcp = netif->dhcp; + /* Remove the flag that says this netif is handled by DHCP. */ + netif->flags &= ~NETIF_FLAG_DHCP; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); + /* netif is DHCP configured? */ + if (dhcp != NULL) { +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + if (dhcp->pcb != NULL) { + udp_remove(dhcp->pcb); + dhcp->pcb = NULL; + } + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); + dhcp_set_state(dhcp, DHCP_OFF); + } +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + */ +static void ICACHE_FLASH_ATTR +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ + if (new_state != dhcp->state) { + dhcp->state = new_state; + dhcp->tries = 0; + dhcp->request_timeout = 0; + } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static void ICACHE_FLASH_ATTR +dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) +{ + LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = option_type; + dhcp->msg_out->options[dhcp->options_out_len++] = option_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static void ICACHE_FLASH_ATTR +dhcp_option_byte(struct dhcp *dhcp, u8_t value) +{ + LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = value; +} + +static void ICACHE_FLASH_ATTR +dhcp_option_short(struct dhcp *dhcp, u16_t value) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); +} + +static void ICACHE_FLASH_ATTR +dhcp_option_long(struct dhcp *dhcp, u32_t value) +{ + LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); +} + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a conitguous piece of memory, and + * use that further on. + * + */ +static err_t ICACHE_FLASH_ATTR +dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) +{ + u8_t *options; + u16_t offset; + u16_t offset_max; + u16_t options_idx; + u16_t options_idx_max; + struct pbuf *q; + int parse_file_as_options = 0; + int parse_sname_as_options = 0; + + /* clear received options */ + dhcp_clear_all_options(dhcp); + /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ + if (p->len < DHCP_SNAME_OFS) { + return ERR_BUF; + } + dhcp->msg_in = (struct dhcp_msg *)p->payload; +#if LWIP_DHCP_BOOTP_FILE + /* clear boot file name */ + dhcp->boot_file_name[0] = 0; +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* parse options */ + + /* start with options field */ + options_idx = DHCP_OPTIONS_OFS; + /* parse options to the end of the received packet */ + options_idx_max = p->tot_len; +again: + q = p; + while((q != NULL) && (options_idx >= q->len)) { + options_idx -= q->len; + options_idx_max -= q->len; + q = q->next; + } + if (q == NULL) { + return ERR_BUF; + } + offset = options_idx; + offset_max = options_idx_max; + options = (u8_t*)q->payload; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { + u8_t op = options[offset]; + u8_t len; + u8_t decode_len = 0; + int decode_idx = -1; + u16_t val_offset = offset + 2; + /* len byte might be in the next pbuf */ + if (offset + 1 < q->len) { + len = options[offset + 1]; + } else { + len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); + } + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + decode_len = len; + switch(op) { + /* case(DHCP_OPTION_END): handled above */ + case(DHCP_OPTION_PAD): + /* special option: no len encoded */ + decode_len = len = 0; + /* will be increased below */ + offset--; + break; + case(DHCP_OPTION_SUBNET_MASK): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; + break; + case(DHCP_OPTION_ROUTER): + decode_len = 4; /* only copy the first given router */ + LWIP_ASSERT("len >= decode_len", len >= decode_len); + decode_idx = DHCP_OPTION_IDX_ROUTER; + break; + case(DHCP_OPTION_DNS_SERVER): + /* special case: there might be more than one server */ + LWIP_ASSERT("len % 4 == 0", len % 4 == 0); + /* limit number of DNS servers */ + decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + LWIP_ASSERT("len >= decode_len", len >= decode_len); + decode_idx = DHCP_OPTION_IDX_DNS_SERVER; + break; + case(DHCP_OPTION_LEASE_TIME): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_LEASE_TIME; + break; + case(DHCP_OPTION_OVERLOAD): + LWIP_ASSERT("len == 1", len == 1); + decode_idx = DHCP_OPTION_IDX_OVERLOAD; + break; + case(DHCP_OPTION_MESSAGE_TYPE): + LWIP_ASSERT("len == 1", len == 1); + decode_idx = DHCP_OPTION_IDX_MSG_TYPE; + break; + case(DHCP_OPTION_SERVER_ID): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_SERVER_ID; + break; + case(DHCP_OPTION_T1): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_T1; + break; + case(DHCP_OPTION_T2): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_T2; + break; + default: + decode_len = 0; + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); + break; + } + offset += len + 2; + if (decode_len > 0) { + u32_t value = 0; + u16_t copy_len; +decode_next: + LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); + LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx)); + copy_len = LWIP_MIN(decode_len, 4); + pbuf_copy_partial(q, &value, copy_len, val_offset); + if (decode_len > 4) { + /* decode more than one u32_t */ + LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0); + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, htonl(value)); + decode_len -= 4; + val_offset += 4; + decode_idx++; + goto decode_next; + } else if (decode_len == 4) { + value = ntohl(value); + } else { + LWIP_ASSERT("invalid decode_len", decode_len == 1); + value = ((u8_t*)&value)[0]; + } + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, value); + } + if (offset >= q->len) { + offset -= q->len; + offset_max -= q->len; + if ((offset < offset_max) && offset_max) { //modify by ives at 2014.4.22 + q = q->next; + LWIP_ASSERT("next pbuf was null", q); + options = (u8_t*)q->payload; + } else { + /* We've run out of bytes, probably no end marker. Don't proceed. */ + break; + } + } + } + /* is this an overloaded message? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { + u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); + dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); + if (overload == DHCP_OVERLOAD_FILE) { + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME) { + parse_sname_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { + parse_sname_as_options = 1; + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); + } +#if LWIP_DHCP_BOOTP_FILE + if (!parse_file_as_options) { + /* only do this for ACK messages */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && + (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) + /* copy bootp file name, don't care for sname (server hostname) */ + pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); + /* make sure the string is really NULL-terminated */ + dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; + } +#endif /* LWIP_DHCP_BOOTP_FILE */ + } + if (parse_file_as_options) { + /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ + parse_file_as_options = 0; + options_idx = DHCP_FILE_OFS; + options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; + goto again; + } else if (parse_sname_as_options) { + parse_sname_as_options = 0; + options_idx = DHCP_SNAME_OFS; + options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; + goto again; + } + return ERR_OK; +} + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void ICACHE_FLASH_ATTR +dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +{ + struct netif *netif = (struct netif *)arg; + struct dhcp *dhcp = netif->dhcp; + struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; + u8_t msg_type; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, + ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); + /* prevent warnings about unused arguments */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); + + if (p->len < DHCP_MIN_REPLY_LEN) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); + goto free_pbuf_and_return; + } + + if (reply_msg->op != DHCP_BOOTREPLY) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); + goto free_pbuf_and_return; + } + /* iterate through hardware address and match against DHCP message */ + for (i = 0; i < netif->hwaddr_len; i++) { + if (netif->hwaddr[i] != reply_msg->chaddr[i]) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", + (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); + goto free_pbuf_and_return; + } + } + /* match transaction ID against what we expected */ + if (ntohl(reply_msg->xid) != dhcp->xid) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); + goto free_pbuf_and_return; + } + /* option fields could be unfold? */ + if (dhcp_parse_reply(dhcp, p) != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("problem unfolding DHCP message - too short on memory?\n")); + goto free_pbuf_and_return; + } + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); + /* obtain pointer to DHCP message type */ + if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); + goto free_pbuf_and_return; + } + + /* read DHCP message type */ + msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); + /* message type is DHCP ACK? */ + if (msg_type == DHCP_ACK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); + /* in requesting state? */ + if (dhcp->state == DHCP_REQUESTING) { + dhcp_handle_ack(netif); +#if DHCP_DOES_ARP_CHECK + /* check if the acknowledged lease address is already in use */ + dhcp_check(netif); +#else + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); +#endif + } + /* already bound to the given lease address? */ + else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { + dhcp_bind(netif); + } + } + /* received a DHCP_NAK in appropriate state? */ + else if ((msg_type == DHCP_NAK) && + ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || + (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); + dhcp_handle_nak(netif); + } + /* received a DHCP_OFFER in DHCP_SELECTING state? */ + else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n")); + dhcp->request_timeout = 0; + /* remember offered lease */ + dhcp_handle_offer(netif); + } +free_pbuf_and_return: + dhcp->msg_in = NULL; + pbuf_free(p); +} + +/** + * Create a DHCP request, fill in common headers + * + * @param netif the netif under DHCP control + * @param dhcp dhcp control struct + * @param message_type message type of the request + */ +static err_t ICACHE_FLASH_ATTR +dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) +{ + u16_t i; +#ifndef DHCP_GLOBAL_XID + /** default global transaction identifier starting value (easy to match + * with a packet analyser). We simply increment for each new request. + * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one + * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ + static u32_t xid = 0xABCD0000; +#else + static u32_t xid; + static u8_t xid_initialised = 0; + if (!xid_initialised) { + xid = DHCP_GLOBAL_XID; + xid_initialised = !xid_initialised; + } +#endif + LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); + LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); + LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); + LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); + dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); + if (dhcp->p_out == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_create_msg(): could not allocate pbuf\n")); + return ERR_MEM; + } + LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", + (dhcp->p_out->len >= sizeof(struct dhcp_msg))); + + /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER modify by ives at 2014.4.22*/ + if (message_type != DHCP_REQUEST) { + /* reuse transaction identifier in retransmissions */ + if (dhcp->tries == 0) { + xid++; + } + dhcp->xid = xid; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, + ("transaction id xid(%"X32_F")\n", xid)); + + dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; + + dhcp->msg_out->op = DHCP_BOOTREQUEST; + /* TODO: make link layer independent */ + dhcp->msg_out->htype = DHCP_HTYPE_ETH; + dhcp->msg_out->hlen = netif->hwaddr_len; + dhcp->msg_out->hops = 0; + dhcp->msg_out->xid = htonl(dhcp->xid); + dhcp->msg_out->secs = 0; + /* we don't need the broadcast flag since we can receive unicast traffic + before being fully configured! */ + dhcp->msg_out->flags = 0; + ip_addr_set_zero(&dhcp->msg_out->ciaddr); + /* set ciaddr to netif->ip_addr based on message_type and state */ + if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || + ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */ + ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) { + ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr); + } + ip_addr_set_zero(&dhcp->msg_out->yiaddr); + ip_addr_set_zero(&dhcp->msg_out->siaddr); + ip_addr_set_zero(&dhcp->msg_out->giaddr); + for (i = 0; i < DHCP_CHADDR_LEN; i++) { + /* copy netif hardware address, pad with zeroes */ + dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/; + } + for (i = 0; i < DHCP_SNAME_LEN; i++) { + dhcp->msg_out->sname[i] = 0; + } + for (i = 0; i < DHCP_FILE_LEN; i++) { + dhcp->msg_out->file[i] = 0; + } + dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); + dhcp->options_out_len = 0; + /* fill options field with an incrementing array (for debugging purposes) */ + for (i = 0; i < DHCP_OPTIONS_LEN; i++) { + dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ + } + /* Add option MESSAGE_TYPE */ + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, message_type); + return ERR_OK; +} + +/** + * Free previously allocated memory used to send a DHCP request. + * + * @param dhcp the dhcp struct to free the request from + */ +static void ICACHE_FLASH_ATTR +dhcp_delete_msg(struct dhcp *dhcp) +{ + LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); + LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); + LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); + if (dhcp->p_out != NULL) { + pbuf_free(dhcp->p_out); + } + dhcp->p_out = NULL; + dhcp->msg_out = NULL; +} + +/** + * Add a DHCP message trailer + * + * Adds the END option to the DHCP message, and if + * necessary, up to three padding bytes. + * + * @param dhcp DHCP state structure + */ +static void ICACHE_FLASH_ATTR +dhcp_option_trailer(struct dhcp *dhcp) +{ + LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); + LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); + LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; + /* packet is too small, or not 4 byte aligned? */ + while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && + (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { + /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ + LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + /* add a fill/padding byte */ + dhcp->msg_out->options[dhcp->options_out_len++] = 0; + } +} + +#endif /* LWIP_DHCP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dns.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dns.c new file mode 100755 index 0000000000..5e75f6d5af --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/dns.c @@ -0,0 +1,988 @@ +/** + * @file + * DNS - host name to IP address resolver. + * + */ + +/** + + * This file implements a DNS host name to IP address resolver. + + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * DNS.C + * + * The lwIP DNS resolver functions are used to lookup a host name and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the dns_lookup() function. + * New hostnames can be resolved using the dns_query() function. + * + * The lwIP version of the resolver also adds a non-blocking version of + * gethostbyname() that will work with a raw API application. This function + * checks for an IP address string first and converts it if it is valid. + * gethostbyname() then does a dns_lookup() to see if the name is + * already in the table. If so, the IP is returned. If not, a query is + * issued and the function returns with a ERR_INPROGRESS status. The app + * using the dns client must then go into a waiting state. + * + * Once a hostname has been resolved (or found to be non-existent), + * the resolver code calls a specified callback function (which + * must be implemented by the module that uses the resolver). + */ + +/*----------------------------------------------------------------------------- + * RFC 1035 - Domain names - implementation and specification + * RFC 2181 - Clarifications to the DNS Specification + *----------------------------------------------------------------------------*/ + +/** @todo: define good default values (rfc compliance) */ +/** @todo: improve answer parsing, more checkings... */ +/** @todo: check RFC1035 - 7.3. Processing responses */ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/dns.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** DNS server IP address */ +#ifndef DNS_SERVER_ADDRESS +#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, 0xDEDE43D0)) /* resolver1.opendns.com(208.67.222.222) */ +#endif + +/** DNS server port address */ +#ifndef DNS_SERVER_PORT +#define DNS_SERVER_PORT 53 +#endif + +/** DNS maximum number of retries when asking for a name, before "timeout". */ +#ifndef DNS_MAX_RETRIES +#define DNS_MAX_RETRIES 4 +#endif + +/** DNS resource record max. TTL (one week as default) */ +#ifndef DNS_MAX_TTL +#define DNS_MAX_TTL 604800 +#endif + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +/* DNS protocol states */ +#define DNS_STATE_UNUSED 0 +#define DNS_STATE_NEW 1 +#define DNS_STATE_ASKING 2 +#define DNS_STATE_DONE 3 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS message header */ +struct dns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u8_t flags1); + PACK_STRUCT_FIELD(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_HDR 12 + +/** DNS query message structure. + No packing needed: only used locally on the stack. */ +struct dns_query { + /* DNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; +}; +#define SIZEOF_DNS_QUERY 4 + +/** DNS answer message structure. + No packing needed: only used locally on the stack. */ +struct dns_answer { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; + u32_t ttl; + u16_t len; +}; +#define SIZEOF_DNS_ANSWER 10 + +/** DNS table entry */ +struct dns_table_entry { + u8_t state; + u8_t numdns; + u8_t tmr; + u8_t retries; + u8_t seqno; + u8_t err; + u32_t ttl; + char name[DNS_MAX_NAME_LENGTH]; + ip_addr_t ipaddr; + /* pointer to callback on DNS query done */ + dns_found_callback found; + void *arg; +}; + +#if DNS_LOCAL_HOSTLIST + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Local host-list. For hostnames in this list, no + * external name resolution is performed */ +static struct local_hostlist_entry *local_hostlist_dynamic; +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE +#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST +#define DNS_LOCAL_HOSTLIST_STORAGE_POST +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ +DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] + DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; + +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +static void dns_init_local(); +#endif /* DNS_LOCAL_HOSTLIST */ + + +/* forward declarations */ +static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); +static void dns_check_entries(void); + +/*----------------------------------------------------------------------------- + * Globales + *----------------------------------------------------------------------------*/ + +/* DNS variables */ +static struct udp_pcb *dns_pcb; +static u8_t dns_seqno; +static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; +static ip_addr_t dns_servers[DNS_MAX_SERVERS]; +/** Contiguous buffer for processing responses */ +//static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)]; +static u8_t* dns_payload; +static u16_t dns_random; +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (DNS_SERVER_ADDRESS). + */ +void ICACHE_FLASH_ATTR +dns_init() +{ + ip_addr_t dnsserver; + +// dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); + + /* initialize default DNS server address */ + DNS_SERVER_ADDRESS(&dnsserver); + + LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); + + /* if dns client not yet initialized... */ + if (dns_pcb == NULL) { + dns_pcb = udp_new(); + + if (dns_pcb != NULL) { + /* initialize DNS table not needed (initialized to zero since it is a + * global variable) */ + LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", + DNS_STATE_UNUSED == 0); + + /* initialize DNS client */ + udp_bind(dns_pcb, IP_ADDR_ANY, 0); + udp_recv(dns_pcb, dns_recv, NULL); + + /* initialize default DNS primary server */ + dns_setserver(0, &dnsserver); + } + } +#if DNS_LOCAL_HOSTLIST + dns_init_local(); +#endif +} + +/** + * Initialize one of the DNS servers. + * + * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS + * @param dnsserver IP address of the DNS server to set + */ +void ICACHE_FLASH_ATTR +dns_setserver(u8_t numdns, ip_addr_t *dnsserver) +{ + if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && + (dnsserver != NULL) && !ip_addr_isany(dnsserver)) { + dns_servers[numdns] = (*dnsserver); + } +} + +/** + * Obtain one of the currently configured DNS server. + * + * @param numdns the index of the DNS server + * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS + * server has not been configured. + */ +ip_addr_t ICACHE_FLASH_ATTR +dns_getserver(u8_t numdns) +{ + if (numdns < DNS_MAX_SERVERS) { + return dns_servers[numdns]; + } else { + return *IP_ADDR_ANY; + } +} + +/** + * The DNS resolver client timer - handle retries and timeouts and should + * be called every DNS_TMR_INTERVAL milliseconds (every second by default). + */ +void ICACHE_FLASH_ATTR +dns_tmr(void) +{ + if (dns_pcb != NULL) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); + dns_check_entries(); + } +} + +#if DNS_LOCAL_HOSTLIST +static void ICACHE_FLASH_ATTR +dns_init_local() +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) + int i; + struct local_hostlist_entry *entry; + /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ + struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; + size_t namelen; + for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { + struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; + LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); + namelen = os_strlen(init_entry->name); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); + if (entry != NULL) { + entry->name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY((char*)entry->name, init_entry->name, namelen); + ((char*)entry->name)[namelen] = 0; + entry->addr = init_entry->addr; + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ +} + +/** + * Scans the local host-list for a hostname. + * + * @param hostname Hostname to look for in the local host-list + * @return The first IP address for the hostname in the local host-list or + * IPADDR_NONE if not found. + */ +static u32_t ICACHE_FLASH_ATTR +dns_lookup_local(const char *hostname) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + while(entry != NULL) { + if(strcmp(entry->name, hostname) == 0) { + return ip4_addr_get_u32(&entry->addr); + } + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + int i; + for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { + if(strcmp(local_hostlist_static[i].name, hostname) == 0) { + return ip4_addr_get_u32(&local_hostlist_static[i].addr); + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return IPADDR_NONE; +} + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Remove all entries from the local host-list for a specific hostname + * and/or IP addess + * + * @param hostname hostname for which entries shall be removed from the local + * host-list + * @param addr address for which entries shall be removed from the local host-list + * @return the number of removed entries + */ +int ICACHE_FLASH_ATTR +dns_local_removehost(const char *hostname, const ip_addr_t *addr) +{ + int removed = 0; + struct local_hostlist_entry *entry = local_hostlist_dynamic; + struct local_hostlist_entry *last_entry = NULL; + while (entry != NULL) { + if (((hostname == NULL) || !strcmp(entry->name, hostname)) && + ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { + struct local_hostlist_entry *free_entry; + if (last_entry != NULL) { + last_entry->next = entry->next; + } else { + local_hostlist_dynamic = entry->next; + } + free_entry = entry; + entry = entry->next; + memp_free(MEMP_LOCALHOSTLIST, free_entry); + removed++; + } else { + last_entry = entry; + entry = entry->next; + } + } + return removed; +} + +/** + * Add a hostname/IP address pair to the local host-list. + * Duplicates are not checked. + * + * @param hostname hostname of the new entry + * @param addr IP address of the new entry + * @return ERR_OK if succeeded or ERR_MEM on memory error + */ +err_t ICACHE_FLASH_ATTR +dns_local_addhost(const char *hostname, const ip_addr_t *addr) +{ + struct local_hostlist_entry *entry; + size_t namelen; + LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); + namelen = os_strlen(hostname); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + if (entry == NULL) { + return ERR_MEM; + } + entry->name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY((char*)entry->name, hostname, namelen); + ((char*)entry->name)[namelen] = 0; + ip_addr_copy(entry->addr, *addr); + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + return ERR_OK; +} +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** + * Look up a hostname in the array of known hostnames. + * + * @note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function dns_enqueue() can be used to send a query + * for a hostname. + * + * @param name the hostname to look up + * @return the hostname's IP address, as u32_t (instead of ip_addr_t to + * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname + * was not found in the cached dns_table. + */ +static u32_t ICACHE_FLASH_ATTR +dns_lookup(const char *name) +{ + u8_t i; +#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) + u32_t addr; +#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ +#if DNS_LOCAL_HOSTLIST + if ((addr = dns_lookup_local(name)) != IPADDR_NONE) { + return addr; + } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN + if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) { + return addr; + } +#endif /* DNS_LOOKUP_LOCAL_EXTERN */ + + /* Walk through name list, return entry if found. If not, return NULL. */ + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + if ((dns_table[i].state == DNS_STATE_DONE) && + (strcmp(name, dns_table[i].name) == 0)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); + ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + return ip4_addr_get_u32(&dns_table[i].ipaddr); + } + } + + return IPADDR_NONE; +} + +#if DNS_DOES_NAME_CHECK +/** + * Compare the "dotted" name "query" with the encoded name "response" + * to make sure an answer from the DNS server matches the current dns_table + * entry (otherwise, answers might arrive late for hostname not on the list + * any more). + * + * @param query hostname (not encoded) from the dns_table + * @param response encoded hostname in the DNS response + * @return 0: names equal; 1: names differ + */ +static u8_t ICACHE_FLASH_ATTR +dns_compare_name(unsigned char *query, unsigned char *response) +{ + unsigned char n; + + do { + n = *response++; + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name */ + break; + } else { + /* Not compressed name */ + while (n > 0) { + if ((*query) != (*response)) { + return 1; + } + ++response; + ++query; + --n; + }; + ++query; + } + } while (*response != 0); + + return 0; +} +#endif /* DNS_DOES_NAME_CHECK */ + +/** + * Walk through a compact encoded DNS name and return the end of the name. + * + * @param query encoded DNS name in the DNS server response + * @return end of the name + */ +static unsigned char * ICACHE_FLASH_ATTR +dns_parse_name(unsigned char *query) +{ + unsigned char n; + + do { + n = *query++; + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name */ + break; + } else { + /* Not compressed name */ + while (n > 0) { + ++query; + --n; + }; + } + } while (*query != 0); + + return query + 1; +} + +/** + * Send a DNS query packet. + * + * @param numdns index of the DNS server in the dns_servers table + * @param name hostname to query + * @param id index of the hostname in dns_table, used as transaction ID in the + * DNS query packet + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t ICACHE_FLASH_ATTR +dns_send(u8_t numdns, const char* name, u8_t id) +{ + err_t err; + struct dns_hdr *hdr; + struct dns_query qry; + struct pbuf *p; + char *query, *nptr; + const char *pHostname; + u8_t n; + dns_random = os_random()>>16; + LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", + (u16_t)(numdns), name)); + LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); + LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns])); + + /* if here, we have either a new query or a retry on a previous query to process */ + p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + + SIZEOF_DNS_QUERY, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); + /* fill dns header */ + hdr = (struct dns_hdr*)p->payload; + os_memset(hdr, 0, SIZEOF_DNS_HDR); + hdr->id = htons(id + dns_random); + hdr->flags1 = DNS_FLAG1_RD; + hdr->numquestions = PP_HTONS(1); + query = (char*)hdr + SIZEOF_DNS_HDR; + pHostname = name; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while(*pHostname != 0); + *query++='\0'; + + /* fill dns query */ + qry.type = PP_HTONS(DNS_RRTYPE_A); + qry.cls = PP_HTONS(DNS_RRCLASS_IN); + SMEMCPY(query, &qry, SIZEOF_DNS_QUERY); + + /* resize pbuf to the exact dns query */ + pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)))); + + /* connect to the server for faster receiving */ + udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); + /* send dns packet */ + err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT); + + /* free pbuf */ + pbuf_free(p); + } else { + err = ERR_MEM; + } + + return err; +} + +/** + * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query. + * Check an entry in the dns_table: + * - send out query for new entries + * - retry old pending entries on timeout (also with different servers) + * - remove completed entries from the table if their TTL has expired + * + * @param i index of the dns_table entry to check + */ +static void ICACHE_FLASH_ATTR +dns_check_entry(u8_t i) +{ + err_t err; + struct dns_table_entry *pEntry = &dns_table[i]; + + LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); + + switch(pEntry->state) { + + case DNS_STATE_NEW: { + /* initialize new entry */ + pEntry->state = DNS_STATE_ASKING; + pEntry->numdns = 0; + pEntry->tmr = 1; + pEntry->retries = 0; + + /* send DNS packet for this entry */ + err = dns_send(pEntry->numdns, pEntry->name, i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + break; + } + + case DNS_STATE_ASKING: { + if (--pEntry->tmr == 0) { + if (++pEntry->retries == DNS_MAX_RETRIES) { + if ((pEntry->numdns+1numdns+1])) { + /* change of server */ + pEntry->numdns++; + pEntry->tmr = 1; + pEntry->retries = 0; + break; + } else { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name)); + /* call specified callback function if provided */ + if (pEntry->found) + (*pEntry->found)(pEntry->name, NULL, pEntry->arg); + /* flush this entry */ + pEntry->state = DNS_STATE_UNUSED; + pEntry->found = NULL; + break; + } + } + + /* wait longer for the next retry */ + pEntry->tmr = pEntry->retries; + + /* send DNS packet for this entry */ + err = dns_send(pEntry->numdns, pEntry->name, i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + } + break; + } + + case DNS_STATE_DONE: { + /* if the time to live is nul */ + if ((pEntry->ttl == 0) || (--pEntry->ttl == 0)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name)); + /* flush this entry */ + pEntry->state = DNS_STATE_UNUSED; + pEntry->found = NULL; + } + break; + } + case DNS_STATE_UNUSED: + /* nothing to do */ + break; + default: + LWIP_ASSERT("unknown dns_table entry state:", 0); + break; + } +} + +/** + * Call dns_check_entry for each entry in dns_table - check all entries. + */ +static void ICACHE_FLASH_ATTR +dns_check_entries(void) +{ + u8_t i; + + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + dns_check_entry(i); + } +} + +/** + * Receive input function for DNS response packets arriving for the dns UDP pcb. + * + * @params see udp.h + */ +static void ICACHE_FLASH_ATTR +dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +{ + u16_t i; + char *pHostname; + struct dns_hdr *hdr; + struct dns_answer ans; + struct dns_table_entry *pEntry; + u16_t nquestions, nanswers; + + u8_t* dns_payload_buffer = (u8_t* )os_zalloc(LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)); + dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + /* is the dns message too big ? */ + if (p->tot_len > DNS_MSG_SIZE) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); + /* free pbuf and return */ + goto memerr; + } + + /* is the dns message big enough ? */ + if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); + /* free pbuf and return */ + goto memerr; + } + + /* copy dns payload inside static buffer for processing */ + if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { + /* The ID in the DNS header should be our entry into the name table. */ + hdr = (struct dns_hdr*)dns_payload; + i = htons(hdr->id); + i = i - dns_random; + if (i < DNS_TABLE_SIZE) { + pEntry = &dns_table[i]; + if(pEntry->state == DNS_STATE_ASKING) { + pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; + + /* We only care about the question(s) and the answers. The authrr + and the extrarr are simply discarded. */ + nquestions = htons(hdr->numquestions); + nanswers = htons(hdr->numanswers); + + /* Check for error. If so, call callback to inform. */ + if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name)); + /* call callback to indicate error, clean up memory and return */ + //goto responseerr; + goto memerr; + } + /* This entry is now completed. */ + pEntry->state = DNS_STATE_DONE; + +#if DNS_DOES_NAME_CHECK + /* Check if the name in the "question" part match with the name in the entry. */ + if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); + /* call callback to indicate error, clean up memory and return */ + goto responseerr; + } +#endif /* DNS_DOES_NAME_CHECK */ + + /* Skip the name in the "question" part */ + pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; + + while (nanswers > 0) { + /* skip answer resource record's host name */ + pHostname = (char *) dns_parse_name((unsigned char *)pHostname); + + /* Check for IP address type and Internet class. Others are discarded. */ + SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); + if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && + (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) { + /* read the answer resource record's TTL, and maximize it if needed */ + pEntry->ttl = ntohl(ans.ttl); + if (pEntry->ttl > DNS_MAX_TTL) { + pEntry->ttl = DNS_MAX_TTL; + } + /* read the IP address after answer resource record's header */ + SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t)); + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); + ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + /* call specified callback function if provided */ + if (pEntry->found) { + (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); + } + if (pEntry->ttl == 0) { + /* RFC 883, page 29: "Zero values are + interpreted to mean that the RR can only be used for the + transaction in progress, and should not be cached." + -> flush this entry now */ + goto flushentry; + } + /* deallocate memory and return */ + goto memerr; + } else { + pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); + } + --nanswers; + } + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name)); + /* call callback to indicate error, clean up memory and return */ + goto responseerr; + } + } + } + + /* deallocate memory and return */ + goto memerr; + +responseerr: + /* ERROR: call specified callback function with NULL as name to indicate an error */ + if (pEntry->found) { + (*pEntry->found)(pEntry->name, NULL, pEntry->arg); + } +flushentry: + /* flush this entry */ + pEntry->state = DNS_STATE_UNUSED; + pEntry->found = NULL; + +memerr: + /* free pbuf */ + pbuf_free(p); + os_free(dns_payload_buffer); + return; +} + +/** + * Queues a new hostname to resolve and sends out a DNS query for that hostname + * + * @param name the hostname that is to be queried + * @param found a callback founction to be called on success, failure or timeout + * @param callback_arg argument to pass to the callback function + * @return @return a err_t return code. + */ +static err_t ICACHE_FLASH_ATTR +dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) +{ + u8_t i; + u8_t lseq, lseqi; + struct dns_table_entry *pEntry = NULL; + size_t namelen; + + /* search an unused entry, or the oldest one */ + lseq = lseqi = 0; + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + pEntry = &dns_table[i]; + /* is it an unused entry ? */ + if (pEntry->state == DNS_STATE_UNUSED) + break; + + /* check if this is the oldest completed entry */ + if (pEntry->state == DNS_STATE_DONE) { + if ((dns_seqno - pEntry->seqno) > lseq) { + lseq = dns_seqno - pEntry->seqno; + lseqi = i; + } + } + } + + /* if we don't have found an unused entry, use the oldest completed one */ + if (i == DNS_TABLE_SIZE) { + if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { + /* no entry can't be used now, table is full */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); + return ERR_MEM; + } else { + /* use the oldest completed one */ + i = lseqi; + pEntry = &dns_table[i]; + } + } + + /* use this entry */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); + + /* fill the entry */ + pEntry->state = DNS_STATE_NEW; + pEntry->seqno = dns_seqno++; + pEntry->found = found; + pEntry->arg = callback_arg; + namelen = LWIP_MIN(os_strlen(name), DNS_MAX_NAME_LENGTH-1); + MEMCPY(pEntry->name, name, namelen); + pEntry->name[namelen] = 0; + + /* force to send query without waiting timer */ + dns_check_entry(i); + + /* dns query is enqueued */ + return ERR_INPROGRESS; +} + +/** + * Resolve a hostname (string) into an IP address. + * NON-BLOCKING callback version for use with raw API!!! + * + * Returns immediately with one of err_t return codes: + * - ERR_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ERR_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ERR_ARG: dns client not initialized or invalid hostname + * + * @param hostname the hostname that is to be queried + * @param addr pointer to a ip_addr_t where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @return a err_t return code. + */ +err_t ICACHE_FLASH_ATTR +dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg) +{ + u32_t ipaddr; + /* not initialized or no valid server yet, or invalid addr pointer + * or invalid hostname or invalid hostname length */ + if ((dns_pcb == NULL) || (addr == NULL) || + (!hostname) || (!hostname[0]) || + (os_strlen(hostname) >= DNS_MAX_NAME_LENGTH)) { + return ERR_ARG; + } + +#if LWIP_HAVE_LOOPIF + if (strcmp(hostname, "localhost")==0) { + ip_addr_set_loopback(addr); + return ERR_OK; + } +#endif /* LWIP_HAVE_LOOPIF */ + + /* host name already in octet notation? set ip addr and return ERR_OK */ + ipaddr = ipaddr_addr(hostname); + if (ipaddr == IPADDR_NONE) { + /* already have this address cached? */ +// ipaddr = dns_lookup(hostname); + } + if (ipaddr != IPADDR_NONE) { + ip4_addr_set_u32(addr, ipaddr); + return ERR_OK; + } + + /* queue query with specified callback */ + return dns_enqueue(hostname, found, callback_arg); +} + +#endif /* LWIP_DNS */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/init.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/init.c new file mode 100755 index 0000000000..aa403f482e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/init.c @@ -0,0 +1,325 @@ +/** + * @file + * Modules initialization + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/init.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/sockets.h" +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp_impl.h" +#include "lwip/snmp_msg.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/timers.h" +#include "netif/etharp.h" + +/* Compile-time sanity checks for configuration errors. + * These can be done independently of LWIP_DEBUG, without penalty. + */ +#ifndef BYTE_ORDER + #error "BYTE_ORDER is not defined, you have to define it in your cc.h" +#endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && ARP_QUEUEING) + #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_UDPLITE) + #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_SNMP) + #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DHCP) + #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_IGMP) + #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_SNMP) + #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DNS) + #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) + #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" +#endif +#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) + #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) + #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" +#endif +//#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) +// #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" +//#endif +//#if (LWIP_TCP && (TCP_WND > 0xffff)) +// #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +//#endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) + #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) + #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" +#endif +//#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) +// #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" +//#endif +#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff)) + #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" +#endif +#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) + #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" +#endif +#if (LWIP_NETIF_API && (NO_SYS==1)) + #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) + #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) + #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" +#endif +#if (!LWIP_NETCONN && LWIP_SOCKET) + #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) + #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) + #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && LWIP_AUTOIP) + #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0)) + #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h" +#endif +#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) + #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) + #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" +#endif +/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)) + #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#endif +#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) + #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" +#endif +#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) + #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" +#endif +#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) + #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" +#endif +#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) + #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" +#endif +#if (TCP_QUEUE_OOSEQ && !LWIP_TCP) + #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" +#endif +#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) + #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" +#endif +#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT + #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on" +#endif +#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) + #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" +#endif +#if LWIP_IGMP && !defined(LWIP_RAND) + #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" +#endif +#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING + #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" +#endif +#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE + #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" +#endif +#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF + #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" +#endif + + +/* Compile-time checks for deprecated options. + */ +#ifdef MEMP_NUM_TCPIP_MSG + #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef MEMP_NUM_API_MSG + #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef TCP_REXMIT_DEBUG + #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef RAW_STATS + #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_QUEUE_FIRST + #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_ALWAYS_INSERT + #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." +#endif + +#ifdef LWIP_DEBUG +static void ICACHE_FLASH_ATTR +lwip_sanity_check(void) +{ + /* Warnings */ +#if LWIP_NETCONN + if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n")); +#endif /* LWIP_NETCONN */ +#if LWIP_TCP + if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n")); + if (TCP_SND_BUF < 2 * TCP_MSS) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n")); + if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); + if (TCP_SNDLOWAT >= TCP_SND_BUF) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n")); + if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n")); + if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); + if (TCP_WND < TCP_MSS) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); +#endif /* LWIP_TCP */ +#if LWIP_SOCKET + /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ + if (SO_ACCEPTCONN != SOF_ACCEPTCONN) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n")); + if (SO_REUSEADDR != SOF_REUSEADDR) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n")); + if (SO_KEEPALIVE != SOF_KEEPALIVE) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n")); + if (SO_BROADCAST != SOF_BROADCAST) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n")); + if (SO_LINGER != SOF_LINGER) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n")); +#endif /* LWIP_SOCKET */ +} +#else /* LWIP_DEBUG */ +#define lwip_sanity_check() +#endif /* LWIP_DEBUG */ + +/** + * Perform Sanity check of user-configurable values, and initialize all modules. + */ +void +lwip_init(void) +{ + MEMP_NUM_TCP_PCB = 5; + TCP_WND = (4 * TCP_MSS); + TCP_MAXRTX = 12; + TCP_SYNMAXRTX = 6; + + /* Sanity check user-configurable values */ + lwip_sanity_check(); + + /* Modules initialization */ + stats_init(); +#if !NO_SYS + sys_init(); +#endif /* !NO_SYS */ +#if 0 + mem_init(&_bss_end); +#endif + memp_init(); + + pbuf_init(); + + netif_init(); + +#if LWIP_SOCKET + lwip_socket_init(); +#endif /* LWIP_SOCKET */ + ip_init(); + +#if LWIP_ARP + etharp_init(); + +#endif /* LWIP_ARP */ +#if LWIP_RAW + raw_init(); + +#endif /* LWIP_RAW */ +#if LWIP_UDP + udp_init(); + +#endif /* LWIP_UDP */ +#if LWIP_TCP + tcp_init(); + +#endif /* LWIP_TCP */ +#if LWIP_SNMP + snmp_init(); + +#endif /* LWIP_SNMP */ +#if LWIP_AUTOIP + autoip_init(); + +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP + igmp_init(); + +#endif /* LWIP_IGMP */ +#if LWIP_DNS + dns_init(); + +#endif /* LWIP_DNS */ + +#if LWIP_TIMERS + sys_timeouts_init(); +#endif /* LWIP_TIMERS */ +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/Makefile new file mode 100755 index 0000000000..2d818fe81a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblwipipv4.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/autoip.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/autoip.c new file mode 100755 index 0000000000..cdba69d6bf --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/autoip.c @@ -0,0 +1,536 @@ +/** + * @file + * AutoIP Automatic LinkLocal IP Configuration + * + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +/******************************************************************************* + * USAGE: + * + * define LWIP_AUTOIP 1 in your lwipopts.h + * + * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): + * - First, call autoip_init(). + * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, + * that should be defined in autoip.h. + * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. + * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + * + * Without DHCP: + * - Call autoip_start() after netif_add(). + * + * With DHCP: + * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. + * - Configure your DHCP Client. + * + */ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#include +#include + +/* 169.254.0.0 */ +#define AUTOIP_NET 0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) + + +/** Pseudo random macro based on netif informations. + * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ +#ifndef LWIP_AUTOIP_RAND +#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ + ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ + ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ + ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ + (netif->autoip?netif->autoip->tried_llipaddr:0)) +#endif /* LWIP_AUTOIP_RAND */ + +/** + * Macro that generates the initial IP address to be tried by AUTOIP. + * If you want to override this, define it to something else in lwipopts.h. + */ +#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR +#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ + htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ + ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) +#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ + +/* static functions */ +static void autoip_handle_arp_conflict(struct netif *netif); + +/* creates a pseudo random LL IP-Address for a network interface */ +static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr); + +/* sends an ARP probe */ +static err_t autoip_arp_probe(struct netif *netif); + +/* sends an ARP announce */ +static err_t autoip_arp_announce(struct netif *netif); + +/* configure interface for use with current LL IP-Address */ +static err_t autoip_bind(struct netif *netif); + +/* start sending probes for llipaddr */ +static void autoip_start_probing(struct netif *netif); + +/** + * Initialize this module + */ +void +autoip_init(void) +{ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n")); +} + +/** Set a statically allocated struct autoip to work with. + * Using this prevents autoip_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct autoip + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void +autoip_set_struct(struct netif *netif, struct autoip *autoip) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("autoip != NULL", autoip != NULL); + LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); + + /* clear data structure */ + os_memset(autoip, 0, sizeof(struct autoip)); + /* autoip->state = AUTOIP_STATE_OFF; */ + netif->autoip = autoip; +} + +/** Restart AutoIP client and check the next address (conflict detected) + * + * @param netif The netif under AutoIP control + */ +static void +autoip_restart(struct netif *netif) +{ + netif->autoip->tried_llipaddr++; + autoip_start(netif); +} + +/** + * Handle a IP address conflict after an ARP conflict detection + */ +static void +autoip_handle_arp_conflict(struct netif *netif) +{ + /* Somehow detect if we are defending or retreating */ + unsigned char defend = 1; /* tbd */ + + if(defend) { + if(netif->autoip->lastconflict > 0) { + /* retreat, there was a conflicting ARP in the last + * DEFEND_INTERVAL seconds + */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + + /* TODO: close all TCP sessions */ + autoip_restart(netif); + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); + autoip_arp_announce(netif); + netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); + /* TODO: close all TCP sessions */ + autoip_restart(netif); + } +} + +/** + * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * + * @param netif network interface on which create the IP-Address + * @param ipaddr ip address to initialize + */ +static void +autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr) +{ + /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * compliant to RFC 3927 Section 2.1 + * We have 254 * 256 possibilities */ + + u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); + addr += netif->autoip->tried_llipaddr; + addr = AUTOIP_NET | (addr & 0xffff); + /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ + + if (addr < AUTOIP_RANGE_START) { + addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + if (addr > AUTOIP_RANGE_END) { + addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && + (addr <= AUTOIP_RANGE_END)); + ip4_addr_set_u32(ipaddr, htonl(addr)); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), + ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); +} + +/** + * Sends an ARP probe from a network interface + * + * @param netif network interface used to send the probe + */ +static err_t +autoip_arp_probe(struct netif *netif) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, + (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero, + &netif->autoip->llipaddr, ARP_REQUEST); +} + +/** + * Sends an ARP announce from a network interface + * + * @param netif network interface used to send the announce + */ +static err_t +autoip_arp_announce(struct netif *netif) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, + (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, + &netif->autoip->llipaddr, ARP_REQUEST); +} + +/** + * Configure interface for use with current LL IP-Address + * + * @param netif network interface to configure with current LL IP-Address + */ +static err_t +autoip_bind(struct netif *netif) +{ + struct autoip *autoip = netif->autoip; + ip_addr_t sn_mask, gw_addr; + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + + IP4_ADDR(&sn_mask, 255, 255, 0, 0); + IP4_ADDR(&gw_addr, 0, 0, 0, 0); + + netif_set_ipaddr(netif, &autoip->llipaddr); + netif_set_netmask(netif, &sn_mask); + netif_set_gw(netif, &gw_addr); + + /* bring the interface up */ + netif_set_up(netif); + + return ERR_OK; +} + +/** + * Start AutoIP client + * + * @param netif network interface on which start the AutoIP client + */ +err_t +autoip_start(struct netif *netif) +{ + struct autoip *autoip = netif->autoip; + err_t result = ERR_OK; + + if(netif_is_up(netif)) { + netif_set_down(netif); + } + + /* Set IP-Address, Netmask and Gateway to 0 to make sure that + * ARP Packets are formed correctly + */ + ip_addr_set_zero(&netif->ip_addr); + ip_addr_set_zero(&netif->netmask); + ip_addr_set_zero(&netif->gw); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + if(autoip == NULL) { + /* no AutoIP client attached yet? */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): starting new AUTOIP client\n")); + autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); + if(autoip == NULL) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): could not allocate autoip\n")); + return ERR_MEM; + } + os_memset(autoip, 0, sizeof(struct autoip)); + /* store this AutoIP client in the netif */ + netif->autoip = autoip; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); + } else { + autoip->state = AUTOIP_STATE_OFF; + autoip->ttw = 0; + autoip->sent_num = 0; + ip_addr_set_zero(&autoip->llipaddr); + autoip->lastconflict = 0; + } + + autoip_create_addr(netif, &(autoip->llipaddr)); + autoip_start_probing(netif); + + return result; +} + +static void +autoip_start_probing(struct netif *netif) +{ + struct autoip *autoip = netif->autoip; + + autoip->state = AUTOIP_STATE_PROBING; + autoip->sent_num = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); + + /* time to wait to first probe, this is randomly + * choosen out of 0 to PROBE_WAIT seconds. + * compliant to RFC 3927 Section 2.2.1 + */ + autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); + + /* + * if we tried more then MAX_CONFLICTS we must limit our rate for + * accquiring and probing address + * compliant to RFC 3927 Section 2.2.1 + */ + if(autoip->tried_llipaddr > MAX_CONFLICTS) { + autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } +} + +/** + * Handle a possible change in the network configuration. + * + * If there is an AutoIP address configured, take the interface down + * and begin probing with the same address. + */ +void +autoip_network_changed(struct netif *netif) +{ + if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) { + netif_set_down(netif); + autoip_start_probing(netif); + } +} + +/** + * Stop AutoIP client + * + * @param netif network interface on which stop the AutoIP client + */ +err_t +autoip_stop(struct netif *netif) +{ + netif->autoip->state = AUTOIP_STATE_OFF; + netif_set_down(netif); + return ERR_OK; +} + +/** + * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds + */ +void +autoip_tmr() +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + /* only act on AutoIP configured interfaces */ + if (netif->autoip != NULL) { + if(netif->autoip->lastconflict > 0) { + netif->autoip->lastconflict--; + } + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", + (u16_t)(netif->autoip->state), netif->autoip->ttw)); + + switch(netif->autoip->state) { + case AUTOIP_STATE_PROBING: + if(netif->autoip->ttw > 0) { + netif->autoip->ttw--; + } else { + if(netif->autoip->sent_num >= PROBE_NUM) { + netif->autoip->state = AUTOIP_STATE_ANNOUNCING; + netif->autoip->sent_num = 0; + netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); + } else { + autoip_arp_probe(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_tmr() PROBING Sent Probe\n")); + netif->autoip->sent_num++; + /* calculate time to wait to next probe */ + netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % + ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + + PROBE_MIN * AUTOIP_TICKS_PER_SECOND); + } + } + break; + + case AUTOIP_STATE_ANNOUNCING: + if(netif->autoip->ttw > 0) { + netif->autoip->ttw--; + } else { + if(netif->autoip->sent_num == 0) { + /* We are here the first time, so we waited ANNOUNCE_WAIT seconds + * Now we can bind to an IP address and use it. + * + * autoip_bind calls netif_set_up. This triggers a gratuitous ARP + * which counts as an announcement. + */ + autoip_bind(netif); + } else { + autoip_arp_announce(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_tmr() ANNOUNCING Sent Announce\n")); + } + netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; + netif->autoip->sent_num++; + + if(netif->autoip->sent_num >= ANNOUNCE_NUM) { + netif->autoip->state = AUTOIP_STATE_BOUND; + netif->autoip->sent_num = 0; + netif->autoip->ttw = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); + } + } + break; + } + } + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * Handles every incoming ARP Packet, called by etharp_arp_input. + * + * @param netif network interface to use for autoip processing + * @param hdr Incoming ARP packet + */ +void +autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); + if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { + /* when ip.src == llipaddr && hw.src != netif->hwaddr + * + * when probing ip.dst == llipaddr && hw.src != netif->hwaddr + * we have a conflict and must solve it + */ + ip_addr_t sipaddr, dipaddr; + struct eth_addr netifaddr; + ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); + + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). + */ + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); + + if ((netif->autoip->state == AUTOIP_STATE_PROBING) || + ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && + (netif->autoip->sent_num == 0))) { + /* RFC 3927 Section 2.2.1: + * from beginning to after ANNOUNCE_WAIT + * seconds we have a conflict if + * ip.src == llipaddr OR + * ip.dst == llipaddr && hw.src != own hwaddr + */ + if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || + (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Probe Conflict detected\n")); + autoip_restart(netif); + } + } else { + /* RFC 3927 Section 2.5: + * in any state we have a conflict if + * ip.src == llipaddr && hw.src != own hwaddr + */ + if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); + autoip_handle_arp_conflict(netif); + } + } + } +} + +#endif /* LWIP_AUTOIP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/icmp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/icmp.c new file mode 100755 index 0000000000..421d50d6a4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/icmp.c @@ -0,0 +1,354 @@ +/** + * @file + * ICMP - Internet Control Message Protocol + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwipopts.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include + +/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be + * used to modify and send a response packet (and to 1 if this is not the case, + * e.g. when link header is stripped of when receiving) */ +#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + +/* The amount of data from the original packet to return in a dest-unreachable */ +#define ICMP_DEST_UNREACH_DATASIZE 8 + +static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); + +/** + * Processes ICMP input packets, called from ip_input(). + * + * Currently only processes icmp echo requests and sends + * out the echo response. + * + * @param p the icmp echo request packet, p->payload pointing to the ip header + * @param inp the netif on which this packet was received + */ +void +icmp_input(struct pbuf *p, struct netif *inp) +{ + u8_t type; +#ifdef LWIP_DEBUG + u8_t code; +#endif /* LWIP_DEBUG */ + struct icmp_echo_hdr *iecho; + struct ip_hdr *iphdr; + s16_t hlen; + + ICMP_STATS_INC(icmp.recv); + snmp_inc_icmpinmsgs(); + + + iphdr = (struct ip_hdr *)p->payload; + hlen = IPH_HL(iphdr) * 4; + if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); + goto lenerr; + } + + type = *((u8_t *)p->payload); +#ifdef LWIP_DEBUG + code = *(((u8_t *)p->payload)+1); +#endif /* LWIP_DEBUG */ + switch (type) { + case ICMP_ER: + /* This is OK, echo reply might have been parsed by a raw PCB + (as obviously, an echo request has been sent, too). */ + break; +#if ESP_SYSTEM_APP /* by LiuHan: change the current MTU on the interface */ + case ICMP_DUR: + { + u16_t next_mtu = 0; + next_mtu = *(u8_t *)((u8_t *)p->payload + 6); + next_mtu <<= 8; + next_mtu |= *(u8_t *)((u8_t *)p->payload + 7); + if (next_mtu != 0 && next_mtu != inp->mtu){ + //ets_printf("Match the MTU.\n"); + inp->mtu = next_mtu; + } else { + //ets_printf("Receive the MTU %d\n", next_mtu); + } + } + break; +#endif + case ICMP_ECHO: +#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING + { + int accepted = 1; +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip_addr_ismulticast(¤t_iphdr_dest)) { + accepted = 0; + } +#endif /* LWIP_MULTICAST_PING */ +#if !LWIP_BROADCAST_PING + /* broadcast destination address? */ + if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { + accepted = 0; + } +#endif /* LWIP_BROADCAST_PING */ + /* broadcast or multicast destination address not acceptd? */ + if (!accepted) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); + ICMP_STATS_INC(icmp.err); + pbuf_free(p); + return; + } + } +#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + if (p->tot_len < sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + goto lenerr; + } + if (inet_chksum_pbuf(p) != 0) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.chkerr); + snmp_inc_icmpinerrors(); + return; + } +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { + /* p is not big enough to contain link headers + * allocate a new one and copy p into it + */ + struct pbuf *r; + /* switch p->payload to ip header */ + if (pbuf_header(p, hlen)) { + LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); + goto memerr; + } + /* allocate new packet buffer with space for link headers */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); + goto memerr; + } + LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", + (r->len >= hlen + sizeof(struct icmp_echo_hdr))); + /* copy the whole packet including ip header */ + if (pbuf_copy(r, p) != ERR_OK) { + LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); + goto memerr; + } + iphdr = (struct ip_hdr *)r->payload; + /* switch r->payload back to icmp header */ + if (pbuf_header(r, -hlen)) { + LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); + goto memerr; + } + /* free the original p */ + pbuf_free(p); + /* we now have an identical copy of p that has room for link headers */ + p = r; + } else { + /* restore p->payload to point to icmp header */ + if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { + LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); + goto memerr; + } + } +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + /* At this point, all checks are OK. */ + /* We generate an answer by switching the dest and src ip addresses, + * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ + iecho = (struct icmp_echo_hdr *)p->payload; + ip_addr_copy(iphdr->src, *ip_current_dest_addr()); + ip_addr_copy(iphdr->dest, *ip_current_src_addr()); + ICMPH_TYPE_SET(iecho, ICMP_ER); + /* adjust the checksum */ + if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; + } else { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8); + } + + /* Set the correct TTL and recalculate the header checksum. */ + IPH_TTL_SET(iphdr, ICMP_TTL); + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); +#endif /* CHECKSUM_GEN_IP */ + + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of echo replies attempted to send */ + snmp_inc_icmpoutechoreps(); + + if(pbuf_header(p, hlen)) { + LWIP_ASSERT("Can't move over header in packet", 0); + } else { + err_t ret; + /* send an ICMP packet, src addr is the dest addr of the curren packet */ + ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, + ICMP_TTL, 0, IP_PROTO_ICMP, inp); + if (ret != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); + } + } + break; + default: + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", + (s16_t)type, (s16_t)code)); + ICMP_STATS_INC(icmp.proterr); + ICMP_STATS_INC(icmp.drop); + } + pbuf_free(p); + return; +lenerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + snmp_inc_icmpinerrors(); + return; +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +memerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.err); + snmp_inc_icmpinerrors(); + return; +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ +} + +/** + * Send an icmp 'destination unreachable' packet, called from ip_input() if + * the transport layer protocol is unknown and from udp_input() if the local + * port is not bound. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'unreachable' packet + */ +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ + icmp_send_response(p, ICMP_DUR, t); +} + +#if IP_FORWARD || IP_REASSEMBLY +/** + * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. + * + * @param p the input packet for which the 'time exceeded' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'time exceeded' packet + */ +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ + icmp_send_response(p, ICMP_TE, t); +} + +#endif /* IP_FORWARD || IP_REASSEMBLY */ + +/** + * Send an icmp packet in response to an incoming packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param type Type of the ICMP header + * @param code Code of the ICMP header + */ +static void ICACHE_FLASH_ATTR +icmp_send_response(struct pbuf *p, u8_t type, u8_t code) +{ + struct pbuf *q; + struct ip_hdr *iphdr; + /* we can use the echo header here */ + struct icmp_echo_hdr *icmphdr; + ip_addr_t iphdr_src; + + /* ICMP header + IP header + 8 bytes of data */ + //Ϊ²î´í±¨ÎÄÉêÇëpbuf¿Õ¼ä£¬pbufÖÐÔ¤ÁôIPÊײ¿ºÍÒÔÌ«ÍøÊײ¿¿Õ¼ä£¬pbufÊý¾ÝÇø + //³¤¶È=²î´í±¨ÎÄÊײ¿+²î´í±¨ÎÄÊý¾Ý³¤¶È(IPÊײ¿³¤¶È+8) + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, + PBUF_RAM); + if (q == NULL) {//ʧ°Ü£¬·µ»Ø + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp message", + (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); + + iphdr = (struct ip_hdr *)p->payload;//Ö¸ÏòÒýÆð²î´íµÄIPÊý¾Ý°üÊײ¿ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); + LWIP_DEBUGF(ICMP_DEBUG, (" to ")); + ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); + LWIP_DEBUGF(ICMP_DEBUG, ("\n")); + + icmphdr = (struct icmp_echo_hdr *)q->payload;//Ö¸Ïò²î´í±¨ÎÄÊײ¿ + icmphdr->type = type;//ÌîдÀàÐÍ×ֶΠ+ icmphdr->code = code;//Ìîд´úÂë×ֶΠ+ icmphdr->id = 0;//¶ÔÓÚÄ¿µÄ²»¿É´ïºÍÊý¾Ý±¨³¬Ê± + icmphdr->seqno = 0;//±¨ÎÄ£¬Êײ¿Ê£ÓàµÄ4¸ö×Ö½Ú¶¼Îª0 + + /* copy fields from original packet ½«ÒýÆð²î´íµÄIPÊý¾Ý±¨µÄIPÊײ¿+8×Ö½ÚÊý¾Ý¿½±´µ½²î´í±¨ÎÄÊý¾ÝÇø*/ + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); + + /* calculate checksum */ + icmphdr->chksum = 0;//±¨ÎÄУÑéºÍ×Ö¶ÎÇå0 + icmphdr->chksum = inet_chksum(icmphdr, q->len);//¼ÆËãÌîдУÑéºÍ + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of destination unreachable messages attempted to send */ + snmp_inc_icmpouttimeexcds(); + ip_addr_copy(iphdr_src, iphdr->src); + ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);//µ÷ÓÃIP²ãº¯ÊýÊä³öICMP±¨ÎÄ + pbuf_free(q); +} + +#endif /* LWIP_ICMP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/igmp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/igmp.c new file mode 100755 index 0000000000..b41bfad24f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/igmp.c @@ -0,0 +1,845 @@ +/** + * @file + * IGMP - Internet Group Management Protocol + * + */ + +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +/*------------------------------------------------------------- +Note 1) +Although the rfc requires V1 AND V2 capability +we will only support v2 since now V1 is very old (August 1989) +V1 can be added if required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 2) +A query for a specific group address (as opposed to ALLHOSTS) +has now been implemented as I am unsure if it is required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 3) +The router alert rfc 2113 is implemented in outgoing packets +but not checked rigorously incoming +------------------------------------------------------------- +Steve Reynolds +------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * RFC 988 - Host extensions for IP multicasting - V0 + * RFC 1054 - Host extensions for IP multicasting - + * RFC 1112 - Host extensions for IP multicasting - V1 + * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) + * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 + * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ + * RFC 2113 - IP Router Alert Option - + *----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/igmp.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/stats.h" + +#include "string.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +//#define DYC_IGMP_DEBUG +#ifdef DYC_IGMP_DEBUG +#define IGMP_LOG os_printf +#else +#define IGMP_LOG //os_printf +#endif + +/* + * IGMP constants + */ +#define IGMP_TTL 1 +#define IGMP_MINLEN 8 +#define ROUTER_ALERT 0x9404 +#define ROUTER_ALERTLEN 4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY 0x11 /* Membership query */ +#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ + +/* Group membership states */ +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 + +/** + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FIELD(u8_t igmp_msgtype); + PACK_STRUCT_FIELD(u8_t igmp_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_checksum); + PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +static err_t igmp_remove_group(struct igmp_group *group)ICACHE_FLASH_ATTR; +static void igmp_timeout( struct igmp_group *group)ICACHE_FLASH_ATTR; +static void igmp_start_timer(struct igmp_group *group, u8_t max_time)ICACHE_FLASH_ATTR; +static void igmp_stop_timer(struct igmp_group *group)ICACHE_FLASH_ATTR; +static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp)ICACHE_FLASH_ATTR; +static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)ICACHE_FLASH_ATTR; +static void igmp_send(struct igmp_group *group, u8_t type)ICACHE_FLASH_ATTR; + + +static struct igmp_group* igmp_group_list = NULL; +static ip_addr_t allsystems; +static ip_addr_t allrouters; + + +/** + * Initialize the IGMP module + */ +void +igmp_init(void) +{ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); + + IP4_ADDR(&allsystems, 224, 0, 0, 1); + IP4_ADDR(&allrouters, 224, 0, 0, 2); +} + +//#ifdef LWIP_DEBUG +#ifdef DYC_IGMP_DEBUG +/** + * Dump global IGMP groups list + */ +void +igmp_dump_group_list() +{ + struct igmp_group *group = igmp_group_list; + IGMP_LOG("igmp_dump:\n"); + + while (group != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); + ip_addr_debug_print(IGMP_DEBUG, &group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); + + if(group!=NULL) + IGMP_LOG("group:%p,netif:%p\n",group,group->netif); + + group = group->next; + } + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + IGMP_LOG("\n"); +} +#else +#define igmp_dump_group_list() +#endif /* LWIP_DEBUG */ + +/** + * Start IGMP processing on interface + * + * @param netif network interface on which start IGMP processing + */ +err_t +igmp_start(struct netif *netif) +{ + struct igmp_group* group; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); + + group = igmp_lookup_group(netif, &allsystems); + + if (group != NULL) { + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->use++; + + /* Allow the igmp messages at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); + ip_addr_debug_print(IGMP_DEBUG, &allsystems); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); + } + + return ERR_OK; + } + + return ERR_MEM; +} + +/** + * Stop IGMP processing on interface + * + * @param netif network interface on which stop IGMP processing + */ +err_t +igmp_stop(struct netif *netif) +{ + struct igmp_group *group = igmp_group_list; + struct igmp_group *prev = NULL; + struct igmp_group *next; + + /* look for groups joined on this interface further down the list */ + while (group != NULL) { + next = group->next; + /* is it a group joined on this interface? */ + if (group->netif == netif) { + + IGMP_LOG("stop igmp:%p,%p,",group,group->netif); + + /* is it the first group of the list? */ + if (group == igmp_group_list) { + igmp_group_list = next; + } + /* is there a "previous" group defined? */ + if (prev != NULL) { + prev->next = next; + } + /* disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); + ip_addr_debug_print(IGMP_DEBUG, &group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); + } + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + +igmp_dump_group_list(); + + } else { + /* change the "previous" */ + prev = group; + } + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report IGMP memberships for this interface + * + * @param netif network interface on which report IGMP memberships + */ +void +igmp_report_groups(struct netif *netif) +{ + struct igmp_group *group = igmp_group_list; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); + + while (group != NULL) { + if (group->netif == netif) { + igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + } + group = group->next; + } +} + +/** + * Search for a group in the global igmp_group_list + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search for + * @return a struct igmp_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct igmp_group * +igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) +{ + struct igmp_group *group = igmp_group_list; + + while (group != NULL) { + if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { + return group; + } + group = group->next; + } + + /* to be clearer, we return NULL here instead of + * 'group' (which is also NULL at this point). + */ + return NULL; +} + +/** + * Search for a specific igmp group and create a new one if not found- + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search + * @return a struct igmp_group*, + * NULL on memory error. + */ +struct igmp_group * +igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) +{ + struct igmp_group *group = igmp_group_list; + + /* Search if the group already exists */ + group = igmp_lookfor_group(ifp, addr); + if (group != NULL) { + /* Group already exists. */ + return group; + } + + /* Group doesn't exist yet, create a new one */ + group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); + if (group != NULL) { + group->netif = ifp; + ip_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = IGMP_GROUP_NON_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = igmp_group_list; + + igmp_group_list = group; + } + IGMP_LOG("add igmp:%p,%p,",group,group->netif); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); + ip_addr_debug_print(IGMP_DEBUG, addr); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); + igmp_dump_group_list(); + return group; +} + +/** + * Remove a group in the global igmp_group_list + * + * @param group the group to remove from the global igmp_group_list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +igmp_remove_group(struct igmp_group *group) +{ + err_t err = ERR_OK; + IGMP_LOG("rmv igmp:%p,%p,",group,group->netif); + /* Is it the first group? */ + if (igmp_group_list == group) { + igmp_group_list = group->next; + } else { + /* look for group further down the list */ + struct igmp_group *tmpGroup; + for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not found in the global igmp_group_list */ + if (tmpGroup == NULL) + err = ERR_ARG; + } + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + +igmp_dump_group_list(); + return err; +} + +/** + * Called from ip_input() if a new IGMP packet is received. + * + * @param p received igmp packet, p->payload pointing to the ip header + * @param inp network interface on which the packet was received + * @param dest destination ip address of the igmp packet + */ +void +igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) +{ + struct ip_hdr * iphdr; + struct igmp_msg* igmp; + struct igmp_group* group; + struct igmp_group* groupref; + + IGMP_STATS_INC(igmp.recv); + + /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ + iphdr = (struct ip_hdr *)p->payload; + if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { + pbuf_free(p); + IGMP_STATS_INC(igmp.lenerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); + return; + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); + ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); + LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); + ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); + + /* Now calculate and check the checksum */ + igmp = (struct igmp_msg *)p->payload; + if (inet_chksum(igmp, p->len)) { + pbuf_free(p); + IGMP_STATS_INC(igmp.chkerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); + return; + } + + /* Packet is ok so find an existing group */ + group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ + + /* If group can be found or create... */ + if (!group) { + pbuf_free(p); + IGMP_STATS_INC(igmp.drop); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); + return; + } + + /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ + switch (igmp->igmp_msgtype) { + case IGMP_MEMB_QUERY: { + /* IGMP_MEMB_QUERY to the "all systems" address ? */ + if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { + /* THIS IS THE GENERAL QUERY */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + + if (igmp->igmp_maxresp == 0) { + IGMP_STATS_INC(igmp.rx_v1); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); + igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; + } else { + IGMP_STATS_INC(igmp.rx_general); + } + + groupref = igmp_group_list; + while (groupref) { + /* Do not send messages on the all systems group address! */ + if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { + igmp_delaying_member(groupref, igmp->igmp_maxresp); + } + groupref = groupref->next; + } + } else { + /* IGMP_MEMB_QUERY to a specific group ? */ + if (!ip_addr_isany(&igmp->igmp_group_address)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); + ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); + if (ip_addr_cmp(dest, &allsystems)) { + ip_addr_t groupaddr; + LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + /* we first need to re-look for the group since we used dest last time */ + ip_addr_copy(groupaddr, igmp->igmp_group_address); + group = igmp_lookfor_group(inp, &groupaddr); + } else { + LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + } + + if (group != NULL) { + IGMP_STATS_INC(igmp.rx_group); + igmp_delaying_member(group, igmp->igmp_maxresp); + } else { + IGMP_STATS_INC(igmp.drop); + } + } else { + IGMP_STATS_INC(igmp.proterr); + } + } + break; + } + case IGMP_V2_MEMB_REPORT: { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); + IGMP_STATS_INC(igmp.rx_report); + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { + /* This is on a specific group we have already looked up */ + group->timer = 0; /* stopped */ + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + break; + } + default: { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", + igmp->igmp_msgtype, group->group_state, &group, group->netif)); + IGMP_STATS_INC(igmp.proterr); + break; + } + } + + pbuf_free(p); + return; +} + +/** + * Join a group on one network interface. + * + * @param ifaddr ip address of the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct igmp_group *group; + struct netif *netif; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we join this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { + /* find group or create a new one if not found */ + group = igmp_lookup_group(netif, groupaddr); + + if (group != NULL) { + /* This should create a new group, check the state to make sure */ + if (group->group_state != IGMP_GROUP_NON_MEMBER) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); + } else { + /* OK - it was new group */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If first use of the group, allow the group at the MAC level */ + if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); + } + + IGMP_STATS_INC(igmp.tx_join); + igmp_send(group, IGMP_V2_MEMB_REPORT); + + igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + + /* Need to work out where this timer comes from */ + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } + /* Increment group use */ + group->use++; + /* Join on this interface */ + err = ERR_OK; + } else { + /* Return an error even if some network interfaces are joined */ + /** @todo undo any other netif already joined */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); + return ERR_MEM; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * Leave a group on one network interface. + * + * @param ifaddr ip address of the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct igmp_group *group; + struct netif *netif; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we leave this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { + /* find group */ + group = igmp_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Only send a leave if the flag is set according to the state diagram */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If there is no other use of the group */ + if (group->use <= 1) { + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); + IGMP_STATS_INC(igmp.tx_leave); + igmp_send(group, IGMP_LEAVE_GROUP); + } + + /* Disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); + netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* Free the group */ + igmp_remove_group(group); + } else { + /* Decrement group use */ + group->use--; + } + /* Leave on this interface */ + err = ERR_OK; + } else { + /* It's not a fatal error on "leavegroup" */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * The igmp timer function (both for NO_SYS=1 and =0) + * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). + */ +void +igmp_tmr(void) +{ + struct igmp_group *group = igmp_group_list; + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + igmp_timeout(group); + } + } + group = group->next; + } +} + +/** + * Called if a timeout for one group is reached. + * Sends a report for this group. + * + * @param group an igmp_group for which a timeout is reached + */ +static void +igmp_timeout(struct igmp_group *group) +{ + /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); + ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); + + IGMP_STATS_INC(igmp.tx_report); + igmp_send(group, IGMP_V2_MEMB_REPORT); + } +} + +/** + * Start a timer for an igmp group + * + * @param group the igmp_group for which to start a timer + * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with + * every call to igmp_tmr()) + */ +static void +igmp_start_timer(struct igmp_group *group, u8_t max_time) +{ + /* ensure the input value is > 0 */ + if (max_time == 0) { + max_time = 1; + } + /* ensure the random value is > 0 */ +if(max_time == 1) + group->timer = 1; +else + group->timer = (LWIP_RAND() % (max_time - 1)) + 1; +} + +/** + * Stop a timer for an igmp_group + * + * @param group the igmp_group for which to stop the timer + */ +static void +igmp_stop_timer(struct igmp_group *group) +{ + group->timer = 0; +} + +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +static void +igmp_delaying_member(struct igmp_group *group, u8_t maxresp) +{ + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + igmp_start_timer(group, maxresp); + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } +} + + +/** + * Sends an IP packet on a network interface. This function constructs the IP header + * and calculates the IP header checksum. If the source IP address is NULL, + * the IP address of the outgoing network interface is filled in as source address. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + */ +static err_t +igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) +{ + /* This is the "router alert" option */ + u16_t ra[2]; + ra[0] = PP_HTONS(ROUTER_ALERT); + ra[1] = 0x0000; /* Router shall examine packet */ + IGMP_STATS_INC(igmp.xmit); + return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); +} + +/** + * Send an igmp packet to a specific group. + * + * @param group the group to which to send the packet + * @param type the type of igmp packet to send + */ +static void +igmp_send(struct igmp_group *group, u8_t type) +{ + struct pbuf* p = NULL; + struct igmp_msg* igmp = NULL; + ip_addr_t src = *IP_ADDR_ANY; + ip_addr_t* dest = NULL; + + /* IP header + "router alert" option + IGMP header */ + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); + + if (p) { + igmp = (struct igmp_msg *)p->payload; + LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", + (p->len >= sizeof(struct igmp_msg))); + ip_addr_copy(src, group->netif->ip_addr); + + if (type == IGMP_V2_MEMB_REPORT) { + dest = &(group->group_address); + ip_addr_copy(igmp->igmp_group_address, group->group_address); + group->last_reporter_flag = 1; /* Remember we were the last to report */ + } else { + if (type == IGMP_LEAVE_GROUP) { + dest = &allrouters; + ip_addr_copy(igmp->igmp_group_address, group->group_address); + } + } + + if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { + igmp->igmp_msgtype = type; + igmp->igmp_maxresp = 0; + igmp->igmp_checksum = 0; + igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); + + igmp_ip_output_if(p, &src, dest, group->netif); + } + + pbuf_free(p); + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); + IGMP_STATS_INC(igmp.memerr); + } +} + +#endif /* LWIP_IGMP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet.c new file mode 100755 index 0000000000..e283a57660 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet.c @@ -0,0 +1,42 @@ +/** + * @file + * Functions common to all TCP/IPv4 modules, such as the byte order functions. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet.h" + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet_chksum.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet_chksum.c new file mode 100755 index 0000000000..bfcc40d5b2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/inet_chksum.c @@ -0,0 +1,450 @@ +/** + * @file + * Incluse internet checksum functions. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet_chksum.h" +#include "lwip/def.h" + +#include +#include + +/* These are some reference implementations of the checksum algorithm, with the + * aim of being simple, correct and fully portable. Checksumming is the + * first thing you would want to optimize for your platform. If you create + * your own version, link it in and in your cc.h put: + * + * #define LWIP_CHKSUM + * + * Or you can select from the implementations below by defining + * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. + */ + +#ifndef LWIP_CHKSUM +# define LWIP_CHKSUM lwip_standard_chksum +# ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 2 +# endif +#endif +/* If none set: */ +#ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 0 +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ +/** + * lwip checksum + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * @note accumulator size limits summable length to 64k + * @note host endianess is irrelevant (p3 RFC1071) + */ +static u16_t ICACHE_FLASH_ATTR +lwip_standard_chksum(void *dataptr, u16_t len) +{ + u32_t acc; + u16_t src; + u8_t *octetptr; + + acc = 0; + /* dataptr may be at odd or even addresses */ + octetptr = (u8_t*)dataptr; + while (len > 1) { + /* declare first octet as most significant + thus assume network order, ignoring host order */ + src = (*octetptr) << 8; + octetptr++; + /* declare second octet as least significant */ + src |= (*octetptr); + octetptr++; + acc += src; + len -= 2; + } + if (len > 0) { + /* accumulate remaining octet */ + src = (*octetptr) << 8; + acc += src; + } + /* add deferred carry bits */ + acc = (acc >> 16) + (acc & 0x0000ffffUL); + if ((acc & 0xffff0000UL) != 0) { + acc = (acc >> 16) + (acc & 0x0000ffffUL); + } + /* This maybe a little confusing: reorder sum using htons() + instead of ntohs() since it has a little less call overhead. + The caller must invert bits for Internet sum ! */ + return htons((u16_t)acc); +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ +/* + * Curt McDowell + * Broadcom Corp. + * csm@broadcom.com + * + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + */ + +static u16_t ICACHE_FLASH_ATTR +lwip_standard_chksum(void *dataptr, int len) +{ + u8_t *pb = (u8_t *)dataptr; + u16_t *ps, t = 0; + u32_t sum = 0; + int odd = ((mem_ptr_t)pb & 1); + + /* Get aligned to u16_t */ + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + /* Add the bulk of the data */ + ps = (u16_t *)(void *)pb; + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* Consume left-over byte, if any */ + if (len > 0) { + ((u8_t *)&t)[0] = *(u8_t *)ps; + } + + /* Add end bytes */ + sum += t; + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + /* Swap if alignment was odd */ + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time. + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ + +static u16_t ICACHE_FLASH_ATTR +lwip_standard_chksum(void *dataptr, int len) +{ + u8_t *pb = (u8_t *)dataptr; + u16_t *ps, t = 0; + u32_t *pl; + u32_t sum = 0, tmp; + /* starts at odd byte address? */ + int odd = ((mem_ptr_t)pb & 1); + + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + ps = (u16_t *)pb; + + if (((mem_ptr_t)ps & 3) && len > 1) { + sum += *ps++; + len -= 2; + } + + pl = (u32_t *)ps; + + while (len > 7) { + tmp = sum + *pl++; /* ping */ + if (tmp < sum) { + tmp++; /* add back carry */ + } + + sum = tmp + *pl++; /* pong */ + if (sum < tmp) { + sum++; /* add back carry */ + } + + len -= 8; + } + + /* make room in upper bits */ + sum = FOLD_U32T(sum); + + ps = (u16_t *)pl; + + /* 16-bit aligned word remaining? */ + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* dangling tail byte remaining? */ + if (len > 0) { /* include odd byte */ + ((u8_t *)&t)[0] = *(u8_t *)ps; + } + + sum += t; /* add end bytes */ + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len) +{ + u32_t acc; + u32_t addr; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + /* iterate through all pbuf in chain */ + for(q = p; q != NULL; q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + acc += LWIP_CHKSUM(q->payload, q->len); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* just executing this next line is probably faster that the if statement needed + to check whether we really need to execute it, and does no harm */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + addr = ip4_addr_get_u32(src); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len) +{ + u32_t acc; + u32_t addr; + struct pbuf *q; + u8_t swapped; + u16_t chklen; + + acc = 0; + swapped = 0; + /* iterate through all pbuf in chain */ + for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + chklen = q->len; + if (chklen > chksum_len) { + chklen = chksum_len; + } + acc += LWIP_CHKSUM(q->payload, chklen); + chksum_len -= chklen; + LWIP_ASSERT("delete me", chksum_len < 0x7fff); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* fold the upper bit down */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + addr = ip4_addr_get_u32(src); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarily for IP + * and ICMP. + * + * @param dataptr start of the buffer to calculate the checksum (no alignment needed) + * @param len length of the buffer to calculate the checksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ + +u16_t +inet_chksum(void *dataptr, u16_t len) +{ + return ~LWIP_CHKSUM(dataptr, len); +} + +/** + * Calculate a checksum over a chain of pbufs (without pseudo-header, much like + * inet_chksum only pbufs are used). + * + * @param p pbuf chain over that the checksum should be calculated + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + for(q = p; q != NULL; q = q->next) { + acc += LWIP_CHKSUM(q->payload, q->len); + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + return (u16_t)~(acc & 0xffffUL); +} + +/* These are some implementations for LWIP_CHKSUM_COPY, which copies data + * like MEMCPY but generates a checksum at the same time. Since this is a + * performance-sensitive function, you might want to create your own version + * in assembly targeted at your hardware by defining it in lwipopts.h: + * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) + */ + +#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ +/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. + * For architectures with big caches, data might still be in cache when + * generating the checksum after copying. + */ +u16_t +lwip_chksum_copy(void *dst, const void *src, u16_t len) +{ + MEMCPY(dst, src, len); + return LWIP_CHKSUM(dst, len); +} +#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip.c new file mode 100755 index 0000000000..00d35b5509 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip.c @@ -0,0 +1,920 @@ +/** + * @file + * This is the IPv4 layer implementation for incoming and outgoing IP traffic. + * + * @see ip_frag.c + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip_frag.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/igmp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp_impl.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/stats.h" +#include "arch/perf.h" + +#include + +/** Set this to 0 in the rare case of wanting to call an extra function to + * generate the IP checksum (in contrast to calculating it on-the-fly). */ +#ifndef LWIP_INLINE_IP_CHKSUM +#define LWIP_INLINE_IP_CHKSUM 1 +#endif +#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP_INLINE 1 +#else +#define CHECKSUM_GEN_IP_INLINE 0 +#endif + +#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 + +/** Some defines for DHCP to let link-layer-addressed packets through while the + * netif is down. + * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT + * to return 1 if the port is accepted and 0 if the port is not accepted. + */ +#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) +/* accept DHCP client port and custom port */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ + || (LWIP_IP_ACCEPT_UDP_PORT(port))) +#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept custom port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port)) +#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept DHCP client port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) +#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ + +#else /* LWIP_DHCP */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 +#endif /* LWIP_DHCP */ + +/** + * The interface that provided the packet for the current callback + * invocation. + */ +struct netif *current_netif; + +/** + * Header of the input packet currently being processed. + */ +const struct ip_hdr *current_header; +/** Source IP address of current_header */ +ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +ip_addr_t current_iphdr_dest; + +/** The IP header ID of the next outgoing IP packet */ +static u16_t ip_id; + +/** + * Finds the appropriate network interface for a given IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + * + * @param dest the destination IP address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip_route(ip_addr_t *dest) +{ + struct netif *netif; + + /* iterate through netifs */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + /* network mask matches? */ + if (netif_is_up(netif)) { + if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + } + /* iterate through netifs */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + /* network mask matches? */ + if (netif_is_up(netif)) { + if (!ip_addr_isbroadcast(dest, netif) && netif == (struct netif *)eagle_lwip_getif(0)) { + return netif; + } + } + } + if ((netif_default == NULL) || (!netif_is_up(netif_default))) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + snmp_inc_ipoutnoroutes(); + return NULL; + } + /* no matching netif found, use default netif */ + return netif_default; +} + +/** + * Finds the appropriate network interface for a source IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + * + * @param source the sourcination IP address for which to find the route + * @return the netif on which to send to reach source + */ + +struct netif *ICACHE_FLASH_ATTR +ip_router(ip_addr_t *dest, ip_addr_t *source){ + struct netif *netif; + /* iterate through netifs */ + for(netif = netif_list; netif != NULL; netif = netif->next) { + /* network mask matches? */ + + if (netif_is_up(netif)) { + if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + + if (netif_is_up(netif)) { + if (ip_addr_netcmp(source, &(netif->ip_addr), &(netif->netmask))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + } + + if ((netif_default == NULL) || (!netif_is_up(netif_default))) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + snmp_inc_ipoutnoroutes(); + return NULL; + } + /* no matching netif found, use default netif */ + os_printf("ip_router %d %p\n", __LINE__, netif_default); + return netif_default; +} + +#if IP_FORWARD +/** + * Forwards an IP packet. It finds an appropriate route for the + * packet, decrements the TTL value of the packet, adjusts the + * checksum and outputs the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IP header of the input packet + * @param inp the netif on which this packet was received + */ +static void ICACHE_FLASH_ATTR +ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + PERF_START; + + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip_addr_islinklocal(¤t_iphdr_dest)) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip_route(¤t_iphdr_dest); + if (netif == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; + } + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); + goto return_noroute; + } + + /* decrement TTL */ + IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); + /* send ICMP if TTL == 0 */ + if (IPH_TTL(iphdr) == 0) { + snmp_inc_ipinhdrerrors(); +#if LWIP_ICMP + /* Don't send ICMP messages in response to ICMP messages */ + if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { + icmp_time_exceeded(p, ICMP_TE_TTL); + } +#endif /* LWIP_ICMP */ + return; + } + + /* Incrementally update the IP checksum. */ + if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); + } else { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); + } + + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + + IP_STATS_INC(ip.fw); + IP_STATS_INC(ip.xmit); + snmp_inc_ipforwdatagrams(); + + PERF_STOP("ip_forward"); + /* transmit pbuf on chosen interface */ + netif->output(netif, p, ¤t_iphdr_dest); + return; +return_noroute: + snmp_inc_ipoutnoroutes(); +} +#endif /* IP_FORWARD */ + +/** + * This function is called by the network interface device driver when + * an IP packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * @param p the received IP packet (p->payload points to IP header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + * processed, but currently always returns ERR_OK) + */ +err_t +ip_input(struct pbuf *p, struct netif *inp) +{ + struct ip_hdr *iphdr; + struct netif *netif; + u16_t iphdr_hlen; + u16_t iphdr_len; +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + int check_ip_src=1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + + IP_STATS_INC(ip.recv); + snmp_inc_ipinreceives(); + + /* identify the IP header */ + iphdr = (struct ip_hdr *)p->payload; + if (IPH_V(iphdr) != 4) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); + ip_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.err); + IP_STATS_INC(ip.drop); + snmp_inc_ipinhdrerrors(); + return ERR_OK; + } + + /* obtain IP header length in number of 32-bit words */ + iphdr_hlen = IPH_HL(iphdr); + /* calculate IP header length in bytes */ + iphdr_hlen *= 4; + /* obtain ip length in bytes */ + iphdr_len = ntohs(IPH_LEN(iphdr)); + + /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ + if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { + if (iphdr_hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_hlen, p->len)); + } + if (iphdr_len > p->tot_len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_len, p->tot_len)); + } + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.lenerr); + IP_STATS_INC(ip.drop); + snmp_inc_ipindiscards(); + return ERR_OK; + } + + /* verify checksum */ +#if CHECKSUM_CHECK_IP + if (inet_chksum(iphdr, iphdr_hlen) != 0) { + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); + ip_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.chkerr); + IP_STATS_INC(ip.drop); + snmp_inc_ipinhdrerrors(); + return ERR_OK; + } +#endif + + /* Trim pbuf. This should have been done at the netif layer, + * but we'll do it anyway just to be sure that its done. */ + pbuf_realloc(p, iphdr_len); + + /* copy IP addresses to aligned ip_addr_t */ + ip_addr_copy(current_iphdr_dest, iphdr->dest); + ip_addr_copy(current_iphdr_src, iphdr->src); + + /* match packet against an interface, i.e. is this packet for us? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(¤t_iphdr_dest)) { + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { + netif = inp; + } else { + netif = NULL; + } + } else +#endif /* LWIP_IGMP */ + { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. + 'first' is used as a boolean to mark whether we started walking the list */ + int first = 1; + netif = inp; + do { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", + ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), + ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), + ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), + ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); + + /* interface is up and configured? */ + if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { + /* unicast to this interface address? */ + if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || + /* or broadcast on this interface network address? */ + ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } +#if LWIP_AUTOIP + /* connections to link-local addresses must persist after changing + the netif's address (RFC3927 ch. 1.9) */ + if ((netif->autoip != NULL) && + ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } +#endif /* LWIP_AUTOIP */ + } + if (first) { + first = 0; + netif = netif_list; + } else { + netif = netif->next; + } + if (netif == inp) { + netif = netif->next; + } + } while(netif != NULL); + } + +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed + * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. + * According to RFC 1542 section 3.1.1, referred by RFC 2131). + * + * If you want to accept private broadcast communication while a netif is down, + * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: + * + * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) + */ + if (netif == NULL) { + /* remote port is DHCP server? */ + if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", + ntohs(udphdr->dest))); + if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); + netif = inp; + check_ip_src = 0; + } + } + } +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + + /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ + if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || + (ip_addr_ismulticast(¤t_iphdr_src))) { + /* packet source is not valid */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.drop); + snmp_inc_ipinaddrerrors(); + snmp_inc_ipindiscards(); + return ERR_OK; + } + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); +#if IP_FORWARD + /* non-broadcast packet? */ + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { + /* try to forward IP packet on (other) interfaces */ + ip_forward(p, iphdr, inp); + } else +#endif /* IP_FORWARD */ + { + snmp_inc_ipinaddrerrors(); + snmp_inc_ipindiscards(); + } + pbuf_free(p); + return ERR_OK; + } + /* packet consists of multiple fragments? */ + if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { +#if IP_REASSEMBLY /* packet fragment reassembly code present? */ + LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", + ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); + /* reassemble the packet*/ + p = ip_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + return ERR_OK; + } + iphdr = (struct ip_hdr *)p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ + pbuf_free(p); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", + ntohs(IPH_OFFSET(iphdr)))); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + snmp_inc_ipinunknownprotos(); + return ERR_OK; +#endif /* IP_REASSEMBLY */ + } + +#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ + +#if LWIP_IGMP + /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ + if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { +#else + if (iphdr_hlen > IP_HLEN) { +#endif /* LWIP_IGMP */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); + pbuf_free(p); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + snmp_inc_ipinunknownprotos(); + return ERR_OK; + } +#endif /* IP_OPTIONS_ALLOWED == 0 */ + + /* send to upper layers */ + LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); + ip_debug_print(p); + LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + + current_netif = inp; + current_header = iphdr; + +#if LWIP_RAW + /* raw input did not eat the packet? */ + if (raw_input(p, inp) == 0) +#endif /* LWIP_RAW */ + { + + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP + case IP_PROTO_UDP: +#if LWIP_UDPLITE + case IP_PROTO_UDPLITE: +#endif /* LWIP_UDPLITE */ + snmp_inc_ipindelivers(); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP_PROTO_TCP: + snmp_inc_ipindelivers(); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP + case IP_PROTO_ICMP: + snmp_inc_ipindelivers(); + icmp_input(p, inp); + break; +#endif /* LWIP_ICMP */ +#if LWIP_IGMP + case IP_PROTO_IGMP: + igmp_input(p, inp, ¤t_iphdr_dest); + break; +#endif /* LWIP_IGMP */ + default: +#if LWIP_ICMP + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && + !ip_addr_ismulticast(¤t_iphdr_dest)) { + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PROTO); + } +#endif /* LWIP_ICMP */ + pbuf_free(p); + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); + + IP_STATS_INC(ip.proterr); + IP_STATS_INC(ip.drop); + snmp_inc_ipinunknownprotos(); + } + } + + current_netif = NULL; + current_header = NULL; + ip_addr_set_any(¤t_iphdr_src); + ip_addr_set_any(¤t_iphdr_dest); + + return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + * If the destination IP address is IP_HDRINCL, p is assumed to already + * include an IP header and p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + * + * @note ip_id: RFC791 "some host may be able to simply use + * unique identifiers independent of destination" + */ +err_t +ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ + struct ip_hdr *iphdr; + ip_addr_t dest_addr; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum = 0; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + + snmp_inc_ipoutrequests(); + + /* Should the IP header be generated or is it already included in p? */ + if (dest != IP_HDRINCL) { + u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND + u16_t optlen_aligned = 0; + if (optlen != 0) { +#if CHECKSUM_GEN_IP_INLINE + int i; +#endif /* CHECKSUM_GEN_IP_INLINE */ + /* round up to a multiple of 4 */ + optlen_aligned = ((optlen + 3) & ~3); + ip_hlen += optlen_aligned; + /* First write in the IP options */ + if (pbuf_header(p, optlen_aligned)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); + IP_STATS_INC(ip.err); + snmp_inc_ipoutdiscards(); + return ERR_BUF; + } + MEMCPY(p->payload, ip_options, optlen); + if (optlen < optlen_aligned) { + /* zero the remaining bytes */ + os_memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); + } +#if CHECKSUM_GEN_IP_INLINE + for (i = 0; i < optlen_aligned/2; i++) { + chk_sum += ((u16_t*)p->payload)[i]; + } +#endif /* CHECKSUM_GEN_IP_INLINE */ + } +#endif /* IP_OPTIONS_SEND */ + /* generate IP header */ + if (pbuf_header(p, IP_HLEN)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); + + IP_STATS_INC(ip.err); + snmp_inc_ipoutdiscards(); + return ERR_BUF; + } + + iphdr = (struct ip_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", + (p->len >= sizeof(struct ip_hdr))); + + IPH_TTL_SET(iphdr, ttl); + IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += LWIP_MAKE_U16(proto, ttl); +#endif /* CHECKSUM_GEN_IP_INLINE */ + + /* dest cannot be NULL here */ + ip_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_v_hl_tos; +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_LEN_SET(iphdr, htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_OFFSET_SET(iphdr, 0); + IPH_ID_SET(iphdr, htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ + ++ip_id; + +#if ESP_SYSTEM_APP /* by LiuHan: change IP fragment flags for support min MTU*/ + if (IPH_PROTO(iphdr) == IP_PROTO_TCP){ + //ets_printf("TCP protocol need change IP fragment flags\n"); + IPH_OFFSET_SET(iphdr, htons(IP_DF)); + chk_sum += iphdr->_offset; + } else { + //ets_printf("current protocol %d\n", IPH_PROTO(iphdr)); + } +#endif /*CHECKSUM_GEN_IP_OFFSET */ + + if (ip_addr_isany(src)) { + ip_addr_copy(iphdr->src, netif->ip_addr); + } else { + /* src cannot be NULL here */ + ip_addr_copy(iphdr->src, *src); + } + +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; + chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); + chk_sum = (chk_sum >> 16) + chk_sum; + chk_sum = ~chk_sum; + iphdr->_chksum = chk_sum; /* network order */ +#else /* CHECKSUM_GEN_IP_INLINE */ + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); +#endif +#endif /* CHECKSUM_GEN_IP_INLINE */ + } else { + /* IP header already included in p */ + iphdr = (struct ip_hdr *)p->payload; + ip_addr_copy(dest_addr, iphdr->dest); + dest = &dest_addr; + } + + IP_STATS_INC(ip.xmit); + + LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); + ip_debug_print(p); + +#if ENABLE_LOOPBACK + if (ip_addr_cmp(dest, &netif->ip_addr)) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); + return netif_loop_output(netif, p, dest); + } +#if LWIP_IGMP + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p, dest); + } +#endif /* LWIP_IGMP */ +#endif /* ENABLE_LOOPBACK */ +#if IP_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) { + return ip_frag(p, netif, dest); + } +#endif /* IP_FRAG */ + + LWIP_DEBUGF(IP_DEBUG, ("netif->output()\n")); + return netif->output(netif, p, dest); +} + +/** + * Simple interface to ip_output_if. It finds the outgoing network + * interface and calls upon ip_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto) +{ + struct netif *netif; + + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + + if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + return ip_output_if(p, src, dest, ttl, tos, proto, netif); +} + +#if LWIP_NETIF_HWADDRHINT +/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an IP + header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param addr_hint address hint pointer set to netif->addr_hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ + struct netif *netif; + err_t err; + + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + + if ((netif = ip_route(dest)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + netif->addr_hint = addr_hint; + err = ip_output_if(p, src, dest, ttl, tos, proto, netif); + netif->addr_hint = NULL; + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if IP_DEBUG +/* Print an IP header by using LWIP_DEBUGF + * @param p an IP packet, p->payload pointing to the IP header + */ +void +ip_debug_print(struct pbuf *p) +{ + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + u8_t *payload; + + payload = (u8_t *)iphdr + IP_HLEN; + + LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", + IPH_V(iphdr), + IPH_HL(iphdr), + IPH_TOS(iphdr), + ntohs(IPH_LEN(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", + ntohs(IPH_ID(iphdr)), + ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, + ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, + ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, + ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", + IPH_TTL(iphdr), + IPH_PROTO(iphdr), + ntohs(IPH_CHKSUM(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", + ip4_addr1_16(&iphdr->src), + ip4_addr2_16(&iphdr->src), + ip4_addr3_16(&iphdr->src), + ip4_addr4_16(&iphdr->src))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", + ip4_addr1_16(&iphdr->dest), + ip4_addr2_16(&iphdr->dest), + ip4_addr3_16(&iphdr->dest), + ip4_addr4_16(&iphdr->dest))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_addr.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_addr.c new file mode 100755 index 0000000000..e2df58d350 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_addr.c @@ -0,0 +1,329 @@ +/** + * @file + * This is the IPv4 address tools implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const ip_addr_t ip_addr_any ICACHE_RODATA_ATTR = { IPADDR_ANY }; +const ip_addr_t ip_addr_broadcast ICACHE_RODATA_ATTR = { IPADDR_BROADCAST }; + +/** + * Determine if an address is a broadcast address on a network interface + * + * @param addr address to be checked + * @param netif the network interface against which the address is checked + * @return returns non-zero if the address is a broadcast address + */ +u8_t +ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) +{ + ip_addr_t ipaddr; + ip4_addr_set_u32(&ipaddr, addr); + + /* all ones (broadcast) or all zeroes (old skool broadcast) */ + if ((~addr == IPADDR_ANY) || + (addr == IPADDR_ANY)) { + return 1; + /* no broadcast support on this network interface? */ + } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { + /* the given address cannot be a broadcast address + * nor can we check against any broadcast addresses */ + return 0; + /* address matches network interface address exactly? => no broadcast */ + } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { + return 0; + /* on the same (sub) network... */ + } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) + /* ...and host identifier bits are all ones? =>... */ + && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == + (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { + /* => network broadcast address */ + return 1; + } else { + return 0; + } +} + +/** Checks if a netmask is valid (starting with ones, then only zeros) + * + * @param netmask the IPv4 netmask to check (in network byte order!) + * @return 1 if the netmask is valid, 0 if it is not + */ +u8_t +ip4_addr_netmask_valid(u32_t netmask) +{ + u32_t mask; + u32_t nm_hostorder = lwip_htonl(netmask); + + /* first, check for the first zero */ + for (mask = 1U << 31 ; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) == 0) { + break; + } + } + /* then check that there is no one */ + for (; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) != 0) { + /* there is a one after the first zero -> invalid */ + return 0; + } + } + /* no one after the first zero -> valid */ + return 1; +} + +/* Here for now until needed in other places in lwIP */ +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +//#define isdigit(c) in_range(c, '0', '9') +//#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif + +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @return ip address in network order + */ +u32_t +ipaddr_addr(const char *cp) +{ + ip_addr_t val; + + if (ipaddr_aton(cp, &val)) { + return ip4_addr_get_u32(&val); + } + return (IPADDR_NONE); +} + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ipaddr_aton(const char *cp, ip_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + char ch; + unsigned long cutoff; + int cutlim; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; + base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') { + base = 16; + c = *++cp; + } else + base = 8; + } + + cutoff =(unsigned long)0xffffffff / (unsigned long)base; + cutlim =(unsigned long)0xffffffff % (unsigned long)base; + + for (;;) { + if (isdigit(c)) { + ch = (int)(c - '0'); + + if (val > cutoff || (val == cutoff && ch > cutlim)) + return (0); + + val = (val * base) + (int)(c - '0'); + c = *++cp; + } else if (base == 16 && isxdigit(c)) { + ch = (int)(c + 10 - (islower(c) ? 'a' : 'A')); + + if (val > cutoff || (val == cutoff && ch > cutlim)) + return (0); + + val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) { + return (0); + } + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) { + return (0); + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if ((val > 0xffffffUL) || (parts[0] > 0xff)) { + return (0); + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) { + return (0); + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) { + return (0); + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + LWIP_ASSERT("unhandled", 0); + break; + } + if (addr) { + ip4_addr_set_u32(addr, htonl(val)); + } + return (1); +} + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * represenation of addr + */ +char * +ipaddr_ntoa(const ip_addr_t *addr) +{ + static char str[16]; + return ipaddr_ntoa_r(addr, str, 16); +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) +{ + u32_t s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + int len = 0; + + s_addr = ip4_addr_get_u32(addr); + + rp = buf; + ap = (u8_t *)&s_addr; + for(n = 0; n < 4; n++) { + i = 0; + do { + rem = *ap % (u8_t)10; + *ap /= (u8_t)10; + inv[i++] = '0' + rem; + } while(*ap); + while(i--) { + if (len++ >= buflen) { + return NULL; + } + *rp++ = inv[i]; + } + if (len++ >= buflen) { + return NULL; + } + *rp++ = '.'; + ap++; + } + *--rp = 0; + return buf; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_frag.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_frag.c new file mode 100755 index 0000000000..b89eeb5872 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/ipv4/ip_frag.c @@ -0,0 +1,863 @@ +/** + * @file + * This is the IPv4 packet segmentation and reassembly implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * Simon Goldschmidt + * original reassembly code by Adam Dunkels + * + */ + +#include "lwip/opt.h" +#include "lwip/ip_frag.h" +#include "lwip/def.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/stats.h" +#include "lwip/icmp.h" + +#include + +#if IP_REASSEMBLY +/** + * The IP reassembly code currently has the following limitations: + * - IP header options are not supported + * - fragments must not overlap (e.g. due to different routes), + * currently, overlapping or duplicate fragments are thrown away + * if IP_REASS_CHECK_OVERLAP=1 (the default)! + * + * @todo: work with IP header options + */ + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IP header, since it replaces + * the IP header in memory in incoming fragments (after copying it) to keep + * track of the various fragments. (-> If the IP header doesn't need packing, + * this struct doesn't need packing, too.) + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ + (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ + ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ + IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 + +/* global variables */ +static struct ip_reassdata *reassdatagrams; +static u16_t ip_reass_pbufcount; + +/* function prototypes */ +static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR; +static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR; + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). + */ +void +ip_reass_tmr(void) +{ + struct ip_reassdata *r, *prev = NULL; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); + prev = r; + r = r->next; + } else { + /* reassembly timed out */ + struct ip_reassdata *tmp; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip_reass_free_complete_datagram(tmp, prev); + } + } +} + +/** + * Free a datagram (struct ip_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip_reass_pbufcount), + * SNMP counters and sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + * @param prev the previous datagram in the linked list + * @return the number of pbufs freed + */ +static int +ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + u16_t pbufs_freed = 0; + u8_t clen; + struct pbuf *p; + struct ip_reass_helper *iprh; + + LWIP_ASSERT("prev != ipr", prev != ipr); + if (prev != NULL) { + LWIP_ASSERT("prev->next == ipr", prev->next == ipr); + } + + snmp_inc_ipreasmfails(); +#if LWIP_ICMP + iprh = (struct ip_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, copy the original header into it. */ + SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); + icmp_time_exceeded(p, ICMP_TE_FRAG); + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(p); + } +#endif /* LWIP_ICMP */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(pcur); + } + /* Then, unchain the struct ip_reassdata from the list and free it. */ + ip_reass_dequeue_datagram(ipr, prev); + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); + ip_reass_pbufcount -= pbufs_freed; + + return pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram 'fraghdr' belongs to is not freed! + * + * @param fraghdr IP header of the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + * @return the number of pbufs freed + */ +static int +ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) +{ + /* @todo Can't we simply remove the last datagram in the + * linked list behind reassdatagrams? + */ + struct ip_reassdata *r, *oldest, *prev; + int pbufs_freed = 0, pbufs_freed_current; + int other_datagrams; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the datagram that 'fraghdr' belongs to! */ + do { + oldest = NULL; + prev = NULL; + other_datagrams = 0; + r = reassdatagrams; + while (r != NULL) { + if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { + /* Not the same datagram as fraghdr */ + other_datagrams++; + if (oldest == NULL) { + oldest = r; + } else if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + } + } + if (r->next != NULL) { + prev = r; + } + r = r->next; + } + if (oldest != NULL) { + pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev); + pbufs_freed += pbufs_freed_current; + } + } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); + return pbufs_freed; +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Enqueues a new fragment into the fragment queue + * @param fraghdr points to the new fragments IP hdr + * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) + * @return A pointer to the queue location into which the fragment was enqueued + */ +static struct ip_reassdata* ICACHE_FLASH_ATTR +ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) +{ + struct ip_reassdata* ipr; + /* No matching previous fragment found, allocate a new reassdata struct */ + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + } + if (ipr == NULL) +#endif /* IP_REASS_FREE_OLDEST */ + { + IPFRAG_STATS_INC(ip_frag.memerr); + LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); + return NULL; + } + } + os_memset(ipr, 0, sizeof(struct ip_reassdata)); + ipr->timer = IP_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + /* copy the ip header for later tests and input */ + /* @todo: no ip options supported? */ + SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); + return ipr; +} + +/** + * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. + * @param ipr points to the queue entry to dequeue + */ +static void ICACHE_FLASH_ATTR +ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + + /* dequeue the reass struct */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", prev != NULL); + prev->next = ipr->next; + } + + /* now we can free the ip_reass struct */ + memp_free(MEMP_REASSDATA, ipr); +} + +/** + * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list + * will grow over time as new pbufs are rx. + * Also checks that the datagram passes basic continuity checks (if the last + * fragment was received at least once). + * @param root_p points to the 'root' pbuf for the current datagram being assembled. + * @param new_p points to the pbuf for the current fragment + * @return 0 if invalid, >0 otherwise + */ +static int ICACHE_FLASH_ATTR +ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) +{ + struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct pbuf *q; + u16_t offset,len; + struct ip_hdr *fraghdr; + int valid = 1; + + /* Extract length and fragment offset from current fragment */ + fraghdr = (struct ip_hdr*)new_p->payload; + len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + + /* overwrite the fragment's ip header from the pbuf with our helper struct, + * and setup the embedded helper structure. */ + /* make sure the struct ip_reass_helper fits into the IP header */ + LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", + sizeof(struct ip_reass_helper) <= IP_HLEN); + iprh = (struct ip_reass_helper*)new_p->payload; + iprh->next_pbuf = NULL; + iprh->start = offset; + iprh->end = offset + len; + + /* Iterate through until we either get to the end of the list (append), + * or we find on with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip_reass_helper*)q->payload; + if (iprh->start < iprh_tmp->start) { + /* the new pbuf should be inserted before this */ + iprh->next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ +#if IP_REASS_CHECK_OVERLAP + if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { + /* fragment overlaps with previous or following, throw away */ + goto freepbuf; + } +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + } else { + /* fragment with the lowest offset */ + ipr->p = new_p; + } + break; + } else if(iprh->start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + goto freepbuf; +#if IP_REASS_CHECK_OVERLAP + } else if(iprh->start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + goto freepbuf; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no wholes. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + if (iprh_prev->end != iprh->start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = new_p; + } + } + + /* At this point, the validation part begins: */ + /* If we already received the last fragment */ + if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { + /* and had no wholes so far */ + if (valid) { + /* then check if the rest of the fragments is here */ + /* Check if the queue starts with the first datagram */ + if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) { + valid = 0; + } else { + /* and check that there are no wholes after this datagram */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while (q != NULL) { + iprh = (struct ip_reass_helper*)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + /* if still valid, all fragments are received + * (because to the MF==0 already arrived */ + if (valid) { + LWIP_ASSERT("sanity check", ipr->p != NULL); + LWIP_ASSERT("sanity check", + ((struct ip_reass_helper*)ipr->p->payload) != iprh); + LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", + iprh->next_pbuf == NULL); + LWIP_ASSERT("validate_datagram:datagram end!=datagram len", + iprh->end == ipr->datagram_len); + } + } + } + /* If valid is 0 here, there are some fragments missing in the middle + * (since MF == 0 has already arrived). Such datagrams simply time out if + * no more fragments are received... */ + return valid; + } + /* If we come here, not all fragments were received, yet! */ + return 0; /* not yet valid! */ +#if IP_REASS_CHECK_OVERLAP +freepbuf: + ip_reass_pbufcount -= pbuf_clen(new_p); + pbuf_free(new_p); + return 0; +#endif /* IP_REASS_CHECK_OVERLAP */ +} + +/** + * Reassembles incoming IP fragments into an IP datagram. + * + * @param p points to a pbuf chain of the fragment + * @return NULL if reassembly is incomplete, ? otherwise + */ +struct pbuf * +ip_reass(struct pbuf *p) +{ + struct pbuf *r; + struct ip_hdr *fraghdr; + struct ip_reassdata *ipr; + struct ip_reass_helper *iprh; + u16_t offset, len; + u8_t clen; + struct ip_reassdata *ipr_prev = NULL; + + IPFRAG_STATS_INC(ip_frag.recv); + snmp_inc_ipreasmreqds(); + + fraghdr = (struct ip_hdr*)p->payload; + + if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { + LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); + IPFRAG_STATS_INC(ip_frag.err); + goto nullreturn; + } + + offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + + /* Check if we are allowed to enqueue more datagrams. */ + clen = pbuf_clen(p); + if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || + ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) +#endif /* IP_REASS_FREE_OLDEST */ + { + /* No datagram could be freed and still too many pbufs enqueued */ + LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", + ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); + IPFRAG_STATS_INC(ip_frag.memerr); + /* @todo: send ICMP time exceeded here? */ + /* drop this pbuf */ + goto nullreturn; + } + } + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", + ntohs(IPH_ID(fraghdr)))); + IPFRAG_STATS_INC(ip_frag.cachehit); + break; + } + ipr_prev = ipr; + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); + /* Bail if unable to enqueue */ + if(ipr == NULL) { + goto nullreturn; + } + } else { + if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && + ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { + /* ipr->iphdr is not the header from the first fragment, but fraghdr is + * -> copy fraghdr into ipr->iphdr since we want to have the header + * of the first fragment (for ICMP time exceeded and later, for copying + * all options, if supported)*/ + SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); + } + } + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time */ + ip_reass_pbufcount += clen; + + /* At this point, we have either created a new entry or pointing + * to an existing one */ + + /* check for 'no more fragments', and update queue entry*/ + if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { + ipr->flags |= IP_REASS_FLAG_LASTFRAG; + ipr->datagram_len = offset + len; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip_reass: last fragment seen, total len %"S16_F"\n", + ipr->datagram_len)); + } + /* find the right place to insert this pbuf */ + /* @todo: trim pbufs if fragments are overlapping */ + if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { + /* the totally last fragment (flag more fragments = 0) was received at least + * once AND all fragments are received */ + ipr->datagram_len += IP_HLEN; + + /* save the second pbuf before copying the header over the pointer */ + r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; + + /* copy the original ip header back to the first pbuf */ + fraghdr = (struct ip_hdr*)(ipr->p->payload); + SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); + IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); + IPH_OFFSET_SET(fraghdr, 0); + IPH_CHKSUM_SET(fraghdr, 0); + /* @todo: do we need to set calculate the correct checksum? */ + IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + + p = ipr->p; + + /* chain together the pbufs contained within the reass_data list. */ + while(r != NULL) { + iprh = (struct ip_reass_helper*)r->payload; + + /* hide the ip header for every succeding fragment */ + pbuf_header(r, -IP_HLEN); + pbuf_cat(p, r); + r = iprh->next_pbuf; + } + /* release the sources allocate for the fragment queue entry */ + ip_reass_dequeue_datagram(ipr, ipr_prev); + + /* and adjust the number of pbufs currently queued for reassembly. */ + ip_reass_pbufcount -= pbuf_clen(p); + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); + return NULL; + +nullreturn: + LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); + IPFRAG_STATS_INC(ip_frag.drop); + pbuf_free(p); + return NULL; +} +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if IP_FRAG_USES_STATIC_BUF +static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; +#else /* IP_FRAG_USES_STATIC_BUF */ + +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* ICACHE_FLASH_ATTR +ip_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void ICACHE_FLASH_ATTR +ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void ICACHE_FLASH_ATTR +ipfrag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ +#endif /* IP_FRAG_USES_STATIC_BUF */ + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by using a fixed size static memory buffer (PBUF_REF) or + * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) +{ + struct pbuf *rambuf; +#if IP_FRAG_USES_STATIC_BUF + struct pbuf *header; +#else +#if !LWIP_NETIF_TX_SINGLE_PBUF + struct pbuf *newpbuf; +#endif + struct ip_hdr *original_iphdr; +#endif + struct ip_hdr *iphdr; + u16_t nfb; + u16_t left, cop; + u16_t mtu = netif->mtu; + u16_t ofo, omf; + u16_t last; + u16_t poff = IP_HLEN; + u16_t tmp; +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF + u16_t newpbuflen = 0; + u16_t left_to_copy; +#endif + + /* Get a RAM based MTU sized pbuf */ +#if IP_FRAG_USES_STATIC_BUF + /* When using a static buffer, we use a PBUF_REF, which we will + * use to reference the packet (without link header). + * Layer and length is irrelevant. + */ + rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); + if (rambuf == NULL) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); + return ERR_MEM; + } + rambuf->tot_len = rambuf->len = mtu; + rambuf->payload = LWIP_MEM_ALIGN((void *)buf); + + /* Copy the IP header in it */ + iphdr = (struct ip_hdr *)rambuf->payload; + SMEMCPY(iphdr, p->payload, IP_HLEN); +#else /* IP_FRAG_USES_STATIC_BUF */ + original_iphdr = (struct ip_hdr *)p->payload; + iphdr = original_iphdr; +#endif /* IP_FRAG_USES_STATIC_BUF */ + + /* Save original offset */ + tmp = ntohs(IPH_OFFSET(iphdr)); + ofo = tmp & IP_OFFMASK; + omf = tmp & IP_MF; + + left = p->tot_len - IP_HLEN; + + nfb = (mtu - IP_HLEN) / 8; + + while (left) { + last = (left <= mtu - IP_HLEN); + + /* Set new offset and MF flag */ + tmp = omf | (IP_OFFMASK & (ofo)); + if (!last) { + tmp = tmp | IP_MF; + } + + /* Fill this fragment */ + cop = last ? left : nfb * 8; + +#if IP_FRAG_USES_STATIC_BUF + poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); +#else /* IP_FRAG_USES_STATIC_BUF */ +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); + if (rambuf == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); + /* make room for the IP header */ + if(pbuf_header(rambuf, IP_HLEN)) { + pbuf_free(rambuf); + return ERR_MEM; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = rambuf->payload; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link and IP header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); + if (rambuf == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (p->len >= (IP_HLEN))); + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = (struct ip_hdr *)rambuf->payload; + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len -= poff; + + left_to_copy = cop; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + pcr = ip_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) { + p = p->next; + } + } + poff = newpbuflen; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ +#endif /* IP_FRAG_USES_STATIC_BUF */ + + /* Correct header */ + IPH_OFFSET_SET(iphdr, htons(tmp)); + IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); + IPH_CHKSUM_SET(iphdr, 0); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + +#if IP_FRAG_USES_STATIC_BUF + if (last) { + pbuf_realloc(rambuf, left + IP_HLEN); + } + + /* This part is ugly: we alloc a RAM based pbuf for + * the link level header for each chunk and then + * free it.A PBUF_ROM style pbuf for which pbuf_header + * worked would make things simpler. + */ + header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); + if (header != NULL) { + pbuf_chain(header, rambuf); + netif->output(netif, header, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + snmp_inc_ipfragcreates(); + pbuf_free(header); + } else { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); + pbuf_free(rambuf); + return ERR_MEM; + } +#else /* IP_FRAG_USES_STATIC_BUF */ + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + netif->output(netif, rambuf, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ + left -= cop; + ofo += nfb; + } +#if IP_FRAG_USES_STATIC_BUF + pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ + snmp_inc_ipfragoks(); + return ERR_OK; +} +#endif /* IP_FRAG */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mdns.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mdns.c new file mode 100755 index 0000000000..952698237e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mdns.c @@ -0,0 +1,1136 @@ +/** + * lwip MDNS resolver file. + * + * Created on: Jul 29, 2010 + * Author: Daniel Toma + * + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + + * This file implements a MDNS host name and PUCK service registration. + + *----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ +#include "lwip/opt.h" +#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */ +#include "lwip/mdns.h" +#include "lwip/puck_def.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/igmp.h" +#include "osapi.h" +#include "os_type.h" +#include "user_interface.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** DNS server IP address */ +#ifndef DNS_MULTICAST_ADDRESS +#define DNS_MULTICAST_ADDRESS ipaddr_addr("224.0.0.251") /* resolver1.opendns.com */ +#endif + +/** DNS server IP address */ +#ifndef MDNS_LOCAL +#define MDNS_LOCAL "local" /* resolver1.opendns.com */ +#endif + +/** DNS server port address */ +#ifndef DNS_MDNS_PORT +#define DNS_MDNS_PORT 5353 +#endif + +/** DNS maximum number of retries when asking for a name, before "timeout". */ +#ifndef DNS_MAX_RETRIES +#define DNS_MAX_RETRIES 4 +#endif + +/** DNS resource record max. TTL (one week as default) */ +#ifndef DNS_MAX_TTL +#define DNS_MAX_TTL 604800 +#endif + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE 0x84 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +/* DNS protocol states */ +#define DNS_STATE_UNUSED 0 +#define DNS_STATE_NEW 1 +#define DNS_STATE_ASKING 2 +#define DNS_STATE_DONE 3 + +/* MDNS registration type */ +#define MDNS_HOSTNAME_REG 0 +#define MDNS_SERVICE_REG 1 + +/* MDNS registration type */ +#define MDNS_REG_ANSWER 1 +#define MDNS_SD_ANSWER 2 +#define MDNS_SERVICE_REG_ANSWER 3 + +/* MDNS registration time */ +#define MDNS_HOST_TIME 120 +#define MDNS_SERVICE_TIME 3600 + +/** MDNS name length with "." at the beginning and end of name*/ +#ifndef MDNS_LENGTH_ADD +#define MDNS_LENGTH_ADD 2 +#endif + +#ifdef MDNS_MAX_NAME_LENGTH +#undef MDNS_MAX_NAME_LENGTH +#endif +#define MDNS_MAX_NAME_LENGTH (256) + +PACK_STRUCT_BEGIN +/** DNS message header */ +struct mdns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u8_t flags1); + PACK_STRUCT_FIELD(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_DNS_HDR 12 + +PACK_STRUCT_BEGIN +/** MDNS query message structure */ +struct mdns_query { + /* MDNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_DNS_QUERY 4 + +PACK_STRUCT_BEGIN +/** MDNS answer message structure */ +struct mdns_answer { + /* MDNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t len); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#define SIZEOF_DNS_ANSWER 10 + +PACK_STRUCT_BEGIN +/** MDNS answer message structure */ +struct mdns_auth { + PACK_STRUCT_FIELD(u32_t src); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_MDNS_AUTH 4 +PACK_STRUCT_BEGIN +/** MDNS service registration message structure */ +struct mdns_service { + PACK_STRUCT_FIELD(u16_t prior); + PACK_STRUCT_FIELD(u16_t weight); + PACK_STRUCT_FIELD(u16_t port); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_MDNS_SERVICE 6 + +uint16 PUCK_PORT ; +os_timer_t mdns_timer; +/* forward declarations */ +static void mdns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, + struct ip_addr *addr, u16_t port); + +/*----------------------------------------------------------------------------- + * Globales + *----------------------------------------------------------------------------*/ + +/* MDNS variables */ +static char host_name[MDNS_NAME_LENGTH]; +static char service_name[MDNS_NAME_LENGTH]; +static char server_name[MDNS_NAME_LENGTH]; +//static char puck_datasheet[PUCK_DATASHEET_SIZE]; +static struct udp_pcb *mdns_pcb = NULL; +static struct mdns_info * ms_info = NULL; +static struct ip_addr multicast_addr; +static struct ip_addr host_addr; +static uint8 register_flag = 0; +static uint8 mdns_flag = 0; +//#if (DNS_USES_STATIC_BUF == 1) +static u8_t mdns_payload[DNS_MSG_SIZE]; +//#endif /* (MDNS_USES_STATIC_BUF == 1) */ +/* + * Function to set the UDP pcb used to send the mDNS packages + */ +void ICACHE_FLASH_ATTR +getPcb(struct udp_pcb *pcb) { + mdns_pcb = pcb; +} + +#if DNS_DOES_NAME_CHECK +/** + * Compare the "dotted" name "query" with the encoded name "response" + * to make sure an answer from the DNS server matches the current mdns_table + * entry (otherwise, answers might arrive late for hostname not on the list + * any more). + * + * @param query hostname (not encoded) from the mdns_table + * @param response encoded hostname in the DNS response + * @return 0: names equal; 1: names differ + */ +static u8_t ICACHE_FLASH_ATTR +mdns_compare_name(unsigned char *query, unsigned char *response) { + unsigned char n; + + do { + n = *response++; + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name */ + break; + } else { + /* Not compressed name */ + while (n > 0) { + if ((*query) != (*response)) { + return 1; + } + ++response; + ++query; + --n; + }; + ++query; + } + } while (*response != 0); + + return 0; +} +#endif /* DNS_DOES_NAME_CHECK */ +/** + * Send a mDNS answer packet. + * + * @param type of answer hostname and service registration or service + * @param name to query + * @param id transaction ID in the DNS query packet + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t ICACHE_FLASH_ATTR +mdns_answer(u16_t type, const char* name, u8_t id) { + err_t err; + struct mdns_hdr *hdr; + struct mdns_answer ans; + struct mdns_auth auth; + struct mdns_service serv; + struct pbuf *p ,*p_sta; + char *query, *nptr; + const char *pHostname; + struct netif * sta_netif = NULL; + struct netif * ap_netif = NULL; + static char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH]; + u8_t n; + u16_t length = 0; + /* if here, we have either a new query or a retry on a previous query to process */ + p = pbuf_alloc(PBUF_TRANSPORT, + SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); + /* fill dns header */ + hdr = (struct mdns_hdr*) p->payload; + os_memset(hdr, 0, SIZEOF_DNS_HDR); + hdr->id = htons(id); + hdr->flags1 = DNS_FLAG1_RESPONSE; + + if (type == MDNS_SD_ANSWER) { + pHostname = DNS_SD_SERVICE; + hdr->numanswers = htons(1); + } else if (type == MDNS_SERVICE_REG_ANSWER) { + pHostname = PUCK_SERVICE; + hdr->numanswers = htons(type); + } else { + pHostname = name; + hdr->numanswers = htons(type); + } + query = (char*) hdr + SIZEOF_DNS_HDR; + --pHostname; + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + /* fill dns query */ + + if (type == MDNS_REG_ANSWER) { + + ans.type = htons(DNS_RRTYPE_A); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(MDNS_SERVICE_TIME); + ans.len = htons(DNS_IP_ADDR_LEN); + length = DNS_IP_ADDR_LEN; + + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + /* set the local IP address */ + auth.src = host_addr.addr; + MEMCPY( query, &auth, SIZEOF_MDNS_AUTH); + } + if (type == MDNS_SD_ANSWER) { + + ans.type = htons(DNS_RRTYPE_PTR); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(300); + ans.len = htons(os_strlen(PUCK_SERVICE) + 1 +1 ); + length = 0; + + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + pHostname = PUCK_SERVICE; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + } + + if (type == MDNS_SERVICE_REG_ANSWER) { + + ans.type = htons(DNS_RRTYPE_PTR); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(MDNS_SERVICE_TIME); + os_strcpy(tmpBuf, name); + os_strcat(tmpBuf, "."); + os_strcat(tmpBuf, PUCK_SERVICE); + + length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; + ans.len = htons(length); + length = 0; + + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + pHostname = tmpBuf; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + + /* Service query*/ + pHostname = name; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + + /* Add to the service name the service local + * pointing to the beginning of the mDNS message*/ + *query++ = DNS_OFFSET_FLAG; + *query++ = DNS_DEFAULT_OFFSET; + + /* fill the query */ + + ans.type = htons(DNS_RRTYPE_SRV); + ans.class = htons(DNS_RRCLASS_FLUSH_IN); + ans.ttl = htonl(MDNS_SERVICE_TIME); + os_strcpy(tmpBuf, host_name); + os_strcat(tmpBuf, "."); + os_strcat(tmpBuf, MDNS_LOCAL); + length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; + ans.len = htons(SIZEOF_MDNS_SERVICE + length); + length = 0; + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + /* fill the service properties */ + + serv.prior = htons(0); + serv.weight = htons(0); + serv.port = htons(PUCK_PORT); + MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE); + /* resize the query */ + query = query + SIZEOF_MDNS_SERVICE; + + pHostname = tmpBuf; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + + /* TXT answer */ + pHostname = name; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + + /* Add to the service name the service local + * pointing to the beginning of the mDNS message*/ + *query++ = DNS_OFFSET_FLAG; + *query++ = DNS_DEFAULT_OFFSET; + + /* fill the answer */ + ans.type = htons(DNS_RRTYPE_TXT); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(MDNS_SERVICE_TIME); + length = sizeof(SERVICE_DESCRIPTION); + ans.len = htons(length); + length = 0; + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + pHostname = SERVICE_DESCRIPTION; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + } + /* resize pbuf to the exact dns query */ + pbuf_realloc(p, (query + length) - ((char*) (p->payload))); + + /* send dns packet */ + /*add by tzx for AP + STA MDNS begin------*/ + sta_netif = (struct netif *)eagle_lwip_getif(0x00); + ap_netif = (struct netif *)eagle_lwip_getif(0x01); + if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\ + sta_netif != NULL && ap_netif != NULL) { + if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) { + + p_sta = pbuf_alloc(PBUF_TRANSPORT, + SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); + if (pbuf_copy (p_sta,p) != ERR_OK) { + os_printf("mdns_answer copying to new pbuf failed\n"); + return -1; + } + netif_set_default(sta_netif); + err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT); + pbuf_free(p_sta); + netif_set_default(ap_netif); + } + } + /*add by tzx for AP + STA MDNS end------*/ + err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT); + /* free pbuf */ + pbuf_free(p); + } else { + err = ERR_MEM; + } + + return err; +} + +/** + * Send a mDNS service answer packet. + * + * @param name service name to query + * @param id transaction ID in the DNS query packet + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t ICACHE_FLASH_ATTR +mdns_send_service(struct mdns_info *info, u8_t id) { + err_t err; + struct mdns_hdr *hdr; + struct mdns_answer ans; + struct mdns_service serv; + struct mdns_auth auth; + struct pbuf *p ,*p_sta; + char *query, *nptr; + const char *pHostname; + char *device_info; + const char *name = info->host_name; + u8_t n; + u8_t i = 0; + u16_t length = 0; + u8_t addr1 = 12, addr2 = 12; + struct netif * sta_netif = NULL; + struct netif * ap_netif = NULL; + static char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH]; + /* if here, we have either a new query or a retry on a previous query to process */ + p = pbuf_alloc(PBUF_TRANSPORT, + SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); + /* fill dns header */ + hdr = (struct mdns_hdr*) p->payload; + os_memset(hdr, 0, SIZEOF_DNS_HDR); + hdr->id = htons(id); + hdr->flags1 = DNS_FLAG1_RESPONSE; + hdr->numanswers = htons(4); + query = (char*) hdr + SIZEOF_DNS_HDR; + os_strcpy(tmpBuf, PUCK_SERVICE); + + pHostname = tmpBuf; + --pHostname; + + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + ++addr1; + ++addr2; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++addr1; + ++addr2; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + length = sizeof(MDNS_LOCAL); + addr1 -= length; + length = os_strlen(PUCK_SERVICE) + 1; + addr2 -= length; + + ans.type = htons(DNS_RRTYPE_PTR); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(300); + os_strcpy(tmpBuf, name); + length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD + 1; + ans.len = htons(length); + length = 0; + + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + pHostname = tmpBuf; + --pHostname; + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = DNS_OFFSET_FLAG; + *query++ = DNS_DEFAULT_OFFSET; + pHostname = name; + --pHostname; + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + //*query++ = '\0'; + *query++ = DNS_OFFSET_FLAG; + *query++ = DNS_DEFAULT_OFFSET; + + /* fill the answer */ + ans.type = htons(DNS_RRTYPE_TXT); + ans.class = htons(DNS_RRCLASS_FLUSH_IN); + ans.ttl = htonl(300); +// length = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1; + device_info = (char *)os_zalloc(50); + ets_sprintf(device_info,"vendor = %s","Espressif"); + for(i = 0; i < 10 &&(info->txt_data[i] != NULL);i++) { + length += os_strlen(info->txt_data[i]); + length++; + } + length += os_strlen(device_info)+ 1 ; + ans.len = htons(length); + length = 0; + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + query = query + SIZEOF_DNS_ANSWER; + pHostname = device_info; + --pHostname; + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + i = 0; + while(info->txt_data[i] != NULL && i < 10) { + pHostname = info->txt_data[i]; + --pHostname; + /* convert hostname into suitable query format. */ + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + i++; + } +// *query++ = '\0'; + os_free(device_info); + os_strcpy(tmpBuf, name); + pHostname = tmpBuf; + --pHostname; + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + + *query++ = DNS_OFFSET_FLAG; + *query++ = DNS_DEFAULT_OFFSET; + + ans.type = htons(DNS_RRTYPE_SRV); + ans.class = htons(DNS_RRCLASS_FLUSH_IN); + ans.ttl = htonl(300); + os_strcpy(tmpBuf,service_name); + os_strcat(tmpBuf, "."); + os_strcat(tmpBuf, MDNS_LOCAL); + length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD; + ans.len = htons(SIZEOF_MDNS_SERVICE + length); + length = 0; + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + serv.prior = htons(0); + serv.weight = htons(0); + serv.port = htons(PUCK_PORT); + MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE); + /* resize the query */ + query = query + SIZEOF_MDNS_SERVICE; + + pHostname = tmpBuf; + --pHostname; + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + /* set the name of the authority field. + * The same name as the Query using the offset address*/ + os_strcpy(tmpBuf,service_name); + os_strcat(tmpBuf, "."); + os_strcat(tmpBuf, MDNS_LOCAL); + pHostname = tmpBuf; + --pHostname; + do { + ++pHostname; + nptr = query; + ++query; + for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { + *query = *pHostname; + ++query; + ++n; + } + *nptr = n; + } while (*pHostname != 0); + *query++ = '\0'; + /* set the name of the authority field. + * The same name as the Query using the offset address*/ + //*query++ = DNS_OFFSET_FLAG; + //*query++ = DNS_DEFAULT_OFFSET; + ans.type = htons(DNS_RRTYPE_A); + ans.class = htons(DNS_RRCLASS_FLUSH_IN); + ans.ttl = htonl(300); + ans.len = htons(DNS_IP_ADDR_LEN); + + MEMCPY( query, &ans, SIZEOF_DNS_ANSWER); + + /* resize the query */ + query = query + SIZEOF_DNS_ANSWER; + + /* fill the payload of the mDNS message */ + /* set the local IP address */ + auth.src = host_addr.addr; //ipAddr; + MEMCPY( query, &auth, SIZEOF_MDNS_AUTH); + /* resize the query */ + query = query + SIZEOF_MDNS_AUTH; + + /* set the name of the authority field. + * The same name as the Query using the offset address*/ + + /* resize pbuf to the exact dns query */ + pbuf_realloc(p, (query) - ((char*) (p->payload))); + /* send dns packet */ + sta_netif = (struct netif *)eagle_lwip_getif(0x00); + ap_netif = (struct netif *)eagle_lwip_getif(0x01); + if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\ + sta_netif != NULL && ap_netif != NULL) { + if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) { + + p_sta = pbuf_alloc(PBUF_TRANSPORT, + SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM); + if (pbuf_copy (p_sta,p) != ERR_OK) { + os_printf("mdns_send_service copying to new pbuf failed\n"); + return -1; + } + netif_set_default(sta_netif); + err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT); + pbuf_free(p_sta); + netif_set_default(ap_netif); + } + } + err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT); + + /* free pbuf */ + pbuf_free(p); + } else { + os_printf("ERR_MEM \n"); + err = ERR_MEM; + } + + return err; +} + +/** + * Receive input function for DNS response packets arriving for the dns UDP pcb. + * + * @params see udp.h + */ +static void ICACHE_FLASH_ATTR +mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, + u16_t port) { + u8_t i; + struct mdns_hdr *hdr; + u8_t nquestions; + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + struct mdns_info *info = (struct mdns_info *)arg; + /* is the dns message too big ? */ + if (p->tot_len > DNS_MSG_SIZE) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); + /* free pbuf and return */ + goto memerr1; + } + + /* is the dns message big enough ? */ + if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); + /* free pbuf and return */ + goto memerr1; + } + /* copy dns payload inside static buffer for processing */ + if (pbuf_copy_partial(p, mdns_payload, p->tot_len, 0) == p->tot_len) { + /* The ID in the DNS header should be our entry into the name table. */ + hdr = (struct mdns_hdr*) mdns_payload; + + i = htons(hdr->id); + if (i < DNS_TABLE_SIZE) { + + nquestions = htons(hdr->numquestions); + //nanswers = htons(hdr->numanswers); + /* if we have a question send an answer if necessary */ + if (nquestions > 0) { + /* MDNS_DS_DOES_NAME_CHECK */ + /* Check if the name in the "question" part match with the name of the MDNS DS service. */ + if (mdns_compare_name((unsigned char *) DNS_SD_SERVICE, + (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) { + /* respond with the puck service*/ + mdns_answer(MDNS_SD_ANSWER, PUCK_SERVICE, 0); + } else if (mdns_compare_name((unsigned char *) PUCK_SERVICE, + (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) { + /* respond with the puck service*/ + mdns_send_service(info, 0); + } else + goto memerr2; + } + } + } + goto memerr2; + memerr2: + os_memset(mdns_payload , 0 ,DNS_MSG_SIZE); + memerr1: + /* free pbuf */ + pbuf_free(p); + return; +} + +/** + * close the UDP pcb . + */ +void ICACHE_FLASH_ATTR +mdns_close(void) +{ + uint8 text_index = 0; + if (mdns_pcb != NULL && ms_info != NULL) { + udp_remove(mdns_pcb); + for(text_index = 0;text_index < 10;text_index++) { + if(ms_info->txt_data[text_index] != NULL) { + os_free(ms_info->txt_data[text_index]); + ms_info->txt_data[text_index] = NULL; + } + } + if (ms_info->host_name != NULL) { + os_free(ms_info->host_name); + ms_info->host_name = NULL; + } + if (ms_info->server_name != NULL) { + os_free(ms_info->server_name); + ms_info->server_name = NULL; + } + os_free(ms_info); + mdns_pcb = NULL; + ms_info = NULL; + } +} + +void ICACHE_FLASH_ATTR +mdns_set_name(const char *name) +{ + //strcpy(host_name, name); + os_strcpy(service_name, name); +} + +void ICACHE_FLASH_ATTR +mdns_enable(void) +{ + if(mdns_flag == 0) { + udp_recv(mdns_pcb, mdns_recv, NULL); + } +} + +void ICACHE_FLASH_ATTR +mdns_disable(void) +{ + if (mdns_flag == 1) { + udp_recv(mdns_pcb, NULL, NULL); + } +} + +/** + * close the UDP pcb . + */ +char* ICACHE_FLASH_ATTR +mdns_get_hostname(void) { + //strcpy(host_name, name); + char *name = host_name; + if (host_name[0] != 0 ) { + return name; + } else { + return ("Espressif"); + } +} + +void ICACHE_FLASH_ATTR +mdns_set_hostname(char *name) { + if (name == NULL) { + os_strncpy(host_name, "Espressif", os_strlen("Espressif")+3); + return; + } + if (os_strlen(name) + 3 <= MDNS_NAME_LENGTH ){ + os_strncpy(host_name, name, os_strlen(name) ); +// os_memset(host_name + os_strlen(host_name) ,0x00,3); + } else { + os_strncpy(host_name, name, MDNS_NAME_LENGTH); + } +} + +void ICACHE_FLASH_ATTR +mdns_set_servername(const char *name) { + if (name == NULL) { + PUCK_SERVICE = "_Espressif._tcp._local"; + }else { + os_sprintf(server_name ,"_%s._tcp.local",name); + PUCK_SERVICE = server_name; + } +} + +char* ICACHE_FLASH_ATTR +mdns_get_servername(void) { + char *name = PUCK_SERVICE; + if (name == NULL) { + PUCK_SERVICE = "_Espressif._tcp._local"; + } + return name; +} + +void ICACHE_FLASH_ATTR +mdns_server_unregister(void) { + struct ip_addr ap_host_addr; + struct ip_info ipconfig; + if(register_flag == 1){ + if (igmp_leavegroup(&host_addr, &multicast_addr) != ERR_OK) { + os_printf("sta udp_leave_multigrup failed!\n"); + return; + }; + if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) { + wifi_get_ip_info(SOFTAP_IF, &ipconfig); + ap_host_addr.addr = ipconfig.ip.addr; + if (igmp_leavegroup(&ap_host_addr, &multicast_addr) != ERR_OK) { + os_printf("ap udp_join_multigrup failed!\n"); + return; + }; + } + register_flag = 0; + } +} + +void ICACHE_FLASH_ATTR +mdns_server_register(void) { + + if (register_flag == 1) { + os_printf("mdns server is already registered !\n"); + return; + } else if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) { + os_printf("udp_join_multigrup failed!\n"); + return; + }; + register_flag = 1; +} + +void ICACHE_FLASH_ATTR +mdns_reg(struct mdns_info *info) { + + static uint8 i = 0; + if (i <= 3) { + mdns_send_service(info,0); + i++; + } else { + os_timer_disarm(&mdns_timer); + } +} + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (NEW IP). + */ +void ICACHE_FLASH_ATTR +mdns_init(struct mdns_info *info) { + /* initialize default DNS server address */ + multicast_addr.addr = DNS_MULTICAST_ADDRESS; + struct ip_addr ap_host_addr; + struct ip_info ipconfig; + uint8 text_index = 0; + ms_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); + if (ms_info != NULL) { + os_memcpy(ms_info,info,sizeof(struct mdns_info)); + ms_info->host_name = (char *)os_zalloc(os_strlen(info->host_name)+1); + os_memcpy(ms_info->host_name,info->host_name,os_strlen(info->host_name)); + ms_info->server_name = (char *)os_zalloc(os_strlen(info->server_name)+1); + os_memcpy(ms_info->server_name,info->server_name,os_strlen(info->server_name)); + for(text_index = 0;text_index < 10;text_index++) { + if(info->txt_data[text_index] != NULL) { + ms_info->txt_data[text_index] = (char *)os_zalloc(os_strlen(info->txt_data[text_index])+1); + os_memcpy(ms_info->txt_data[text_index],info->txt_data[text_index],os_strlen(info->txt_data[text_index])); + } else { + break; + } + + } + + } else { + os_printf("ms_info alloc failed\n"); + return; + } + if (ms_info->ipAddr == 0) { + os_printf("mdns ip error!\n "); + return; + } + host_addr.addr = ms_info->ipAddr ; + LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); + //get the datasheet from PUCK + mdns_set_hostname(ms_info->host_name); + mdns_set_servername(ms_info->server_name); + mdns_set_name(ms_info->host_name); + + // get the host name as instrumentName_serialNumber for MDNS + // set the name of the service, the same as host name + os_printf("host_name = %s\n", host_name); + os_printf("server_name = %s\n", PUCK_SERVICE); + if (ms_info->server_port == 0) + { + PUCK_PORT = 80; + } else { + PUCK_PORT = ms_info->server_port; + } + + /* initialize mDNS */ + mdns_pcb = udp_new(); + + if (mdns_pcb != NULL) { + /* join to the multicast address 224.0.0.251 */ + if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x01) { + if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) { + os_printf("sta udp_join_multigrup failed!\n"); + return; + }; + } + if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) { + wifi_get_ip_info(SOFTAP_IF, &ipconfig); + ap_host_addr.addr = ipconfig.ip.addr; + if (igmp_joingroup(&ap_host_addr, &multicast_addr) != ERR_OK) { + os_printf("ap udp_join_multigrup failed!\n"); + return; + }; + } + register_flag = 1; + /* join to any IP address at the port 5353 */ + if (udp_bind(mdns_pcb, IP_ADDR_ANY, DNS_MDNS_PORT) != ERR_OK) { + os_printf("udp_bind failed!\n"); + return; + }; + + /*loopback function for the multicast(224.0.0.251) messages received at port 5353*/ +// mdns_enable(); + udp_recv(mdns_pcb, mdns_recv, ms_info); + mdns_flag = 1; + /* + * Register the name of the instrument + */ + + os_timer_disarm(&mdns_timer); + os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info); + os_timer_arm(&mdns_timer, 1000, 1); + } +} + +#endif /* LWIP_MDNS */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mem.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mem.c new file mode 100755 index 0000000000..bf6263d977 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/mem.c @@ -0,0 +1,644 @@ +/** + * @file + * Dynamic memory manager + * + * This is a lightweight replacement for the standard C library malloc(). + * + * If you want to use the standard C library malloc() instead, define + * MEM_LIBC_MALLOC to 1 in your lwipopts.h + * + * To let mem_malloc() use pools (prevents fragmentation and is much faster than + * a heap but might waste some memory), define MEM_USE_POOLS to 1, define + * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list + * of pools like this (more pools can be added between _START and _END): + * + * Define three pools with sizes 256, 512, and 1512 bytes + * LWIP_MALLOC_MEMPOOL_START + * LWIP_MALLOC_MEMPOOL(20, 256) + * LWIP_MALLOC_MEMPOOL(10, 512) + * LWIP_MALLOC_MEMPOOL(5, 1512) + * LWIP_MALLOC_MEMPOOL_END + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/err.h" + +#include + +#if MEM_USE_POOLS +/* lwIP head implemented with different sized pools */ + +/** + * Allocate memory: determine the smallest pool that is big enough + * to contain an element of 'size' and get an element from that pool. + * + * @param size the size in bytes of the memory needed + * @return a pointer to the allocated memory or NULL if the pool is empty + */ +void * +mem_malloc(mem_size_t size) +{ + struct memp_malloc_helper *element; + memp_t poolnr; + mem_size_t required_size = size + sizeof(struct memp_malloc_helper); + + for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { +#if MEM_USE_POOLS_TRY_BIGGER_POOL +again: +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ + /* is this pool big enough to hold an element of the required size + plus a struct memp_malloc_helper that saves the pool this element came from? */ + if (required_size <= memp_sizes[poolnr]) { + break; + } + } + if (poolnr > MEMP_POOL_LAST) { + LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); + return NULL; + } + element = (struct memp_malloc_helper*)memp_malloc(poolnr); + if (element == NULL) { + /* No need to DEBUGF or ASSERT: This error is already + taken care of in memp.c */ +#if MEM_USE_POOLS_TRY_BIGGER_POOL + /** Try a bigger pool if this one is empty! */ + if (poolnr < MEMP_POOL_LAST) { + poolnr++; + goto again; + } +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ + return NULL; + } + + /* save the pool number this element came from */ + element->poolnr = poolnr; + /* and return a pointer to the memory directly after the struct memp_malloc_helper */ + element++; + + return element; +} + +/** + * Free memory previously allocated by mem_malloc. Loads the pool number + * and calls memp_free with that pool number to put the element back into + * its pool + * + * @param rmem the memory element to free + */ +void +mem_free(void *rmem) +{ + struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; + + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); + + /* get the original struct memp_malloc_helper */ + hmem--; + + LWIP_ASSERT("hmem != NULL", (hmem != NULL)); + LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); + LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); + + /* and put it in the pool we saved earlier */ + memp_free(hmem->poolnr, hmem); +} + +#else /* MEM_USE_POOLS */ +/* lwIP replacement for your libc malloc() */ + +/** + * The heap is made up as a list of structs of this type. + * This does not have to be aligned since for getting its size, + * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. + */ +struct mem { + /** index (-> ram[next]) of the next struct */ + mem_size_t next; + /** index (-> ram[prev]) of the previous struct */ + mem_size_t prev; + /** 1: this area is used; 0: this area is unused */ + u8_t used; + u8_t pad[3]; /* XXX: pad here instead use global ALIGN */ +} __ATTRIB_PACK; + +/** All allocated blocks will be MIN_SIZE bytes big, at least! + * MIN_SIZE can be overridden to suit your needs. Smaller values save space, + * larger values could prevent too small blocks to fragment the RAM too much. */ +#ifndef MIN_SIZE +#define MIN_SIZE 12 +#endif /* MIN_SIZE */ +/* some alignment macros: we define them here for better source code layout */ +#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) +#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) +#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) + +/** If you want to relocate the heap to external memory, simply define + * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. + * If so, make sure the memory at that location is big enough (see below on + * how that space is calculated). */ +#ifndef LWIP_RAM_HEAP_POINTER +/** the heap. we need one struct mem at the end and some room for alignment */ +/* enlarge heap as tx pbuf payload is allocate from heap as well */ +u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] SHMEM_ATTR; +#define LWIP_RAM_HEAP_POINTER ram_heap +#endif /* LWIP_RAM_HEAP_POINTER */ + +/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ +static u8_t *ram; +/** the last entry, always unused! */ +static struct mem *ram_end; +/** pointer to the lowest free block, this is used for faster search */ +static struct mem *lfree; + +/** concurrent access protection */ +//static sys_mutex_t mem_mutex; + +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + +static volatile u8_t mem_free_count; + +/* Allow mem_free from other (e.g. interrupt) context */ +#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) +#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) +#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) +#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) + +#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/* Protect the heap only by using a semaphore */ +#define LWIP_MEM_FREE_DECL_PROTECT() +#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) +#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) +/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ +#define LWIP_MEM_ALLOC_DECL_PROTECT() +#define LWIP_MEM_ALLOC_PROTECT() +#define LWIP_MEM_ALLOC_UNPROTECT() + +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + +/** + * "Plug holes" by combining adjacent empty struct mems. + * After this function is through, there should not exist + * one empty struct mem pointing to another empty struct mem. + * + * @param mem this points to a struct mem which just has been freed + * @internal this function is only called by mem_free() and mem_trim() + * + * This assumes access to the heap is protected by the calling function + * already. + */ +static void ICACHE_FLASH_ATTR +plug_holes(struct mem *mem) +{ + struct mem *nmem; + struct mem *pmem; + + LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); + LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); + LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); + + /* plug hole forward */ + LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); + + nmem = (struct mem *)(void *)&ram[mem->next]; + if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { + /* if mem->next is unused and not end of ram, combine mem and mem->next */ + if (lfree == nmem) { + lfree = mem; + } + mem->next = nmem->next; + ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); + } + + /* plug hole backward */ + pmem = (struct mem *)(void *)&ram[mem->prev]; + if (pmem != mem && pmem->used == 0) { + /* if mem->prev is unused, combine mem and mem->prev */ + if (lfree == mem) { + lfree = pmem; + } + pmem->next = mem->next; + ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); + } +} + +/** + * Zero the heap and initialize start, end and lowest-free + */ +void +mem_init(void) +{ + struct mem *mem; + + LWIP_ASSERT("Sanity check alignment", + (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); + + /* align the heap */ + ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); + /* initialize the start of the heap */ + mem = (struct mem *)(void *)ram; + mem->next = MEM_SIZE_ALIGNED; + mem->prev = 0; + mem->used = 0; + /* initialize the end of the heap */ + ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; + ram_end->used = 1; + ram_end->next = MEM_SIZE_ALIGNED; + ram_end->prev = MEM_SIZE_ALIGNED; + + /* initialize the lowest-free pointer to the start of the heap */ + lfree = (struct mem *)(void *)ram; + + MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); + + if(sys_mutex_new(&mem_mutex) != ERR_OK) { + LWIP_ASSERT("failed to create mem_mutex", 0); + } +} + +/** + * Put a struct mem back on the heap + * + * @param rmem is the data portion of a struct mem as returned by a previous + * call to mem_malloc() + */ +void +mem_free(void *rmem) +{ + struct mem *mem; + LWIP_MEM_FREE_DECL_PROTECT(); + + if (rmem == NULL) { + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); + return; + } + LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); + + LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + SYS_ARCH_DECL_PROTECT(lev); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); + return; + } + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + /* Get the corresponding struct mem ... */ + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + /* ... which has to be in a used state ... */ + LWIP_ASSERT("mem_free: mem->used", mem->used); + /* ... and is now unused. */ + mem->used = 0; + + if (mem < lfree) { + /* the newly freed struct is now the lowest */ + lfree = mem; + } + + MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); + + /* finally, see if prev or next are free also */ + plug_holes(mem); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); +} + +/** + * Shrink memory returned by mem_malloc(). + * + * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked + * @param newsize required size after shrinking (needs to be smaller than or + * equal to the previous size) + * @return for compatibility reasons: is always == rmem, at the moment + * or NULL if newsize is > old size, in which case rmem is NOT touched + * or freed! + */ +void * +mem_trim(void *rmem, mem_size_t newsize) +{ + mem_size_t size; + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; + /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ + LWIP_MEM_FREE_DECL_PROTECT(); + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + newsize = LWIP_MEM_ALIGN_SIZE(newsize); + + if(newsize < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + newsize = MIN_SIZE_ALIGNED; + } + + if (newsize > MEM_SIZE_ALIGNED) { + return NULL; + } + + LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + SYS_ARCH_DECL_PROTECT(lev); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); + return rmem; + } + /* Get the corresponding struct mem ... */ + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + /* ... and its offset pointer */ + ptr = (mem_size_t)((u8_t *)mem - ram); + + size = mem->next - ptr - SIZEOF_STRUCT_MEM; + LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); + if (newsize > size) { + /* not supported */ + return NULL; + } + if (newsize == size) { + /* No change in size, simply return */ + return rmem; + } + + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + + mem2 = (struct mem *)(void *)&ram[mem->next]; + if(mem2->used == 0) { + /* The next struct is unused, we can simply move it at little */ + mem_size_t next; + /* remember the old next pointer */ + next = mem2->next; + /* create new struct mem which is moved directly after the shrinked mem */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + if (lfree == mem2) { + lfree = (struct mem *)(void *)&ram[ptr2]; + } + mem2 = (struct mem *)(void *)&ram[ptr2]; + mem2->used = 0; + /* restore the next pointer */ + mem2->next = next; + /* link it back to mem */ + mem2->prev = ptr; + /* link mem to it */ + mem->next = ptr2; + /* last thing to restore linked list: as we have moved mem2, + * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not + * the end of the heap */ + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* no need to plug holes, we've already done that */ + } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { + /* Next struct is used but there's room for another struct mem with + * at least MIN_SIZE_ALIGNED of data. + * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem + * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + mem2 = (struct mem *)(void *)&ram[ptr2]; + if (mem2 < lfree) { + lfree = mem2; + } + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + mem->next = ptr2; + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* the original mem->next is used, so no need to plug holes! */ + } + /* else { + next struct mem is used but size between mem and mem2 is not big enough + to create another struct mem + -> don't do anyhting. + -> the remaining space stays unused since it is too small + } */ +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); + return rmem; +} + +/** + * Adam's mem_malloc() plus solution for bug #17922 + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size) +{ + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + u8_t local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_ALLOC_DECL_PROTECT(); + + if (size == 0) { + return NULL; + } + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + size = LWIP_MEM_ALIGN_SIZE(size); + + if(size < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + size = MIN_SIZE_ALIGNED; + } + + if (size > MEM_SIZE_ALIGNED) { + return NULL; + } + + /* protect the heap from concurrent access */ + sys_mutex_lock(&mem_mutex); + LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* run as long as a mem_free disturbed mem_malloc */ + do { + local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + /* Scan through the heap searching for a free block that is big enough, + * beginning with the lowest free block. + */ + for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; + ptr = ((struct mem *)(void *)&ram[ptr])->next) { + mem = (struct mem *)(void *)&ram[ptr]; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* allow mem_free to run */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + local_mem_free_count = mem_free_count; + } + mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + if ((!mem->used) && + (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { + /* mem is not used and at least perfect fit is possible: + * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + + if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { + /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing + * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') + * -> split large block, create empty remainder, + * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if + * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, + * struct mem would fit in but no data between mem2 and mem2->next + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory + */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + /* create mem2 struct */ + mem2 = (struct mem *)(void *)&ram[ptr2]; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + /* and insert it between mem and mem->next */ + mem->next = ptr2; + mem->used = 1; + + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); + } else { + /* (a mem2 struct does no fit into the user data space of mem and mem->next will always + * be used at this point: if not we have 2 unused structs in a row, plug_holes should have + * take care of this). + * -> near fit or excact fit: do not split, no mem2 creation + * also can't move mem->next directly behind mem, since mem->next + * will always be used at this point! + */ + mem->used = 1; + MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); + } + + if (mem == lfree) { + /* Find next free block after mem and update lowest free pointer */ + while (lfree->used && lfree != ram_end) { + LWIP_MEM_ALLOC_UNPROTECT(); + /* prevent high interrupt latency... */ + LWIP_MEM_ALLOC_PROTECT(); + lfree = (struct mem *)(void *)&ram[lfree->next]; + } + LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); + } + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", + (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); + LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", + ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); + LWIP_ASSERT("mem_malloc: sanity check alignment", + (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); + + return (u8_t *)mem + SIZEOF_STRUCT_MEM; + } + } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* if we got interrupted by a mem_free, try again */ + } while(local_mem_free_count != 0); +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); + MEM_STATS_INC(err); + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + return NULL; +} + +#endif /* MEM_USE_POOLS */ +/** + * Contiguously allocates enough space for count objects that are size bytes + * of memory each and returns a pointer to the allocated memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void *mem_calloc(mem_size_t count, mem_size_t size) +{ + void *p; + + /* allocate 'count' objects of size 'size' */ + p = mem_malloc(count * size); + if (p) { + /* zero the memory */ + os_memset(p, 0, count * size); + } + return p; +} + +#endif /* !MEM_LIBC_MALLOC */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/memp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/memp.c new file mode 100755 index 0000000000..38bdd1bed6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/memp.c @@ -0,0 +1,490 @@ +/** + * @file + * Dynamic pool memory manager + * + * lwIP has dedicated pools for many structures (netconn, protocol control blocks, + * packet buffers, ...). All these pools are managed here. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/raw.h" +#include "lwip/tcp_impl.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/api_msg.h" +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/stats.h" +#include "netif/etharp.h" +#include "lwip/ip_frag.h" +#include "lwip/snmp_structs.h" +#include "lwip/snmp_msg.h" +#include "lwip/dns.h" +#include "netif/ppp_oe.h" + +#include + +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + +struct memp { + struct memp *next; +#if MEMP_OVERFLOW_CHECK + const char *file; + int line; +#endif /* MEMP_OVERFLOW_CHECK */ +}; + +#if MEMP_OVERFLOW_CHECK +/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning + * and at the end of each element, initialize them as 0xcd and check + * them later. */ +/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, + * every single element in each pool is checked! + * This is VERY SLOW but also very helpful. */ +/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in + * lwipopts.h to change the amount reserved for checking. */ +#ifndef MEMP_SANITY_REGION_BEFORE +#define MEMP_SANITY_REGION_BEFORE 16 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#if MEMP_SANITY_REGION_BEFORE > 0 +#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) +#else +#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#ifndef MEMP_SANITY_REGION_AFTER +#define MEMP_SANITY_REGION_AFTER 16 +#endif /* MEMP_SANITY_REGION_AFTER*/ +#if MEMP_SANITY_REGION_AFTER > 0 +#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) +#else +#define MEMP_SANITY_REGION_AFTER_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_AFTER*/ + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE 0 +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + +/** This array holds the first free element of each pool. + * Elements form a linked list. */ +static struct memp *memp_tab[MEMP_MAX]; + +#else /* MEMP_MEM_MALLOC */ + +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_MEM_MALLOC */ + +/** This array holds the element sizes of each pool. */ +#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC +static +#endif +const u32_t memp_sizes[MEMP_MAX] ICACHE_RODATA_ATTR = { //LWIP_MEM_ALIGN_SIZE +#define LWIP_MEMPOOL(name,num,size,desc,attr) LWIP_MEM_ALIGN_SIZE(size), +#include "lwip/memp_std.h" +}; + +u16_t memp_sizes_test[1] = {PBUF_POOL_BUFSIZE,}; + +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + +/** This array holds the number of elements in each pool. */ +static const u16_t memp_num[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc,attr) (num), +#include "lwip/memp_std.h" +}; + +/** This array holds a textual description of each pool. */ +//#ifdef LWIP_DEBUG +//static const char *memp_desc[MEMP_MAX] = { +const char *memp_desc[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc,attr) (desc), +#include "lwip/memp_std.h" +}; +//#endif /* LWIP_DEBUG */ + +#if MEMP_SEPARATE_POOLS + +/** This creates each memory pool. These are named memp_memory_XXX_base (where + * XXX is the name of the pool defined in memp_std.h). + * To relocate a pool, declare it as extern in cc.h. Example for GCC: + * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[]; + */ +#define LWIP_MEMPOOL(name,num,size,desc,attr) u8_t memp_memory_ ## name ## _base \ + [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))] attr; +#include "lwip/memp_std.h" + +/** This array holds the base of each memory pool. */ +static u8_t *const memp_bases[] = { +#define LWIP_MEMPOOL(name,num,size,desc,attr) memp_memory_ ## name ## _base, +#include "lwip/memp_std.h" +}; + +#else /* MEMP_SEPARATE_POOLS */ + +/** This is the actual memory used by the pools (all pools in one big block). */ +static u8_t memp_memory[MEM_ALIGNMENT - 1 +#define LWIP_MEMPOOL(name,num,size,desc, attr) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) +#include "lwip/memp_std.h" +]; + +#endif /* MEMP_SEPARATE_POOLS */ + +#if MEMP_SANITY_CHECK +/** + * Check that memp-lists don't form a circle, modify by ives at 2014.4.23. + */ +static int ICACHE_FLASH_ATTR +memp_sanity(void) +{ + s16_t i; + struct memp *t, *h; + + for (i = 0; i < MEMP_MAX; i++) { + t = memp_tab[i]; + if(t != NULL) { + for (h = t->next; (t != NULL) && (h != NULL); t = t->next, + h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) { + if (t == h) { + return 0; + } + } + } + } + return 1; +} +#endif /* MEMP_SANITY_CHECK*/ +#if MEMP_OVERFLOW_CHECK +#if defined(LWIP_DEBUG) && MEMP_STATS +static const char * memp_overflow_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc,attr) "/"desc, +#include "lwip/memp_std.h" + }; +#endif + +/** + * Check if a memp element was victim of an overflow + * (e.g. the restricted area after it has been altered) + * + * @param p the memp element to check + * @param memp_type the pool p comes from + */ +static void ICACHE_FLASH_ATTR +memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) +{ + u16_t k; + u8_t *m; +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; + for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128] = "detected memp overflow in pool "; + char digit[] = "0"; + if(memp_type >= 10) { + digit[0] = '0' + (memp_type/10); + strcat(errstr, digit); + } + digit[0] = '0' + (memp_type%10); + strcat(errstr, digit); +#if defined(LWIP_DEBUG) && MEMP_STATS + strcat(errstr, memp_overflow_names[memp_type]); +#endif + LWIP_ASSERT(errstr, 0); + } + } +#endif +} + +/** + * Check if a memp element was victim of an underflow + * (e.g. the restricted area before it has been altered) + * + * @param p the memp element to check + * @param memp_type the pool p comes from + */ +static void ICACHE_FLASH_ATTR +memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) +{ + u16_t k; + u8_t *m; +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; + for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128] = "detected memp underflow in pool "; + char digit[] = "0"; + if(memp_type >= 10) { + digit[0] = '0' + (memp_type/10); + strcat(errstr, digit); + } + digit[0] = '0' + (memp_type%10); + strcat(errstr, digit); +#if defined(LWIP_DEBUG) && MEMP_STATS + strcat(errstr, memp_overflow_names[memp_type]); +#endif + LWIP_ASSERT(errstr, 0); + } + } +#endif +} + +/** + * Do an overflow check for all elements in every pool. + * + * @see memp_overflow_check_element for a description of the check + */ +static void ICACHE_FLASH_ATTR +memp_overflow_check_all(void) +{ + u16_t i, j; + struct memp *p; + + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { + memp_overflow_check_element_overflow(p, i); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); + } + } + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { + memp_overflow_check_element_underflow(p, i); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); + } + } +} + +/** + * Initialize the restricted areas of all memp elements in every pool. + */ +static void ICACHE_FLASH_ATTR +memp_overflow_init(void) +{ + u16_t i, j; + struct memp *p; + u8_t *m; + + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; + os_memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); +#endif +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; + os_memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); +#endif + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); + } + } +} +#endif /* MEMP_OVERFLOW_CHECK */ + +/** + * Initialize this module. + * + * Carves out memp_memory into linked lists for each pool-type. + */ +void +memp_init(void) +{ + struct memp *memp; + u16_t i, j; + + for (i = 0; i < MEMP_MAX; ++i) { + MEMP_STATS_AVAIL(used, i, 0); + MEMP_STATS_AVAIL(max, i, 0); + MEMP_STATS_AVAIL(err, i, 0); + MEMP_STATS_AVAIL(avail, i, memp_num[i]); + } + +#if !MEMP_SEPARATE_POOLS + memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory); +#endif /* !MEMP_SEPARATE_POOLS */ + /* for every pool: */ + for (i = 0; i < MEMP_MAX; ++i) { + memp_tab[i] = NULL; +#if MEMP_SEPARATE_POOLS + memp = (struct memp*)memp_bases[i]; +#endif /* MEMP_SEPARATE_POOLS */ + /* create a linked list of memp elements */ + for (j = 0; j < memp_num[i]; ++j) { + memp->next = (struct memp *)memp_tab[i]; + memp_tab[i] = memp; + memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] +#if MEMP_OVERFLOW_CHECK + + MEMP_SANITY_REGION_AFTER_ALIGNED +#endif + ); + } + } +#if MEMP_OVERFLOW_CHECK + memp_overflow_init(); + /* check everything a first time to see if it worked */ + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK */ +} + +/** + * Get an element from a specific pool. + * + * @param type the pool to get an element from + * + * the debug version has two more parameters: + * @param file file name calling this function + * @param line number of line where this function is called + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc(memp_t type) +#else +memp_malloc_fn(memp_t type, const char* file, const int line) +#endif +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); + + SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + + memp = memp_tab[type]; + + if (memp != NULL) { + memp_tab[type] = memp->next; +#if MEMP_OVERFLOW_CHECK + memp->next = NULL; + memp->file = file; + memp->line = line; +#endif /* MEMP_OVERFLOW_CHECK */ + MEMP_STATS_INC_USED(used, type); + LWIP_ASSERT("memp_malloc: memp properly aligned", + ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); + memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE); + } else { + LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); + MEMP_STATS_INC(err, type); + } + + SYS_ARCH_UNPROTECT(old_level); + + return memp; +} + +/** + * Put an element back into its pool. + * + * @param type the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free(memp_t type, void *mem) +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + + if (mem == NULL) { + return; + } + LWIP_ASSERT("memp_free: mem properly aligned", + ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); + + memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); + + SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#else + memp_overflow_check_element_overflow(memp, type); + memp_overflow_check_element_underflow(memp, type); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +#endif /* MEMP_OVERFLOW_CHECK */ + + MEMP_STATS_DEC(used, type); + + memp->next = memp_tab[type]; + memp_tab[type] = memp; + +#if MEMP_SANITY_CHECK + LWIP_ASSERT("memp sanity", memp_sanity()); +#endif /* MEMP_SANITY_CHECK */ + + SYS_ARCH_UNPROTECT(old_level); +} + +#endif /* MEMP_MEM_MALLOC */ +#if 0 +void memp_dump(void) +{ + printf("sizeof raw_pcb %u, memp_s1 %u, %s\n", sizeof(struct raw_pcb), memp_sizes[0], memp_desc[0]); + printf("sizeof udp_pcb %u, memp_s2 %u, %s\n", sizeof(struct udp_pcb), memp_sizes[1], memp_desc[1]); + printf("sizeof tcp_pcb %u, memp_s3 %u, %s\n", sizeof(struct tcp_pcb), memp_sizes[2], memp_desc[2]); + printf("sizeof tcp_pcb_listen %u, memp_s4 %u, %s\n", sizeof(struct tcp_pcb_listen), memp_sizes[3], memp_desc[3]); + printf("sizeof tcp_seg %u, memp_s5 %u, %s\n", sizeof(struct tcp_seg), memp_sizes[4], memp_desc[4]); + printf("sizeof sys_timeo %u, memp_s6 %u, %s\n", sizeof(struct sys_timeo), memp_sizes[5], memp_desc[5]); + printf("sizeof pbuf %u, memp_s7 %u, %s\n", sizeof(struct pbuf), memp_sizes[6], memp_desc[6]); + printf("align pbuf size %u, memp_s8 %u, %s\n", (PBUF_POOL_BUFSIZE), memp_sizes[7], memp_desc[7]); + printf("TCP_MSS %d PBUF_LINK_HLEN %d ETH_PAD_SIZE %d\n", TCP_MSS, PBUF_LINK_HLEN, ETH_PAD_SIZE); + printf("TCP_MSS + PBUF_LINK_HLEN + ETH_PAD_SIZE %d \n", TCP_MSS+PBUF_LINK_HLEN+ETH_PAD_SIZE+40); + printf("test size %u\n",memp_sizes_test[0]); + printf("sizeof memp_memory_PBUF_pool %u \n", sizeof(memp_memory_PBUF_POOL_base)); +} +#endif //0000 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/netif.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/netif.c new file mode 100755 index 0000000000..cb6b6a84e6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/netif.c @@ -0,0 +1,762 @@ +/** + * @file + * lwIP network interface abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/tcp_impl.h" +#include "lwip/snmp.h" +#include "lwip/igmp.h" +#include "netif/etharp.h" +#include "lwip/stats.h" +#if ENABLE_LOOPBACK +#include "lwip/sys.h" +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/tcpip.h" +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_AUTOIP +#include "lwip/autoip.h" +#endif /* LWIP_AUTOIP */ +#if LWIP_DHCP +#include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ + +#if LWIP_NETIF_STATUS_CALLBACK +#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) +#else +#define NETIF_STATUS_CALLBACK(n) +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) +#else +#define NETIF_LINK_CALLBACK(n) +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +struct netif *netif_list; +struct netif *netif_default; + +#if LWIP_HAVE_LOOPIF +static struct netif loop_netif; + +/** + * Initialize a lwip network interface structure for a loopback interface + * + * @param netif the lwip network interface structure for this loopif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + */ + static err_t ICACHE_FLASH_ATTR +netif_loopif_init(struct netif *netif) +{ + /* initialize the snmp variables and counters inside the struct netif + * ifSpeed: no assumption can be made! + */ + NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); + + netif->name[0] = 'l'; + netif->name[1] = 'o'; + netif->output = netif_loop_output; + return ERR_OK; +} +#endif /* LWIP_HAVE_LOOPIF */ + +void +netif_init(void) +{ +#if LWIP_HAVE_LOOPIF + ip_addr_t loop_ipaddr, loop_netmask, loop_gw; + IP4_ADDR(&loop_gw, 127,0,0,1); + IP4_ADDR(&loop_ipaddr, 127,0,0,1); + IP4_ADDR(&loop_netmask, 255,0,0,0); + +#if NO_SYS + netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); +#else /* NO_SYS */ + netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); +#endif /* NO_SYS */ + netif_set_up(&loop_netif); + +#endif /* LWIP_HAVE_LOOPIF */ +} + +/** + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack. + * + * @return netif, or NULL if failed. + */ +struct netif * +netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) +{ + static u8_t netifnum = 0; + + LWIP_ASSERT("No init function given", init != NULL); + + /* reset new interface configuration state */ + ip_addr_set_zero(&netif->ip_addr); + ip_addr_set_zero(&netif->netmask); + ip_addr_set_zero(&netif->gw); + netif->flags = 0; +#if LWIP_DHCP + /* netif not under DHCP control by default */ + netif->dhcp = NULL; + netif->dhcps_pcb = NULL; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /* netif not under AutoIP control by default */ + netif->autoip = NULL; +#endif /* LWIP_AUTOIP */ +#if LWIP_NETIF_STATUS_CALLBACK + netif->status_callback = NULL; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif->link_callback = NULL; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_IGMP + netif->igmp_mac_filter = NULL; +#endif /* LWIP_IGMP */ +#if ENABLE_LOOPBACK + netif->loop_first = NULL; + netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK */ + + /* remember netif specific state information data */ + netif->state = state; + netif->num = netifnum++; + netif->input = input; +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS + netif->loop_cnt_current = 0; +#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ + + netif_set_addr(netif, ipaddr, netmask, gw); + + /* call user specified initialization function for netif */ + if (init(netif) != ERR_OK) { + return NULL; + } + + /* add this netif to the list */ + netif->next = netif_list; + netif_list = netif; + snmp_inc_iflist(); + +#if LWIP_IGMP + /* start IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_start(netif); + } +#endif /* LWIP_IGMP */ + + LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", + netif->name[0], netif->name[1])); + ip_addr_debug_print(NETIF_DEBUG, ipaddr); + LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); + ip_addr_debug_print(NETIF_DEBUG, netmask); + LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); + ip_addr_debug_print(NETIF_DEBUG, gw); + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); + return netif; +} + +/** + * Change IP address configuration for a network interface (including netmask + * and default gateway). + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * @param netmask the new netmask + * @param gw the new default gateway + */ +void +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw) +{ + netif_set_ipaddr(netif, ipaddr); + netif_set_netmask(netif, netmask); + netif_set_gw(netif, gw); +} + +/** + * Remove a network interface from the list of lwIP netifs. + * + * @param netif the network interface to remove + */ +void +netif_remove(struct netif *netif) +{ + if (netif == NULL) { + return; + } + +#if LWIP_IGMP + /* stop IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_stop(netif); + } +#endif /* LWIP_IGMP */ + if (netif_is_up(netif)) { + /* set netif down before removing (call callback function) */ + netif_set_down(netif); + } + + snmp_delete_ipaddridx_tree(netif); + + /* is it the first netif? */ + if (netif_list == netif) { + netif_list = netif->next; + } else { + /* look for netif further down the list */ + struct netif * tmpNetif; + for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { + if (tmpNetif->next == netif) { + tmpNetif->next = netif->next; + break; + } + } + if (tmpNetif == NULL) + return; /* we didn't find any netif today */ + } + snmp_dec_iflist(); + /* this netif is default? */ + if (netif_default == netif) { + /* reset default netif */ + netif_set_default(NULL); + } + LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); +} + +/** + * Find a network interface by searching for its name + * + * @param name the name of the netif (like netif->name) plus concatenated number + * in ascii representation (e.g. 'en0') + */ +struct netif * +netif_find(char *name) +{ + struct netif *netif; + u8_t num; + + if (name == NULL) { + return NULL; + } + + num = name[2] - '0'; + + for(netif = netif_list; netif != NULL; netif = netif->next) { + if (num == netif->num && + name[0] == netif->name[0] && + name[1] == netif->name[1]) { + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); + return netif; + } + } + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); + return NULL; +} + +/** + * Change the IP address of a network interface + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * + * @note call netif_set_addr() if you also want to change netmask and + * default gateway + */ +void +netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) +{ + /* TODO: Handling of obsolete pcbs */ + /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ +#if LWIP_TCP + struct tcp_pcb *pcb; + struct tcp_pcb_listen *lpcb; + + /* address is actually being changed? */ + if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { + /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); + pcb = tcp_active_pcbs; + while (pcb != NULL) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && !ip_addr_islinklocal(&(pcb->local_ip)) +#endif /* LWIP_AUTOIP */ + ) { + /* this connection must be aborted */ + struct tcp_pcb *next = pcb->next; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); + tcp_abort(pcb); + pcb = next; + } else { + pcb = pcb->next; + } + } + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + /* PCB bound to current local interface address? */ + if ((!(ip_addr_isany(&(lpcb->local_ip)))) && + (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { + /* The PCB is listening to the old ipaddr and + * is set to listen to the new one instead */ + ip_addr_set(&(lpcb->local_ip), ipaddr); + } + } + } +#endif + snmp_delete_ipaddridx_tree(netif); + snmp_delete_iprteidx_tree(0,netif); + /* set new IP address to netif */ + ip_addr_set(&(netif->ip_addr), ipaddr); + snmp_insert_ipaddridx_tree(netif); + snmp_insert_iprteidx_tree(0,netif); + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(&netif->ip_addr), + ip4_addr2_16(&netif->ip_addr), + ip4_addr3_16(&netif->ip_addr), + ip4_addr4_16(&netif->ip_addr))); +} + +/** + * Change the default gateway for a network interface + * + * @param netif the network interface to change + * @param gw the new default gateway + * + * @note call netif_set_addr() if you also want to change ip address and netmask + */ +void +netif_set_gw(struct netif *netif, ip_addr_t *gw) +{ + ip_addr_set(&(netif->gw), gw); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(&netif->gw), + ip4_addr2_16(&netif->gw), + ip4_addr3_16(&netif->gw), + ip4_addr4_16(&netif->gw))); +} + +/** + * Change the netmask of a network interface + * + * @param netif the network interface to change + * @param netmask the new netmask + * + * @note call netif_set_addr() if you also want to change ip address and + * default gateway + */ +void +netif_set_netmask(struct netif *netif, ip_addr_t *netmask) +{ + snmp_delete_iprteidx_tree(0, netif); + /* set new netmask to netif */ + ip_addr_set(&(netif->netmask), netmask); + snmp_insert_iprteidx_tree(0, netif); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(&netif->netmask), + ip4_addr2_16(&netif->netmask), + ip4_addr3_16(&netif->netmask), + ip4_addr4_16(&netif->netmask))); +} + +/** + * Set a network interface as the default network interface + * (used to output all packets for which no specific route is found) + * + * @param netif the default network interface + */ +void +netif_set_default(struct netif *netif) +{ + if (netif == NULL) { + /* remove default route */ + snmp_delete_iprteidx_tree(1, netif); + } else { + /* install default route */ + snmp_insert_iprteidx_tree(1, netif); + } + netif_default = netif; + LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", + netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); +} + +/** + * Bring an interface up, available for processing + * traffic. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_up(struct netif *netif) +{ + if (!(netif->flags & NETIF_FLAG_UP)) { + netif->flags |= NETIF_FLAG_UP; + +#if LWIP_SNMP + snmp_get_sysuptime(&netif->ts); +#endif /* LWIP_SNMP */ + + NETIF_STATUS_CALLBACK(netif); + + if (netif->flags & NETIF_FLAG_LINK_UP) { +#if LWIP_ARP + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & (NETIF_FLAG_ETHARP)) { + etharp_gratuitous(netif); + } +#endif /* LWIP_ARP */ + +#if LWIP_IGMP + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups( netif); + } +#endif /* LWIP_IGMP */ + } + } +} + +/** + * Bring an interface down, disabling any traffic processing. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_down(struct netif *netif) +{ + if (netif == NULL) { + return; + } + + if (netif->flags & NETIF_FLAG_UP) { + netif->flags &= ~NETIF_FLAG_UP; +#if LWIP_SNMP + snmp_get_sysuptime(&netif->ts); +#endif + +#if LWIP_ARP + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_cleanup_netif(netif); + } +#endif /* LWIP_ARP */ + NETIF_STATUS_CALLBACK(netif); + } +} + +#if LWIP_NETIF_STATUS_CALLBACK +/** + * Set callback to be called when interface is brought up/down + */ +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) +{ + if (netif) { + netif->status_callback = status_callback; + } +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +/** + * Called by a driver when its link goes up + */ +void netif_set_link_up(struct netif *netif ) +{ + if (!(netif->flags & NETIF_FLAG_LINK_UP)) { + netif->flags |= NETIF_FLAG_LINK_UP; + +#if LWIP_DHCP + if (netif->dhcp) { + dhcp_network_changed(netif); + } +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP + if (netif->autoip) { + autoip_network_changed(netif); + } +#endif /* LWIP_AUTOIP */ + + if (netif->flags & NETIF_FLAG_UP) { +#if LWIP_ARP + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_gratuitous(netif); + } +#endif /* LWIP_ARP */ + +#if LWIP_IGMP + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups( netif); + } +#endif /* LWIP_IGMP */ + } + NETIF_LINK_CALLBACK(netif); + } +} + +/** + * Called by a driver when its link goes down + */ +void netif_set_link_down(struct netif *netif ) +{ + if (netif->flags & NETIF_FLAG_LINK_UP) { + netif->flags &= ~NETIF_FLAG_LINK_UP; + NETIF_LINK_CALLBACK(netif); + } +} + +#if LWIP_NETIF_LINK_CALLBACK +/** + * Set callback to be called when link is brought up/down + */ +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) +{ + if (netif) { + netif->link_callback = link_callback; + } +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is simply copied and handed back to netif->input. + * In multithreaded mode, this is done directly since netif->input must put + * the packet on a queue. + * In callback mode, the packet is put on an internal queue and is fed to + * netif->input by netif_poll(). + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @param ipaddr the ip address to send the packet to (not used) + * @return ERR_OK if the packet has been sent + * ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr) +{ + struct pbuf *r; + err_t err; + struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if LWIP_SNMP +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* LWIP_SNMP */ + SYS_ARCH_DECL_PROTECT(lev); + LWIP_UNUSED_ARG(ipaddr); + + /* Allocate a new pbuf */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); + return ERR_MEM; + } +#if LWIP_LOOPBACK_MAX_PBUFS + clen = pbuf_clen(r); + /* check for overflow or too many pbuf on queue */ + if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || + ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); + return ERR_MEM; + } + netif->loop_cnt_current += clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* Copy the whole pbuf queue p into the single pbuf r */ + if ((err = pbuf_copy(r, p)) != ERR_OK) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); + return err; + } + + /* Put the packet on a linked list which gets emptied through calling + netif_poll(). */ + + /* let last point to the last pbuf in chain r */ + for (last = r; last->next != NULL; last = last->next); + + SYS_ARCH_PROTECT(lev); + if(netif->loop_first != NULL) { + LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); + netif->loop_last->next = r; + netif->loop_last = last; + } else { + netif->loop_first = r; + netif->loop_last = last; + } + SYS_ARCH_UNPROTECT(lev); + + LINK_STATS_INC(link.xmit); + snmp_add_ifoutoctets(stats_if, p->tot_len); + snmp_inc_ifoutucastpkts(stats_if); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* For multithreading environment, schedule a call to netif_poll */ + tcpip_callback((tcpip_callback_fn)netif_poll, netif); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + + return ERR_OK; +} + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ + struct pbuf *in; + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if LWIP_SNMP +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* LWIP_SNMP */ + SYS_ARCH_DECL_PROTECT(lev); + + do { + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + in = netif->loop_first; + if (in != NULL) { + struct pbuf *in_end = in; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = pbuf_clen(in); + /* adjust the number of pbufs on queue */ + LWIP_ASSERT("netif->loop_cnt_current underflow", + ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); + netif->loop_cnt_current -= clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + while (in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; + } + /* 'in_end' now points to the last pbuf from 'in' */ + if (in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; + } + SYS_ARCH_UNPROTECT(lev); + + if (in != NULL) { + LINK_STATS_INC(link.recv); + snmp_add_ifinoctets(stats_if, in->tot_len); + snmp_inc_ifinucastpkts(stats_if); + /* loopback packets are always IP packets! */ + if (ip_input(in, netif) != ERR_OK) { + pbuf_free(in); + } + /* Don't reference the packet any more! */ + in = NULL; + } + /* go on while there is a packet on the list */ + } while (netif->loop_first != NULL); +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ + struct netif *netif = netif_list; + /* loop through netifs */ + while (netif != NULL) { + netif_poll(netif); + /* proceed to next network interface */ + netif = netif->next; + } +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/pbuf.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/pbuf.c new file mode 100755 index 0000000000..61967840d3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/pbuf.c @@ -0,0 +1,1257 @@ +/** + * @file + * Packet buffer management + * + * Packets are built from the pbuf data structure. It supports dynamic + * memory allocation for packet contents or can reference externally + * managed packet contents both in RAM and ROM. Quick allocation for + * incoming packets is provided through pools with fixed sized pbufs. + * + * A packet may span over multiple pbufs, chained as a singly linked + * list. This is called a "pbuf chain". + * + * Multiple packets may be queued, also using this singly linked list. + * This is called a "packet queue". + * + * So, a packet queue consists of one or more pbuf chains, each of + * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE + * NOT SUPPORTED!!! Use helper structs to queue multiple packets. + * + * The differences between a pbuf chain and a packet queue are very + * precise but subtle. + * + * The last pbuf of a packet has a ->tot_len field that equals the + * ->len field. It can be found by traversing the list. If the last + * pbuf of a packet has a ->next field other than NULL, more packets + * are on the queue. + * + * Therefore, looping through a pbuf of a single packet, has an + * loop end condition (tot_len == p->len), NOT (next == NULL). + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "arch/perf.h" +#if TCP_QUEUE_OOSEQ +#include "lwip/tcp_impl.h" +#endif +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#ifdef EBUF_LWIP +#define EP_OFFSET 36 +#else +#define EP_OFFSET 0 +#endif /* ESF_LWIP */ + +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) +/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically + aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ +#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + +/** + * Attempt to reclaim some memory from queued out-of-sequence TCP segments + * if we run out of pool pbufs. It's better to give priority to new packets + * if we're running out. + */ +#if TCP_QUEUE_OOSEQ +void ICACHE_FLASH_ATTR +pbuf_free_ooseq_new(void* arg) +{ + struct tcp_pcb* pcb; + struct tcp_seg *head = NULL; + struct tcp_seg *seg1 = NULL; + struct tcp_seg *seg2 = NULL; + for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { + head = pcb->ooseq; + seg1 = head; + if (head != NULL) { + if (seg1->next == NULL){ + head = head->next; + tcp_seg_free(seg1); + pcb->ooseq = head; + } else { + while (seg1 != NULL){ + seg2 = seg1; + seg2 = seg2->next; + if (seg2 ->next == NULL){ + seg1->next = seg2->next; + tcp_seg_free(seg2); + break; + } + seg1 = seg1->next; + } + pcb->ooseq = head; + } + } + } +} +#endif + +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS +#define PBUF_POOL_IS_EMPTY() +#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ +/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ +#ifndef PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_FREE_OOSEQ 1 +#endif /* PBUF_POOL_FREE_OOSEQ */ + +#if PBUF_POOL_FREE_OOSEQ +#include "lwip/tcpip.h" +#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() +static u8_t pbuf_free_ooseq_queued; +/** + * Attempt to reclaim some memory from queued out-of-sequence TCP segments + * if we run out of pool pbufs. It's better to give priority to new packets + * if we're running out. + * + * This must be done in the correct thread context therefore this function + * can only be used with NO_SYS=0 and through tcpip_callback. + */ +static void ICACHE_FLASH_ATTR +pbuf_free_ooseq(void* arg) +{ + struct tcp_pcb* pcb; + SYS_ARCH_DECL_PROTECT(old_level); + LWIP_UNUSED_ARG(arg); + + SYS_ARCH_PROTECT(old_level); + pbuf_free_ooseq_queued = 0; + SYS_ARCH_UNPROTECT(old_level); + + for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { + if (NULL != pcb->ooseq) { + /** Free the ooseq pbufs of one PCB only */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + return; + } + } +} + +/** Queue a call to pbuf_free_ooseq if not already queued. */ +static void ICACHE_FLASH_ATTR +pbuf_pool_is_empty(void) +{ + u8_t queued; + SYS_ARCH_DECL_PROTECT(old_level); + + SYS_ARCH_PROTECT(old_level); + queued = pbuf_free_ooseq_queued; + pbuf_free_ooseq_queued = 1; + SYS_ARCH_UNPROTECT(old_level); + + if(!queued) { + /* queue a call to pbuf_free_ooseq if not already queued */ + if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) { + SYS_ARCH_PROTECT(old_level); + pbuf_free_ooseq_queued = 0; + SYS_ARCH_UNPROTECT(old_level); + } + } +} +#endif /* PBUF_POOL_FREE_OOSEQ */ +#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ + +/** + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + * chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + * protocol headers. Additional headers must be prepended + * by allocating another pbuf and chain in to the front of + * the ROM pbuf. It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + * protocol headers. It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ +struct pbuf * +pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) +{ + struct pbuf *p, *q, *r; + u16_t offset; + s32_t rem_len; /* remaining length */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); + + /* determine header offset */ + offset = 0; + switch (layer) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset += PBUF_TRANSPORT_HLEN; + /* FALLTHROUGH */ + case PBUF_IP: + /* add room for IP layer header */ + offset += PBUF_IP_HLEN; + /* FALLTHROUGH */ + case PBUF_LINK: + /* add room for link layer header */ + offset += PBUF_LINK_HLEN; + +#ifdef PBUF_RSV_FOR_WLAN + /* + * 1. LINK_HLEN 14Byte will be remove in WLAN layer + * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes. + * 3. encryption needs exra 4 bytes ahead of actual data payload, and require + * DAddr and SAddr to be 4-byte aligned. + * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice... + * 5. LCC add 6 bytes more, We don't consider WAPI yet... + * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be + * matter is ether_hdr is not 4B aligned. + * + * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned + * + * 1. lwip + * | empty 30B | eth_hdr (14B) | payload ...| + * total: 44B ahead payload + * 2. net80211 + * | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...| + * total: 40B ahead sec_rsv and 44B ahead payload + * + */ + offset += EP_OFFSET; //remove LINK hdr in wlan +#endif /* PBUF_RSV_FOR_WLAN */ + + break; + case PBUF_RAW: +#ifdef PBUF_RSV_FOR_WLAN + /* + * RAW pbuf suppose + */ + offset += EP_OFFSET; //remove LINK hdr in wlan +#endif /* PBUF_RAW */ + break; + default: + LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); + return NULL; + } + + switch (type) { + case PBUF_POOL: + /* allocate head of pbuf chain into p */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); + if (p == NULL) { + PBUF_POOL_IS_EMPTY(); + return NULL; + } + p->type = type; + p->next = NULL; + + /* make the payload pointer point 'offset' bytes into pbuf data memory */ + p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); + LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + /* the total length of the pbuf chain is the requested size */ + p->tot_len = length; + /* set the length of the first pbuf in the chain */ + p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); + LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", + ((u8_t*)p->payload + p->len <= + (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); + LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", + (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); + /* set reference count (needed here in case we fail) */ + p->ref = 1; + + /* now allocate the tail of the pbuf chain */ + + /* remember first pbuf for linkage in next iteration */ + r = p; + /* remaining length to be allocated */ + rem_len = length - p->len; + /* any remaining pbufs to be allocated? */ + while (rem_len > 0) { + q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + if (q == NULL) { + PBUF_POOL_IS_EMPTY(); + /* free chain so far allocated */ + pbuf_free(p); + /* bail out unsuccesfully */ + return NULL; + } + q->type = type; + q->flags = 0; + q->next = NULL; + /* make previous pbuf point to this pbuf */ + r->next = q; + /* set total length of this pbuf and next in chain */ + LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); + q->tot_len = (u16_t)rem_len; + /* this pbuf length is pool size, unless smaller sized tail */ + q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); + q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); + LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", + ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", + ((u8_t*)p->payload + p->len <= + (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); + q->ref = 1; + /* calculate remaining length to be allocated */ + rem_len -= q->len; + /* remember this pbuf for linkage in next iteration */ + r = q; + } + /* end of chain */ + /*r->next = NULL;*/ + + break; + case PBUF_RAM: + /* If pbuf is to be allocated in RAM, allocate memory for it. */ + p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); + if (p == NULL) { + return NULL; + } + /* Set up internal structure of the pbuf. */ + p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + p->eb = NULL; + + LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + break; +#ifdef EBUF_LWIP + case PBUF_ESF_RX: +#endif /* ESF_LWIP */ + /* pbuf references existing (non-volatile static constant) ROM payload? */ + case PBUF_ROM: + /* pbuf references existing (externally allocated) RAM payload? */ + case PBUF_REF: + /* only allocate memory for the pbuf structure */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF); + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", + (type == PBUF_ROM) ? "ROM" : "REF")); + return NULL; + } + /* caller must set this field properly, afterwards */ + p->payload = NULL; + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + break; + default: + LWIP_ASSERT("pbuf_alloc: erroneous type", 0); + return NULL; + } + /* set reference count */ + p->ref = 1; + /* set flags */ + p->flags = 0; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); + + return p; +} + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Initialize a custom pbuf (already allocated). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type type of the pbuf (only used to treat the pbuf accordingly, as + * this function allocates no memory) + * @param p pointer to the custom pbuf to initialize (already allocated) + * @param payload_mem pointer to the buffer that is used for payload and headers, + * must be at least big enough to hold 'length' plus the header size, + * may be NULL if set later + * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least + * big enough to hold 'length' plus the header size + */ +struct pbuf* +pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, + void *payload_mem, u16_t payload_mem_len) +{ + u16_t offset; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); + + /* determine header offset */ + offset = 0; + switch (l) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset += PBUF_TRANSPORT_HLEN; + /* FALLTHROUGH */ + case PBUF_IP: + /* add room for IP layer header */ + offset += PBUF_IP_HLEN; + /* FALLTHROUGH */ + case PBUF_LINK: + /* add room for link layer header */ + offset += PBUF_LINK_HLEN; + break; + case PBUF_RAW: + break; + default: + LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); + return NULL; + } + + if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); + return NULL; + } + + p->pbuf.next = NULL; + if (payload_mem != NULL) { + p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset)); + } else { + p->pbuf.payload = NULL; + } + p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; + p->pbuf.len = p->pbuf.tot_len = length; + p->pbuf.type = type; + p->pbuf.ref = 1; + return &p->pbuf; +} +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** + * Shrink a pbuf chain to a desired length. + * + * @param p pbuf to shrink. + * @param new_len desired new length of pbuf chain + * + * Depending on the desired length, the first few pbufs in a chain might + * be skipped and left unchanged. The new last pbuf in the chain will be + * resized, and any remaining pbufs will be freed. + * + * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. + * @note May not be called on a packet queue. + * + * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). + */ +void +pbuf_realloc(struct pbuf *p, u16_t new_len) +{ + struct pbuf *q; + u16_t rem_len; /* remaining length */ + s32_t grow; + + LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); + LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || + p->type == PBUF_ROM || + p->type == PBUF_RAM || + p->type == PBUF_REF); + + /* desired length larger than current length? */ + if (new_len >= p->tot_len) { + /* enlarging not yet supported */ + return; + } + + /* the pbuf chain grows by (new_len - p->tot_len) bytes + * (which may be negative in case of shrinking) */ + grow = new_len - p->tot_len; + + /* first, step over any pbufs that should remain in the chain */ + rem_len = new_len; + q = p; + /* should this pbuf be kept? */ + while (rem_len > q->len) { + /* decrease remaining length by pbuf length */ + rem_len -= q->len; + /* decrease total length indicator */ + LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); + q->tot_len += (u16_t)grow; + /* proceed to next pbuf in chain */ + q = q->next; + LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); + } + /* we have now reached the new last pbuf (in q) */ + /* rem_len == desired length for pbuf q */ + + /* shrink allocated memory for PBUF_RAM */ + /* (other types merely adjust their length fields */ + if ((q->type == PBUF_RAM) && (rem_len != q->len)) { + /* reallocate and adjust the length of the pbuf that will be split */ + q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); + LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); + } + /* adjust length fields for new last pbuf */ + q->len = rem_len; + q->tot_len = q->len; + + /* any remaining pbufs in chain? */ + if (q->next != NULL) { + /* free remaining pbufs in chain */ + pbuf_free(q->next); + } + /* q is last packet in chain */ + q->next = NULL; + +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If hdr_size_inc is 0, this function does nothing and returns succesful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size_increment) +{ + u16_t type; + void *payload; + u16_t increment_magnitude; + + LWIP_ASSERT("p != NULL", p != NULL); + if ((header_size_increment == 0) || (p == NULL)) { + return 0; + } + + if (header_size_increment < 0){ + increment_magnitude = -header_size_increment; + /* Check that we aren't going to move off the end of the pbuf */ + LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); + } else { + increment_magnitude = header_size_increment; +#if 0 + /* Can't assert these as some callers speculatively call + pbuf_header() to see if it's OK. Will return 1 below instead. */ + /* Check that we've got the correct type of pbuf to work with */ + LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", + p->type == PBUF_RAM || p->type == PBUF_POOL); + /* Check that we aren't going to move off the beginning of the pbuf */ + LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", + (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); +#endif + } + + type = p->type; + /* remember current payload pointer */ + payload = p->payload; + + /* pbuf types containing payloads? */ + if (type == PBUF_RAM || type == PBUF_POOL) { + /* set new payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + /* boundary check fails? */ + if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF + EP_OFFSET) { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", + (void *)p->payload, (void *)(p + 1))); + /* restore old payload pointer */ + p->payload = payload; + /* bail out unsuccesfully */ + return 1; + } + /* pbuf types refering to external payloads? */ + } else if (type == PBUF_REF || type == PBUF_ROM) { + /* hide a header in the payload? */ + if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { + /* increase payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + } else { + /* cannot expand payload to front (yet!) + * bail out unsuccesfully */ + if (type == PBUF_REF) { + /* increase payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + } else { + return 1; + } + } + } else { + /* Unknown type */ + LWIP_ASSERT("bad pbuf type", 0); + return 1; + } + /* modify pbuf length fields */ + p->len += header_size_increment; + p->tot_len += header_size_increment; + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", + (void *)payload, (void *)p->payload, header_size_increment)); + + return 0; +} + +/** + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param p The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + * + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ +u8_t +pbuf_free(struct pbuf *p) +{ + u16_t type; + struct pbuf *q; + u8_t count; + + if (p == NULL) { + LWIP_ASSERT("p != NULL", p != NULL); + /* if assertions are disabled, proceed with debug output */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_free(p == NULL) was called.\n")); + return 0; + } + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); + + PERF_START; + + LWIP_ASSERT("pbuf_free: sane type", + p->type == PBUF_RAM || p->type == PBUF_ROM || + p->type == PBUF_REF || p->type == PBUF_POOL +#ifdef EBUF_LWIP + || p->type == PBUF_ESF_RX +#endif //EBUF_LWIP + ); + + count = 0; + /* de-allocate all consecutive pbufs from the head of the chain that + * obtain a zero reference count after decrementing*/ + while (p != NULL) { + u16_t ref; + SYS_ARCH_DECL_PROTECT(old_level); + /* Since decrementing ref cannot be guaranteed to be a single machine operation + * we must protect it. We put the new ref into a local variable to prevent + * further protection. */ + SYS_ARCH_PROTECT(old_level); + /* all pbufs in a chain are referenced at least once */ + LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); + /* decrease reference count (number of pointers to pbuf) */ + ref = --(p->ref); + SYS_ARCH_UNPROTECT(old_level); + /* this pbuf is no longer referenced to? */ + if (ref == 0) { + /* remember next pbuf in chain for next iteration */ + q = p->next; + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); + type = p->type; +#if LWIP_SUPPORT_CUSTOM_PBUF + /* is this a custom pbuf? */ + if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { + struct pbuf_custom *pc = (struct pbuf_custom*)p; + LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); + pc->custom_free_function(p); + } else +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + { + /* is this a pbuf from the pool? */ + if (type == PBUF_POOL) { + memp_free(MEMP_PBUF_POOL, p); + /* is this a ROM or RAM referencing pbuf? */ + } else if (type == PBUF_ROM || type == PBUF_REF +#ifdef EBUF_LWIP + || type == PBUF_ESF_RX +#endif //EBUF_LWIP + ) { +#ifdef EBUF_LWIP + system_pp_recycle_rx_pkt(p->eb); +#endif //EBUF_LWIP + memp_free(MEMP_PBUF, p); + /* type == PBUF_RAM */ + } else { + mem_free(p); + } + } + count++; + /* proceed to next pbuf */ + p = q; + /* p->ref > 0, this pbuf is still referenced to */ + /* (and so the remaining pbufs in chain as well) */ + } else { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); + /* stop walking through the chain */ + p = NULL; + } + } + PERF_STOP("pbuf_free"); + /* return number of de-allocated pbufs */ + return count; +} + +/** + * Count number of pbufs in a chain + * + * @param p first pbuf of chain + * @return the number of pbufs in a chain + */ + +u8_t +pbuf_clen(struct pbuf *p) +{ + u8_t len; + + len = 0; + while (p != NULL) { + ++len; + p = p->next; + } + return len; +} + +/** + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void +pbuf_ref(struct pbuf *p) +{ + SYS_ARCH_DECL_PROTECT(old_level); + /* pbuf given? */ + if (p != NULL) { + SYS_ARCH_PROTECT(old_level); + ++(p->ref); + SYS_ARCH_UNPROTECT(old_level); + } +} + +/** + * Concatenate two pbufs (each may be a pbuf chain) and take over + * the caller's reference of the tail pbuf. + * + * @note The caller MAY NOT reference the tail pbuf afterwards. + * Use pbuf_chain() for that purpose. + * + * @see pbuf_chain() + */ + +void +pbuf_cat(struct pbuf *h, struct pbuf *t) +{ + struct pbuf *p; + + LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", + ((h != NULL) && (t != NULL)), return;); + + /* proceed to last pbuf of chain */ + for (p = h; p->next != NULL; p = p->next) { + /* add total length of second chain to all totals of first chain */ + p->tot_len += t->tot_len; + } + /* { p is last pbuf of first h chain, p->next == NULL } */ + LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); + LWIP_ASSERT("p->next == NULL", p->next == NULL); + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len += t->tot_len; + /* chain last pbuf of head (p) with first of tail (t) */ + p->next = t; + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. + */ +} + +/** + * Chain two pbufs (or pbuf chains) together. + * + * The caller MUST call pbuf_free(t) once it has stopped + * using it. Use pbuf_cat() instead if you no longer use t. + * + * @param h head pbuf (chain) + * @param t tail pbuf (chain) + * @note The pbufs MUST belong to the same packet. + * @note MAY NOT be called on a packet queue. + * + * The ->tot_len fields of all pbufs of the head chain are adjusted. + * The ->next field of the last pbuf of the head chain is adjusted. + * The ->ref field of the first pbuf of the tail chain is adjusted. + * + */ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ + pbuf_cat(h, t); + /* t is now referenced by h */ + pbuf_ref(t); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); +} + +/** + * Dechains the first pbuf from its succeeding pbufs in the chain. + * + * Makes p->tot_len field equal to p->len. + * @param p pbuf to dechain + * @return remainder of the pbuf chain, or NULL if it was de-allocated. + * @note May not be called on a packet queue. + */ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + u8_t tail_gone = 1; + /* tail */ + q = p->next; + /* pbuf has successor in chain? */ + if (q != NULL) { + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); + /* enforce invariant if assertion is disabled */ + q->tot_len = p->tot_len - p->len; + /* decouple pbuf from remainder */ + p->next = NULL; + /* total length of pbuf p is its own length only */ + p->tot_len = p->len; + /* q is no longer referenced by p, free it */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); + tail_gone = pbuf_free(q); + if (tail_gone > 0) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, + ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); + } + /* return remaining tail or NULL if deallocated */ + } + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); + return ((tail_gone > 0) ? NULL : q); +} + +/** + * + * Create PBUF_RAM copies of pbufs. + * + * Used to queue packets on behalf of the lwIP stack, such as + * ARP based queueing. + * + * @note You MUST explicitly use p = pbuf_take(p); + * + * @note Only one packet is copied, no packet queue! + * + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy + * + * @return ERR_OK if pbuf was copied + * ERR_ARG if one of the pbufs is NULL or p_to is not big + * enough to hold p_from + */ +err_t +pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) +{ + u16_t offset_to=0, offset_from=0, len; + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", + (void*)p_to, (void*)p_from)); + + /* is the target big enough to hold the source? */ + LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && + (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); + + /* iterate through pbuf chain */ + do + { + LWIP_ASSERT("p_to != NULL", p_to != NULL); + /* copy one part of the original chain */ + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { + /* complete current p_from fits into current p_to */ + len = p_from->len - offset_from; + } else { + /* current p_from does not fit into current p_to */ + len = p_to->len - offset_to; + } + MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); + offset_to += len; + offset_from += len; + LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); + if (offset_to == p_to->len) { + /* on to next p_to (if any) */ + offset_to = 0; + p_to = p_to->next; + } + LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); + if (offset_from >= p_from->len) { + /* on to next p_from (if any) */ + offset_from = 0; + p_from = p_from->next; + } + + if((p_from != NULL) && (p_from->len == p_from->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", + (p_from->next == NULL), return ERR_VAL;); + } + if((p_to != NULL) && (p_to->len == p_to->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", + (p_to->next == NULL), return ERR_VAL;); + } + } while (p_from); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); + return ERR_OK; +} + +/** + * Copy (part of) the contents of a packet buffer + * to an application supplied buffer. + * + * @param buf the pbuf from which to copy data + * @param dataptr the application supplied buffer + * @param len length of data to copy (dataptr must be big enough). No more + * than buf->tot_len will be copied, irrespective of len + * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure + */ +u16_t +pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) +{ + struct pbuf *p; + u16_t left; + u16_t buf_copy_len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + + left = 0; + + if((buf == NULL) || (dataptr == NULL)) { + return 0; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for(p = buf; len != 0 && p != NULL; p = p->next) { + if ((offset != 0) && (offset >= p->len)) { + /* don't copy from this buffer -> on to the next */ + offset -= p->len; + } else { + /* copy from this buffer. maybe only partially. */ + buf_copy_len = p->len - offset; + if (buf_copy_len > len) + buf_copy_len = len; + /* copy the necessary parts of the buffer */ + MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); + copied_total += buf_copy_len; + left += buf_copy_len; + len -= buf_copy_len; + offset = 0; + } + } + return copied_total; +} + +/** + * Copy application supplied data into a pbuf. + * This function can only be used to copy the equivalent of buf->tot_len data. + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ + struct pbuf *p; + u16_t buf_copy_len; + u16_t total_copy_len = len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); + + if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { + return ERR_ARG; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for(p = buf; total_copy_len != 0; p = p->next) { + LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); + buf_copy_len = total_copy_len; + if (buf_copy_len > p->len) { + /* this pbuf cannot hold all remaining data */ + buf_copy_len = p->len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); + total_copy_len -= buf_copy_len; + copied_total += buf_copy_len; + } + LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); + return ERR_OK; +} + +/** + * Creates a single pbuf out of a queue of pbufs. + * + * @remark: Either the source pbuf 'p' is freed by this function or the original + * pbuf 'p' is returned, therefore the caller has to check the result! + * + * @param p the source pbuf + * @param layer pbuf_layer of the new pbuf + * + * @return a new, single pbuf (p->next is NULL) + * or the old pbuf if allocation fails + */ +struct pbuf* +pbuf_coalesce(struct pbuf *p, pbuf_layer layer) +{ + struct pbuf *q; + err_t err; + if (p->next == NULL) { + return p; + } + q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); + if (q == NULL) { + /* @todo: what do we do now? */ + return p; + } + err = pbuf_copy(q, p); + LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); + pbuf_free(p); + return q; +} + +#if LWIP_CHECKSUM_ON_COPY +/** + * Copies data into a single pbuf (*not* into a pbuf queue!) and updates + * the checksum while copying + * + * @param p the pbuf to copy data into + * @param start_offset offset of p->payload where to copy the data to + * @param dataptr data to copy into the pbuf + * @param len length of data to copy into the pbuf + * @param chksum pointer to the checksum which is updated + * @return ERR_OK if successful, another error if the data does not fit + * within the (first) pbuf (no pbuf queues!) + */ +err_t +pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum) +{ + u32_t acc; + u16_t copy_chksum; + char *dst_ptr; + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("dataptr != NULL", dataptr != NULL); + LWIP_ASSERT("chksum != NULL", chksum != NULL); + LWIP_ASSERT("len != 0", len != 0); + + if ((start_offset >= p->len) || (start_offset + len > p->len)) { + return ERR_ARG; + } + + dst_ptr = ((char*)p->payload) + start_offset; + copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); + if ((start_offset & 1) != 0) { + copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); + } + acc = *chksum; + acc += copy_chksum; + *chksum = FOLD_U32T(acc); + return ERR_OK; +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + + /** Get one byte from the specified position in a pbuf + * WARNING: returns zero for offset >= p->tot_len + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len + */ +u8_t +pbuf_get_at(struct pbuf* p, u16_t offset) +{ + u16_t copy_from = offset; + struct pbuf* q = p; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= copy_from)) { + copy_from -= q->len; + q = q->next; + } + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > copy_from)) { + return ((u8_t*)q->payload)[copy_from]; + } + return 0; +} + +/** Compare pbuf contents at specified offset with memory s2, both of length n + * + * @param p pbuf to compare + * @param offset offset into p at wich to start comparing + * @param s2 buffer to compare + * @param n length of buffer to compare + * @return zero if equal, nonzero otherwise + * (0xffff if p is too short, diffoffset+1 otherwise) + */ +u16_t +pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) +{ + u16_t start = offset; + struct pbuf* q = p; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= start)) { + start -= q->len; + q = q->next; + } + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > start)) { + u16_t i; + for(i = 0; i < n; i++) { + u8_t a = pbuf_get_at(q, start + i); + u8_t b = ((u8_t*)s2)[i]; + if (a != b) { + return i+1; + } + } + return 0; + } + return 0xffff; +} + +/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset + * start_offset. + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param mem search for the contents of this buffer + * @param mem_len length of 'mem' + * @param start_offset offset into p at which to start searching + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) +{ + u16_t i; + u16_t max = p->tot_len - mem_len; + if (p->tot_len >= mem_len + start_offset) { + for(i = start_offset; i <= max; ) { + u16_t plus = pbuf_memcmp(p, i, mem, mem_len); + if (plus == 0) { + return i; + } else { + i += plus; + } + } + } + return 0xFFFF; +} + +/** Find occurrence of substr with length substr_len in pbuf p, start at offset + * start_offset + * WARNING: in contrast to strstr(), this one does not stop at the first \0 in + * the pbuf/source string! + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param substr string to search for in p, maximum length is 0xFFFE + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_strstr(struct pbuf* p, const char* substr) +{ + size_t substr_len; + if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { + return 0xFFFF; + } + substr_len = os_strlen(substr); + if (substr_len >= 0xFFFF) { + return 0xFFFF; + } + return pbuf_memfind(p, substr, (u16_t)substr_len, 0); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/raw.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/raw.c new file mode 100755 index 0000000000..b89a4f82fa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/raw.c @@ -0,0 +1,358 @@ +/** + * @file + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" +#include "lwip/stats.h" +#include "arch/perf.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** The list of RAW PCBs */ +static struct raw_pcb *raw_pcbs; + +/** + * Determine if in incoming IP packet is covered by a RAW PCB + * and if so, pass it to a user-provided receive callback function. + * + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and calls the corresponding receive + * callback function. + * + * @param p pbuf to be demultiplexed to a RAW PCB. + * @param inp network interface on which the datagram was received. + * @return - 1 if the packet has been eaten by a RAW PCB receive + * callback function. The caller MAY NOT not reference the + * packet any longer, and MAY NOT call pbuf_free(). + * @return - 0 if packet is not eaten (pbuf is still referenced by the + * caller). + * + */ +u8_t ICACHE_FLASH_ATTR +raw_input(struct pbuf *p, struct netif *inp) +{ + struct raw_pcb *pcb, *prev; + struct ip_hdr *iphdr; + s16_t proto; + u8_t eaten = 0; + + LWIP_UNUSED_ARG(inp); + + iphdr = (struct ip_hdr *)p->payload; + proto = IPH_PROTO(iphdr); + + prev = NULL; + pcb = raw_pcbs; + /* loop through all raw pcbs until the packet is eaten by one */ + /* this allows multiple pcbs to match against the packet by design */ + while ((eaten == 0) && (pcb != NULL)) { + if ((pcb->protocol == proto) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) { +#if IP_SOF_BROADCAST_RECV + /* broadcast filter? */ + if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + /* receive callback function available? */ + if (pcb->recv != NULL) { + /* the receive callback function did not eat the packet? */ + if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) { + /* receive function ate the packet */ + p = NULL; + eaten = 1; + if (prev != NULL) { + /* move the pcb to the front of raw_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + } + } + /* no receive callback function was set for this raw PCB */ + } + /* drop the packet */ + } + prev = pcb; + pcb = pcb->next; + } + return eaten; +} + +/** + * Bind a RAW PCB. + * + * @param pcb RAW PCB to be bound with a local address ipaddr. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified IP address is already bound to by + * another RAW PCB. + * + * @see raw_disconnect() + */ +err_t ICACHE_FLASH_ATTR +raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) +{ + ip_addr_set(&pcb->local_ip, ipaddr); + return ERR_OK; +} + +/** + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_sendto() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_sendto() + */ +err_t ICACHE_FLASH_ATTR +raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) +{ + ip_addr_set(&pcb->remote_ip, ipaddr); + return ERR_OK; +} + + +/** + * Set the callback function for received packets that match the + * raw PCB's protocol and binding. + * + * The callback function MUST either + * - eat the packet by calling pbuf_free() and returning non-zero. The + * packet will not be passed to other raw PCBs or other protocol layers. + * - not free the packet, and return zero. The packet will be matched + * against further PCBs and/or forwarded to another protocol layers. + * + * @return non-zero if the packet was free()d, zero if the packet remains + * available for others. + */ +void ICACHE_FLASH_ATTR +raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * Send the raw IP packet to the given address. Note that actually you cannot + * modify the IP headers (this is inconsistent with the receive callback where + * you actually get the IP headers), you can only specify the IP payload here. + * It requires some more changes in lwIP. (there will be a raw_send() function + * then.) + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t ICACHE_FLASH_ATTR +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) +{ + err_t err; + struct netif *netif; + ip_addr_t *src_ip; + struct pbuf *q; /* q will be sent down the stack */ + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); + + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_header(p, IP_HLEN)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + } + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + if(pbuf_header(q, -IP_HLEN)) { + LWIP_ASSERT("Can't restore header we just removed!", 0); + return ERR_MEM; + } + } + + if ((netif = ip_route(ipaddr)) == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + +#if IP_SOF_BROADCAST + /* broadcast filter? */ + if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; + } +#endif /* IP_SOF_BROADCAST */ + + if (ip_addr_isany(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = &(netif->ip_addr); + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &(pcb->local_ip); + } + +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ + err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ + + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * + */ +err_t ICACHE_FLASH_ATTR +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ + return raw_sendto(pcb, p, &pcb->remote_ip); +} + +/** + * Remove an RAW PCB. + * + * @param pcb RAW PCB to be removed. The PCB is removed from the list of + * RAW PCB's and the data structure is freed from memory. + * + * @see raw_new() + */ +void ICACHE_FLASH_ATTR +raw_remove(struct raw_pcb *pcb) +{ + struct raw_pcb *pcb2; + /* pcb to be removed is first in list? */ + if (raw_pcbs == pcb) { + /* make list start at 2nd pcb */ + raw_pcbs = raw_pcbs->next; + /* pcb not 1st in list */ + } else { + for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in raw_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + } + } + } + memp_free(MEMP_RAW_PCB, pcb); +} + +/** + * Create a RAW PCB. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) + * + * @see raw_remove() + */ +struct raw_pcb * ICACHE_FLASH_ATTR +raw_new(u8_t proto) +{ + struct raw_pcb *pcb; + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); + + pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); + /* could allocate RAW PCB? */ + if (pcb != NULL) { + /* initialize PCB to all zeroes */ + os_memset(pcb, 0, sizeof(struct raw_pcb)); + pcb->protocol = proto; + pcb->ttl = RAW_TTL; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + return pcb; +} + +#endif /* LWIP_RAW */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sntp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sntp.c new file mode 100755 index 0000000000..dc0e8b7e2c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sntp.c @@ -0,0 +1,1165 @@ +/** + * @file + * SNTP client module + * + * This is simple "SNTP" client for the lwIP raw API. + * It is a minimal implementation of SNTPv4 as specified in RFC 4330. + * + * For a list of some public NTP servers, see this link : + * http://support.ntp.org/bin/view/Servers/NTPPoolServers + * + * @todo: + * - set/change servers at runtime + * - complete SNTP_CHECK_RESPONSE checks 3 and 4 + * - support broadcast/multicast mode? + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt (lwIP raw API part) + */ + +#include "lwip/sntp.h" +#include "osapi.h" +#include "os_type.h" +#include "lwip/opt.h" +#include "lwip/timers.h" +#include "lwip/udp.h" +#include "lwip/dns.h" +#include "lwip/ip_addr.h" +#include "lwip/pbuf.h" +#include "lwip/app/time.h" +//#include +#if LWIP_UDP + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#ifndef SNTP_DEBUG +#define SNTP_DEBUG LWIP_DBG_ON +#endif + +/** SNTP server port */ +#ifndef SNTP_PORT +#define SNTP_PORT 123 +#endif + +/** Set this to 1 to allow config of SNTP server(s) by DNS name */ +#ifndef SNTP_SERVER_DNS +#define SNTP_SERVER_DNS 0 +#endif + +/** Handle support for more than one server via NTP_MAX_SERVERS, + * but catch legacy style of setting SNTP_SUPPORT_MULTIPLE_SERVERS, probably outside of this file + */ +#ifndef SNTP_SUPPORT_MULTIPLE_SERVERS +#if SNTP_MAX_SERVERS > 1 +#define SNTP_SUPPORT_MULTIPLE_SERVERS 1 +#else /* NTP_MAX_SERVERS > 1 */ +#define SNTP_SUPPORT_MULTIPLE_SERVERS 0 +#endif /* NTP_MAX_SERVERS > 1 */ +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +/* The developer has defined SNTP_SUPPORT_MULTIPLE_SERVERS, probably from old code */ +#if SNTP_MAX_SERVERS <= 1 +#error "SNTP_MAX_SERVERS needs to be defined to the max amount of servers if SNTP_SUPPORT_MULTIPLE_SERVERS is defined" +#endif /* SNTP_MAX_SERVERS <= 1 */ +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + + +/** Sanity check: + * Define this to + * - 0 to turn off sanity checks (default; smaller code) + * - >= 1 to check address and port of the response packet to ensure the + * response comes from the server we sent the request to. + * - >= 2 to check returned Originate Timestamp against Transmit Timestamp + * sent to the server (to ensure response to older request). + * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp + * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). + * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each + * greater than or equal to 0 and less than infinity, where infinity is + * currently a cozy number like one second. This check avoids using a + * server whose synchronization source has expired for a very long time. + */ +#ifndef SNTP_CHECK_RESPONSE +#define SNTP_CHECK_RESPONSE 0 +#endif + +/** According to the RFC, this shall be a random delay + * between 1 and 5 minutes (in milliseconds) to prevent load peaks. + * This can be defined to a random generation function, + * which must return the delay in milliseconds as u32_t. + * Turned off by default. + */ +#ifndef SNTP_STARTUP_DELAY +#define SNTP_STARTUP_DELAY 0 +#endif + +/** If you want the startup delay to be a function, define this + * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. + */ +#ifndef SNTP_STARTUP_DELAY_FUNC +#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY +#endif + +/** SNTP receive timeout - in milliseconds + * Also used as retry timeout - this shouldn't be too low. + * Default is 3 seconds. + */ +#ifndef SNTP_RECV_TIMEOUT +#define SNTP_RECV_TIMEOUT 3000 +#endif + +/** SNTP update delay - in milliseconds + * Default is 1 hour. + */ +#ifndef SNTP_UPDATE_DELAY +#define SNTP_UPDATE_DELAY 3600000 +#endif +#if (SNTP_UPDATE_DELAY < 15000) && !SNTP_SUPPRESS_DELAY_CHECK +#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds!" +#endif + +/** SNTP macro to change system time and/or the update the RTC clock */ +#ifndef SNTP_SET_SYSTEM_TIME +#define SNTP_SET_SYSTEM_TIME(sec) ((void)sec) +#endif + +/** SNTP macro to change system time including microseconds */ +uint8 sntp_receive_time_size = 1; +#define SNTP_RECEIVE_TIME_SIZE sntp_receive_time_size +#define SNTP_SET_SYSTEM_TIME_US(sec, us) sntp_update_rtc(sec, us) +//#ifdef SNTP_SET_SYSTEM_TIME_US +//#define SNTP_SET_SYSTEM_TIME_US(sec, us) sntp_update_rtc(sec, us) +//#define SNTP_CALC_TIME_US 1 +//#define SNTP_RECEIVE_TIME_SIZE 2 +//#else +//#define SNTP_SET_SYSTEM_TIME_US(sec, us) +//#define SNTP_CALC_TIME_US 0 +//#define SNTP_RECEIVE_TIME_SIZE sntp_receive_time_size +//#endif + +/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 + * to send in request and compare in response. + */ +#ifndef SNTP_GET_SYSTEM_TIME +#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) +#endif + +/** Default retry timeout (in milliseconds) if the response + * received is invalid. + * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. + */ +#ifndef SNTP_RETRY_TIMEOUT +#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT +#endif + +/** Maximum retry timeout (in milliseconds). */ +#ifndef SNTP_RETRY_TIMEOUT_MAX +#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) +#endif + +/** Increase retry timeout with every retry sent + * Default is on to conform to RFC. + */ +#ifndef SNTP_RETRY_TIMEOUT_EXP +#define SNTP_RETRY_TIMEOUT_EXP 1 +#endif + +/* the various debug levels for this file */ +#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) +#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) +#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) +#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) + +#define SNTP_ERR_KOD 1 + +/* SNTP protocol defines */ +#define SNTP_MSG_LEN 48 + +#define SNTP_OFFSET_LI_VN_MODE 0 +#define SNTP_LI_MASK 0xC0 +#define SNTP_LI_NO_WARNING 0x00 +#define SNTP_LI_LAST_MINUTE_61_SEC 0x01 +#define SNTP_LI_LAST_MINUTE_59_SEC 0x02 +#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ + +#define SNTP_VERSION_MASK 0x38 +#define SNTP_VERSION (4/* NTP Version 4*/<<3) + +#define SNTP_MODE_MASK 0x07 +#define SNTP_MODE_CLIENT 0x03 +#define SNTP_MODE_SERVER 0x04 +#define SNTP_MODE_BROADCAST 0x05 + +#define SNTP_OFFSET_STRATUM 1 +#define SNTP_STRATUM_KOD 0x00 + +#define SNTP_OFFSET_ORIGINATE_TIME 24 +#define SNTP_OFFSET_RECEIVE_TIME 32 +#define SNTP_OFFSET_TRANSMIT_TIME 40 + +/* number of seconds between 1900 and 1970 */ +#define DIFF_SEC_1900_1970 (2208988800UL) + +/** + * SNTP packet format (without optional fields) + * Timestamps are coded as 64 bits: + * - 32 bits seconds since Jan 01, 1970, 00:00 + * - 32 bits seconds fraction (0-padded) + * For future use, if the MSB in the seconds part is set, seconds are based + * on Feb 07, 2036, 06:28:16. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +#define PACK_STRUCT_FLD_8 PACK_STRUCT_FIELD +struct sntp_msg { + PACK_STRUCT_FLD_8(u8_t li_vn_mode); + PACK_STRUCT_FLD_8(u8_t stratum); + PACK_STRUCT_FLD_8(u8_t poll); + PACK_STRUCT_FLD_8(u8_t precision); + PACK_STRUCT_FIELD(u32_t root_delay); + PACK_STRUCT_FIELD(u32_t root_dispersion); + PACK_STRUCT_FIELD(u32_t reference_identifier); + PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); + PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); + PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); + PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* function prototypes */ +static void sntp_request(void *arg); + +/** The UDP pcb used by the SNTP client */ +static struct udp_pcb* sntp_pcb; + +sint8 time_zone = 8; +/** Names/Addresses of servers */ +struct sntp_server { +#if SNTP_SERVER_DNS + char name[32]; +#endif /* SNTP_SERVER_DNS */ + ip_addr_t addr; +}; +static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; + +static u8_t sntp_set_servers_from_dhcp; +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** The currently used server (initialized to 0) */ +static u8_t sntp_current_server; +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +#define sntp_current_server 0 +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +#if SNTP_RETRY_TIMEOUT_EXP +#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT +/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ +static u32_t sntp_retry_timeout; +#else /* SNTP_RETRY_TIMEOUT_EXP */ +#define SNTP_RESET_RETRY_TIMEOUT() +#define sntp_retry_timeout SNTP_RETRY_TIMEOUT +#endif /* SNTP_RETRY_TIMEOUT_EXP */ + +#if SNTP_CHECK_RESPONSE >= 1 +/** Saves the last server address to compare with response */ +static ip_addr_t sntp_last_server_address; +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + +#if SNTP_CHECK_RESPONSE >= 2 +/** Saves the last timestamp sent (which is sent back by the server) + * to compare against in response */ +static u32_t sntp_last_timestamp_sent[2]; +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + +//uint32 current_stamp_1 = 0; +//uint32 current_stamp_2 = 0; +static bool sntp_time_flag = false; +static uint32 sntp_update_delay = SNTP_UPDATE_DELAY; +static uint64 realtime_stamp = 0; +LOCAL os_timer_t sntp_timer; +/*****************************************/ +#define SECSPERMIN 60L +#define MINSPERHOUR 60L +#define HOURSPERDAY 24L +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERWEEK 7 +#define MONSPERYEAR 12 + +#define YEAR_BASE 1900 +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY 4 +#define EPOCH_YEARS_SINCE_LEAP 2 +#define EPOCH_YEARS_SINCE_CENTURY 70 +#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +int __tznorth; +int __tzyear; +char reult[100]; +static const int mon_lengths[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +} ; + +static const int year_lengths[2] = { + 365, + 366 +} ; + +struct tm res_buf; + +__tzrule_type sntp__tzrule[2]; +struct tm * ICACHE_FLASH_ATTR +sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime) +{ + long days, rem; + time_t lcltime; + int i; + int y; + int yleap; + const int *ip; + + /* base decision about std/dst time on current time */ + lcltime = *tim_p; + + days = ((long)lcltime) / SECSPERDAY; + rem = ((long)lcltime) % SECSPERDAY; + while (rem < 0) + { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) + { + rem -= SECSPERDAY; + ++days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int) (rem / SECSPERMIN); + res->tm_sec = (int) (rem % SECSPERMIN); + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + res->tm_wday += DAYSPERWEEK; + + /* compute year & day of year */ + y = EPOCH_YEAR; + if (days >= 0) + { + for (;;) + { + yleap = isleap(y); + if (days < year_lengths[yleap]) + break; + y++; + days -= year_lengths[yleap]; + } + } + else + { + do + { + --y; + yleap = isleap(y); + days += year_lengths[yleap]; + } while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = mon_lengths[yleap]; + for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) + days -= ip[res->tm_mon]; + res->tm_mday = days + 1; + + if (!is_gmtime) + { + int offset; + int hours, mins, secs; + +// TZ_LOCK; +// if (_daylight) +// { +// if (y == __tzyear || __tzcalc_limits (y)) +// res->tm_isdst = (__tznorth +// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) +// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); +// else +// res->tm_isdst = -1; +// } +// else + res->tm_isdst = 0; + + offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); + + hours = offset / SECSPERHOUR; + offset = offset % SECSPERHOUR; + + mins = offset / SECSPERMIN; + secs = offset % SECSPERMIN; + + res->tm_sec -= secs; + res->tm_min -= mins; + res->tm_hour -= hours; + + if (res->tm_sec >= SECSPERMIN) + { + res->tm_min += 1; + res->tm_sec -= SECSPERMIN; + } + else if (res->tm_sec < 0) + { + res->tm_min -= 1; + res->tm_sec += SECSPERMIN; + } + if (res->tm_min >= MINSPERHOUR) + { + res->tm_hour += 1; + res->tm_min -= MINSPERHOUR; + } + else if (res->tm_min < 0) + { + res->tm_hour -= 1; + res->tm_min += MINSPERHOUR; + } + if (res->tm_hour >= HOURSPERDAY) + { + ++res->tm_yday; + ++res->tm_wday; + if (res->tm_wday > 6) + res->tm_wday = 0; + ++res->tm_mday; + res->tm_hour -= HOURSPERDAY; + if (res->tm_mday > ip[res->tm_mon]) + { + res->tm_mday -= ip[res->tm_mon]; + res->tm_mon += 1; + if (res->tm_mon == 12) + { + res->tm_mon = 0; + res->tm_year += 1; + res->tm_yday = 0; + } + } + } + else if (res->tm_hour < 0) + { + res->tm_yday -= 1; + res->tm_wday -= 1; + if (res->tm_wday < 0) + res->tm_wday = 6; + res->tm_mday -= 1; + res->tm_hour += 24; + if (res->tm_mday == 0) + { + res->tm_mon -= 1; + if (res->tm_mon < 0) + { + res->tm_mon = 11; + res->tm_year -= 1; + res->tm_yday = 365 + isleap(res->tm_year); + } + res->tm_mday = ip[res->tm_mon]; + } + } +// TZ_UNLOCK; + } + else + res->tm_isdst = 0; +// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour); + return (res); +} +struct tm * ICACHE_FLASH_ATTR +sntp_localtime_r(const time_t * tim_p , + struct tm *res) +{ + return sntp_mktm_r (tim_p, res, 0); +} + +struct tm * ICACHE_FLASH_ATTR +sntp_localtime(const time_t * tim_p) +{ + return sntp_localtime_r (tim_p, &res_buf); +} + + +int ICACHE_FLASH_ATTR +sntp__tzcalc_limits(int year) +{ + int days, year_days, years; + int i, j; + + if (year < EPOCH_YEAR) + return 0; + + __tzyear = year; + + years = (year - EPOCH_YEAR); + + year_days = years * 365 + + (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + + (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; + + for (i = 0; i < 2; ++i) + { + if (sntp__tzrule[i].ch == 'J') + days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); + else if (sntp__tzrule[i].ch == 'D') + days = year_days + sntp__tzrule[i].d; + else + { + int yleap = isleap(year); + int m_day, m_wday, wday_diff; + const int *ip = mon_lengths[yleap]; + + days = year_days; + + for (j = 1; j < sntp__tzrule[i].m; ++j) + days += ip[j-1]; + + m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; + + wday_diff = sntp__tzrule[i].d - m_wday; + if (wday_diff < 0) + wday_diff += DAYSPERWEEK; + m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; + + while (m_day >= ip[j-1]) + m_day -= DAYSPERWEEK; + + days += m_day; + } + + /* store the change-over time in GMT form by adding offset */ + sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset; + } + + __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); + + return 1; +} + +char * ICACHE_FLASH_ATTR +sntp_asctime_r(struct tm *tim_p ,char *result) +{ + static const char day_name[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n", + day_name[tim_p->tm_wday], + mon_name[tim_p->tm_mon], + tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, + tim_p->tm_sec, 1900 + tim_p->tm_year); + return result; +} +char *ICACHE_FLASH_ATTR +sntp_asctime(struct tm *tim_p) +{ + + return sntp_asctime_r (tim_p, reult); +} + +uint64 sntp_get_current_timestamp() +{ + if(realtime_stamp == 0){ + os_printf("please start sntp first !\n"); + return 0; + } else { + return realtime_stamp; + } +} + +char* sntp_get_real_time(time_t t) +{ + return sntp_asctime(sntp_localtime (&t)); +} +/** + * SNTP get time_zone default GMT + 8 + */ +sint8 ICACHE_FLASH_ATTR +sntp_get_timezone(void) +{ + return time_zone; +} +/** + * SNTP set time_zone default GMT + 8 + */ + +bool ICACHE_FLASH_ATTR +sntp_set_timezone(sint8 timezone) +{ + if(timezone >= -11 || timezone <= 13) { + if (sntp_get_timetype()){ + RTC_TZ_SET(time_zone); + } else + time_zone = timezone; + return true; + } else { + return false; + } + +} + +void ICACHE_FLASH_ATTR sntp_set_daylight(int daylight) +{ + if (sntp_get_timetype()){ + RTC_DST_SET(daylight); + } +} + +void ICACHE_FLASH_ATTR +sntp_time_inc(void) +{ + realtime_stamp++; +} +/** + * SNTP processing of received timestamp + */ +static void ICACHE_FLASH_ATTR +sntp_process(u32_t *receive_timestamp) +{ + /* convert SNTP time (1900-based) to unix GMT time (1970-based) + * @todo: if MSB is 1, SNTP time is 2036-based! + */ + time_t t = (ntohl(receive_timestamp[0]) - DIFF_SEC_1900_1970); + if (sntp_get_timetype()){ + u32_t us = ntohl(receive_timestamp[1]) / 4295; + SNTP_SET_SYSTEM_TIME_US(t, us); + /* display local time from GMT time */ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&t), us)); + } else{ + /* change system time and/or the update the RTC clock */ + SNTP_SET_SYSTEM_TIME(t); + /* display local time from GMT time */ + t += time_zone * 60 * 60;// format GMT + time_zone TIME ZONE + realtime_stamp = t; + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); + os_timer_arm(&sntp_timer, 1000, 1); + } +#if 0 +#if SNTP_CALC_TIME_US + u32_t us = ntohl(receive_timestamp[1]) / 4295; + SNTP_SET_SYSTEM_TIME_US(t, us); + /* display local time from GMT time */ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&t), us)); + +#else /* SNTP_CALC_TIME_US */ + + /* change system time and/or the update the RTC clock */ + SNTP_SET_SYSTEM_TIME(t); + /* display local time from GMT time */ + t += time_zone * 60 * 60;// format GMT + time_zone TIME ZONE + realtime_stamp = t; + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); + os_timer_arm(&sntp_timer, 1000, 1); +#endif /* SNTP_CALC_TIME_US */ +#endif +} + +/** + * Initialize request struct to be sent to server. + */ +static void ICACHE_FLASH_ATTR +sntp_initialize_request(struct sntp_msg *req) +{ + os_memset(req, 0, SNTP_MSG_LEN); + req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; + +#if SNTP_CHECK_RESPONSE >= 2 + { + u32_t sntp_time_sec, sntp_time_us; + /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ + SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); + sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970); + req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; + /* we send/save us instead of fraction to be faster... */ + sntp_last_timestamp_sent[1] = htonl(sntp_time_us); + req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; + } +#endif /* SNTP_CHECK_RESPONSE >= 2 */ +} + +/** + * Retry: send a new request (and increase retry timeout). + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void ICACHE_FLASH_ATTR +sntp_retry(void* arg) +{ + LWIP_UNUSED_ARG(arg); + + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", + sntp_retry_timeout)); + + /* set up a timer to send a retry and increase the retry delay */ + sys_timeout(sntp_retry_timeout, sntp_request, NULL); + +#if SNTP_RETRY_TIMEOUT_EXP + { + u32_t new_retry_timeout; + /* increase the timeout for next retry */ + new_retry_timeout = sntp_retry_timeout << 1; + /* limit to maximum timeout and prevent overflow */ + if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && + (new_retry_timeout > sntp_retry_timeout)) { + sntp_retry_timeout = new_retry_timeout; + } + } +#endif /* SNTP_RETRY_TIMEOUT_EXP */ +} + +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** + * If Kiss-of-Death is received (or another packet parsing error), + * try the next server or retry the current server and increase the retry + * timeout if only one server is available. + * (implicitly, SNTP_MAX_SERVERS > 1) + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_try_next_server(void* arg) +{ + u8_t old_server, i; + LWIP_UNUSED_ARG(arg); + + old_server = sntp_current_server; + for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) { + sntp_current_server++; + if (sntp_current_server >= SNTP_MAX_SERVERS) { + sntp_current_server = 0; + } + if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) +#if SNTP_SERVER_DNS + || (sntp_servers[sntp_current_server].name != NULL) +#endif + ) { + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", + (u16_t)sntp_current_server)); + /* new server: reset retry timeout */ + SNTP_RESET_RETRY_TIMEOUT(); + /* instantly send a request to the next server */ + sntp_request(NULL); + return; + } + } + /* no other valid server found */ + sntp_current_server = old_server; + sntp_retry(NULL); +} +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +/* Always retry on error if only one server is supported */ +#define sntp_try_next_server sntp_retry +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +/** UDP recv callback for the sntp pcb */ +static void ICACHE_FLASH_ATTR +sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +{ + u8_t mode; + u8_t stratum; + u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; + err_t err; +//os_printf("sntp_recv\n"); + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + + /* packet received: stop retry timeout */ + sys_untimeout(sntp_try_next_server, NULL); + sys_untimeout(sntp_request, NULL); + + err = ERR_ARG; +#if SNTP_CHECK_RESPONSE >= 1 + /* check server address and port */ + if (ip_addr_cmp(addr, &sntp_last_server_address) && + (port == SNTP_PORT)) +#else /* SNTP_CHECK_RESPONSE >= 1 */ + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + { + /* process the response */ + if (p->tot_len == SNTP_MSG_LEN) { + pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); + mode &= SNTP_MODE_MASK; + /* if this is a SNTP response... */ + if ((mode == SNTP_MODE_SERVER) || + (mode == SNTP_MODE_BROADCAST)) { + pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); + if (stratum == SNTP_STRATUM_KOD) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + err = SNTP_ERR_KOD; + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); + } else { +#if SNTP_CHECK_RESPONSE >= 2 + /* check originate_timetamp against sntp_last_timestamp_sent */ + u32_t originate_timestamp[2]; + pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); + if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || + (originate_timestamp[1] != sntp_last_timestamp_sent[1])) + { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); + } else +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ + { + /* correct answer */ + err = ERR_OK; + pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_RECEIVE_TIME); + } + } + } else { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); + } + } else { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); + } + } + pbuf_free(p); + if (err == ERR_OK) { + /* Correct response, reset retry timeout */ + SNTP_RESET_RETRY_TIMEOUT(); + + sntp_process(receive_timestamp); + + /* Set up timeout for next request */ + sys_timeout((u32_t)sntp_update_delay, sntp_request, NULL); + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", + (u32_t)sntp_update_delay)); + } else if (err == SNTP_ERR_KOD) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + sntp_try_next_server(NULL); + } else { + /* another error, try the same server again */ + sntp_retry(NULL); + } +} + +/** Actually send an sntp request to a server. + * + * @param server_addr resolved IP address of the SNTP server + */ +static void ICACHE_FLASH_ATTR +sntp_send_request(ip_addr_t *server_addr) +{ + struct pbuf* p; +// os_printf("sntp_send_request\n"); + p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); + if (p != NULL) { + struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); + /* initialize request message */ + sntp_initialize_request(sntpmsg); + /* send request */ + udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); + /* free the pbuf after sending it */ + pbuf_free(p); + /* set up receive timeout: try next server or retry on timeout */ + sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); +#if SNTP_CHECK_RESPONSE >= 1 + /* save server address to verify it in sntp_recv */ + ip_addr_set(&sntp_last_server_address, server_addr); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + } else { + LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", + (u32_t)SNTP_RETRY_TIMEOUT)); + /* out of memory: set up a timer to send a retry */ + sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); + } +} + +#if SNTP_SERVER_DNS +/** + * DNS found callback when using DNS names as server address. + */ +static void +sntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg) +{ + LWIP_UNUSED_ARG(hostname); + LWIP_UNUSED_ARG(arg); + + if (ipaddr != NULL) { + /* Address resolved, send request */ + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); + sntp_send_request(ipaddr); + } else { + /* DNS resolving failed -> try another server */ + LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); + sntp_try_next_server(NULL); + } +} +#endif /* SNTP_SERVER_DNS */ + +/** + * Send out an sntp request. + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void ICACHE_FLASH_ATTR +sntp_request(void *arg) +{ + ip_addr_t sntp_server_address; + err_t err; + + LWIP_UNUSED_ARG(arg); + + /* initialize SNTP server address */ +#if SNTP_SERVER_DNS + + if (sntp_servers[sntp_current_server].name) { + /* always resolve the name and rely on dns-internal caching & timeout */ + ip_addr_set_any(&sntp_servers[sntp_current_server].addr); + err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address, + sntp_dns_found, NULL); + if (err == ERR_INPROGRESS) { + /* DNS request sent, wait for sntp_dns_found being called */ + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); + return; + } else if (err == ERR_OK) { + sntp_servers[sntp_current_server].addr = sntp_server_address; + } + } else +#endif /* SNTP_SERVER_DNS */ + { + sntp_server_address = sntp_servers[sntp_current_server].addr; +// os_printf("sntp_server_address ip %d\n",sntp_server_address.addr); + err = (ip_addr_isany(&sntp_server_address)) ? ERR_ARG : ERR_OK; + } + + if (err == ERR_OK) { + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %u.%u.%u.%u\n", + ip4_addr1(&sntp_server_address), ip4_addr2(&sntp_server_address), ip4_addr3(&sntp_server_address), ip4_addr4(&sntp_server_address))); + sntp_send_request(&sntp_server_address); + } else { + /* address conversion failed, try another server */ + LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); + sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); + } +} + +/** + * Initialize this module. + * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). + */ +void ICACHE_FLASH_ATTR +sntp_init(void) +{ +#ifdef SNTP_SERVER_ADDRESS +#if SNTP_SERVER_DNS + sntp_setservername(0, SNTP_SERVER_ADDRESS); +#else +#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0 +#endif +#endif /* SNTP_SERVER_ADDRESS */ + + if (sntp_pcb == NULL) { + SNTP_RESET_RETRY_TIMEOUT(); + sntp_pcb = udp_new(); + LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); + if (sntp_pcb != NULL) { + udp_recv(sntp_pcb, sntp_recv, NULL); +#if SNTP_STARTUP_DELAY + sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); +#else + sntp_request(NULL); +#endif + } + } +} + +/** + * Stop this module. + */ +void ICACHE_FLASH_ATTR +sntp_stop(void) +{ + if (sntp_pcb != NULL) { + sys_untimeout(sntp_request, NULL); + udp_remove(sntp_pcb); + sntp_pcb = NULL; + } + os_timer_disarm(&sntp_timer); + realtime_stamp = 0; +} + +#if SNTP_GET_SERVERS_FROM_DHCP +/** + * Config SNTP server handling by IP address, name, or DHCP; clear table + * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp + */ +void +sntp_servermode_dhcp(int set_servers_from_dhcp) +{ + u8_t new_mode = set_servers_from_dhcp ? 1 : 0; + if (sntp_set_servers_from_dhcp != new_mode) { + sntp_set_servers_from_dhcp = new_mode; + } +} +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +/** + * Initialize one of the NTP servers by IP address + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver IP address of the NTP server to set + */ +void ICACHE_FLASH_ATTR +sntp_setserver(u8_t idx, ip_addr_t *server) +{ + if (idx < SNTP_MAX_SERVERS) { + if (server != NULL) { + sntp_servers[idx].addr = (*server); +// os_printf("server ip %d\n",server->addr); + } else { + ip_addr_set_any(&sntp_servers[idx].addr); + } +#if SNTP_SERVER_DNS + //sntp_servers[idx].name = NULL; + os_memset(sntp_servers[idx].name,0x0,sizeof(sntp_servers[idx].name)); +#endif + } +} + +#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP +/** + * Initialize one of the NTP servers by IP address, required by DHCP + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver IP address of the NTP server to set + */ +void +dhcp_set_ntp_servers(u8_t num, ip_addr_t *server) +{ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n", + (sntp_set_servers_from_dhcp ? "Got" : "Rejected"), + ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num)); + if (sntp_set_servers_from_dhcp && num) { + u8_t i; + for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) { + sntp_setserver(i, &server[i]); + } + for (i = num; i < SNTP_MAX_SERVERS; i++) { + sntp_setserver(i, NULL); + } + } +} +#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */ + +/** + * Obtain one of the currently configured by IP address (or DHCP) NTP servers + * + * @param numdns the index of the NTP server + * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP + * server has not been configured by address (or at all). + */ +ip_addr_t ICACHE_FLASH_ATTR +sntp_getserver(u8_t idx) +{ + if (idx < SNTP_MAX_SERVERS) { + return sntp_servers[idx].addr; + } + return *IP_ADDR_ANY; +} + +#if SNTP_SERVER_DNS +/** + * Initialize one of the NTP servers by name + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time + */ +void ICACHE_FLASH_ATTR +sntp_setservername(u8_t idx, char *server) +{ + if (idx < SNTP_MAX_SERVERS) { + // sntp_servers[idx].name = server; + os_strcpy(sntp_servers[idx].name,server); + } +} + +/** + * Obtain one of the currently configured by name NTP servers. + * + * @param numdns the index of the NTP server + * @return IP address of the indexed NTP server or NULL if the NTP + * server has not been configured by name (or at all) + */ +char * ICACHE_FLASH_ATTR +sntp_getservername(u8_t idx) +{ + if (idx < SNTP_MAX_SERVERS) { + return sntp_servers[idx].name; + } + return NULL; +} +#endif /* SNTP_SERVER_DNS */ + +void ICACHE_FLASH_ATTR +sntp_set_update_delay(uint32 ms) +{ + sntp_update_delay = ms > 15000?ms:15000; +} + +void ICACHE_FLASH_ATTR +sntp_set_timetype(bool type) +{ + sntp_time_flag = type; +} + +bool sntp_get_timetype(void) +{ + return sntp_time_flag; +} + +void ICACHE_FLASH_ATTR +sntp_set_receive_time_size(void) +{ + if (sntp_get_timetype()){ + sntp_receive_time_size = 2; + } else{ + sntp_receive_time_size = 1; + } +} + +#endif /* LWIP_UDP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/stats.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/stats.c new file mode 100755 index 0000000000..69f97d41fc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/stats.c @@ -0,0 +1,176 @@ +/** + * @file + * Statistics module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" + +#include + +struct stats_ lwip_stats; + +void stats_init(void) +{ +#ifdef LWIP_DEBUG +#if MEMP_STATS + const char * memp_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc) desc, +#include "lwip/memp_std.h" + }; + int i; + for (i = 0; i < MEMP_MAX; i++) { + lwip_stats.memp[i].name = memp_names[i]; + } +#endif /* MEMP_STATS */ +#if MEM_STATS + lwip_stats.mem.name = "MEM"; +#endif /* MEM_STATS */ +#endif /* LWIP_DEBUG */ +} + +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); + LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); + LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); + LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); + LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); + LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); +} + +#if IGMP_STATS +void +stats_display_igmp(struct stats_igmp *igmp) +{ + LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); + LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); + LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group)); + LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general)); + LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); + LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); + LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); + LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); +} +#endif /* IGMP_STATS */ + +#if MEM_STATS || MEMP_STATS +void +stats_display_mem(struct stats_mem *mem, char *name) +{ + LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); + LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); + LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); + LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); + LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); +} + +#if MEMP_STATS +void +stats_display_memp(struct stats_mem *mem, int index) +{ + char * memp_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc) desc, +#include "lwip/memp_std.h" + }; + if(index < MEMP_MAX) { + stats_display_mem(mem, memp_names[index]); + } +} +#endif /* MEMP_STATS */ +#endif /* MEM_STATS || MEMP_STATS */ + +#if SYS_STATS +void +stats_display_sys(struct stats_sys *sys) +{ + LWIP_PLATFORM_DIAG(("\nSYS\n\t")); + LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); + LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); + LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); + LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); + LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); + LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); + LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); + LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); + LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); +} +#endif /* SYS_STATS */ + +void +stats_display(void) +{ + s16_t i; + + LINK_STATS_DISPLAY(); + ETHARP_STATS_DISPLAY(); + IPFRAG_STATS_DISPLAY(); + IP_STATS_DISPLAY(); + IGMP_STATS_DISPLAY(); + ICMP_STATS_DISPLAY(); + UDP_STATS_DISPLAY(); + TCP_STATS_DISPLAY(); + MEM_STATS_DISPLAY(); + for (i = 0; i < MEMP_MAX; i++) { + MEMP_STATS_DISPLAY(i); + } + SYS_STATS_DISPLAY(); +} +#endif /* LWIP_STATS_DISPLAY */ + +#endif /* LWIP_STATS */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys.c new file mode 100755 index 0000000000..d3a77deb28 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys.c @@ -0,0 +1,66 @@ +/** + * @file + * lwIP Operating System abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/sys.h" + +/* Most of the functions defined in sys.h must be implemented in the + * architecture-dependent file sys_arch.c */ + +#if !NO_SYS + +/** + * Sleep for some ms. Timeouts are NOT processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ + if (ms > 0) { + sys_sem_t delaysem; + err_t err = sys_sem_new(&delaysem, 0); + if (err == ERR_OK) { + sys_arch_sem_wait(&delaysem, ms); + sys_sem_free(&delaysem); + } + } +} + +#endif /* !NO_SYS */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys_arch.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys_arch.c new file mode 100755 index 0000000000..e79042f226 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/sys_arch.c @@ -0,0 +1,13 @@ +/* + * copyright (c) 2010 - 2011 espressif system + */ + +#include "c_types.h" +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" + +#include "lwip/opt.h" +#include "lwip/sys.h" + +#include "eagle_soc.h" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp.c new file mode 100755 index 0000000000..ee50cebd78 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp.c @@ -0,0 +1,1671 @@ +/** + * @file + * Transmission Control Protocol for IP + * + * This file contains common functions for the TCP implementation, such as functinos + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_in.c and tcp_out.c respectively. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/snmp.h" +#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" +#include "lwip/debug.h" +#include "lwip/stats.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#if TCP_DEBUG +const char tcp_state_str_rodata[][12] ICACHE_RODATA_ATTR = { + "CLOSED", + "LISTEN", + "SYN_SENT", + "SYN_RCVD", + "ESTABLISHED", + "FIN_WAIT_1", + "FIN_WAIT_2", + "CLOSE_WAIT", + "CLOSING", + "LAST_ACK", + "TIME_WAIT" +}; + +char tcp_state_str[12]; +#endif + +/* Incremented every coarse grained timer shot (typically every 500 ms). */ +u32_t tcp_ticks; +const u8_t tcp_backoff[13] ICACHE_RODATA_ATTR = + { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + /* Times per slowtmr hits */ +const u8_t tcp_persist_backoff[7] ICACHE_RODATA_ATTR = { 3, 6, 12, 24, 48, 96, 120 }; + +/* The TCP PCB lists. */ + +/** List of all TCP PCBs bound but not yet (connected || listening) */ +struct tcp_pcb *tcp_bound_pcbs; +/** List of all TCP PCBs in LISTEN state */ +union tcp_listen_pcbs_t tcp_listen_pcbs; +/** List of all TCP PCBs that are in a state in which + * they accept or send data. */ +struct tcp_pcb *tcp_active_pcbs; +/** List of all TCP PCBs in TIME-WAIT state */ +struct tcp_pcb *tcp_tw_pcbs; + +#define NUM_TCP_PCB_LISTS 4 +#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 +/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ +struct tcp_pcb ** const tcp_pcb_lists[] ICACHE_RODATA_ATTR = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, + &tcp_active_pcbs, &tcp_tw_pcbs}; + +/** Only used for temporary storage. */ +struct tcp_pcb *tcp_tmp_pcb; + +/** Timer counter to handle calling slow-timer from tcp_tmr() */ +static u8_t tcp_timer; +static u16_t tcp_new_port(void);//����µ�tcp���ض˿� + +/** + * Called periodically to dispatch TCP timers. + * + */ +void +tcp_tmr(void) +{ + /* Call tcp_fasttmr() every 250 ms */ + tcp_fasttmr(); + + if (++tcp_timer & 1) { + /* Call tcp_tmr() every 500 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} + +/** + * Closes the TX side of a connection held by the PCB. + * For tcp_close(), a RST is sent if the application didn't receive all data + * (tcp_recved() not called for all data passed to recv callback). + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +static err_t +tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) +{ + err_t err; + + if (rst_on_unacked_data && (pcb->state != LISTEN)) { + if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { + /* Not all data received by application, send RST to tell the remote + side about this. */ + LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); + + /* don't call tcp_abort here: we must not deallocate the pcb since + that might not be expected when calling tcp_close */ + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + + tcp_pcb_purge(pcb); + + /* TODO: to which state do we move now? */ + + /* move to TIME_WAIT since we close actively */ + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + + return ERR_OK; + } + } + + switch (pcb->state) { + case CLOSED: + /* Closing a pcb in the CLOSED state might seem erroneous, + * however, it is in this state once allocated and as yet unused + * and the user needs some way to free it should the need arise. + * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) + * or for a pcb that has been used and then entered the CLOSED state + * is erroneous, but this should never happen as the pcb has in those cases + * been freed, and so any remaining handles are bogus. */ + /*��CLOSED״̬�¹ر�һ��pcb�ƺ��Ǵ���ģ� + *������ˣ�һ�������״̬�·����˶��һ�û��ʹ��,�û���ҪһЩ�취���ͷ��� + *����һ���Ѿ����رյ�pcb��tcp_close(),(��2��)����һ���Ѿ���ʹ����֮�󣬽���CLOSE״̬�Ǵ���� + *������Щ����±��ͷŵ�pcb�Dz�����ڵ�,��ˣ��κ�ʣ��ľ���Ǽٵ� + */ + err = ERR_OK;//�趨����ֵ + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + memp_free(MEMP_TCP_PCB, pcb);//��MEMP_TCP_PCB�ڴ���趨�ͷŵ���pcb��Ӧ�ĵ�Ԫֵ,�ͷ��ڴ� + pcb = NULL; + break; + case LISTEN: + err = ERR_OK; + tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);//�Ӽ����PCB�б���ɾ���Ӧ��pcb + memp_free(MEMP_TCP_PCB_LISTEN, pcb);//��MEMP_TCP_PCB_LISTEN�ڴ�����趨�ͷŵ�pcb��Ԫֵ ,�ͷ��ڴ� + pcb = NULL; + break; + case SYN_SENT: + err = ERR_OK; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + pcb = NULL; + snmp_inc_tcpattemptfails(); + break; + case SYN_RCVD: + err = tcp_send_fin(pcb);//���������ر�FIN���ֱ��� + if (err == ERR_OK) { + snmp_inc_tcpattemptfails(); + pcb->state = FIN_WAIT_1;//ת��FIN_WAIT_1״̬ + } + break; + case ESTABLISHED: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + snmp_inc_tcpestabresets(); + pcb->state = FIN_WAIT_1; + } + break; + case CLOSE_WAIT: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + snmp_inc_tcpestabresets(); + pcb->state = LAST_ACK;//����LAST_ACK�ȴ�ACK��ʱ + } + break; + default: + /* Has already been closed, do nothing. */ + err = ERR_OK; + pcb = NULL; + break; + } + + if (pcb != NULL && err == ERR_OK) { + /* To ensure all data has been sent when tcp_close returns, we have + to make sure tcp_output doesn't fail. + Since we don't really have to ensure all data has been sent when tcp_close + returns (unsent data is sent from tcp timer functions, also), we don't care + for the return value of tcp_output for now. */ + /* @todo: When implementing SO_LINGER, this must be changed somehow: + If SOF_LINGER is set, the data should be sent and acked before close returns. + This can only be valid for sequential APIs, not for the raw API. */ + tcp_output(pcb);//���ú����Ϳ��ƿ������ʣ��ı��ģ�����FIN���ֱ��Ķ� + } + return err; +} + +/** + * Closes the connection held by the PCB. + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it (unless an error is returned). + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ + /* + *ͨ��PCB�ر��������� + *�����е�pcbӦ�ñ��ͷŵģ�Ҳ����ԶҲ���ᱻʹ���� + *���û�����ӻ�����Ҳû�б�����,���ӵ�pcbӦ�ñ��ͷŵ� + *���һ�����ӱ�����(����SYN�Ѿ������ջ�����һ���ر��е�״̬) + *���ӱ��ر��ˣ�����������һ�����ڹرյ�״̬ + *pcb�Զ���tcp_slowtmr()�ͷ�,�����������Dz���ȫ�� + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ +#if TCP_DEBUG //TCP debug��Ϣ����ӡpcb��״̬ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ + + if (pcb->state != LISTEN) { + /* Set a flag not to receive any more data... */ + pcb->flags |= TF_RXCLOSED; + } + /* ... and close */ + return tcp_close_shutdown(pcb, 1); +} + +/** + * Causes all or part of a full-duplex connection of this PCB to be shut down. + * This doesn't deallocate the PCB! + * + * @param pcb PCB to shutdown + * @param shut_rx shut down receive side if this is != 0 + * @param shut_tx shut down send side if this is != 0 + * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) + * another err_t on error. + */ +err_t +tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) +{ + if (pcb->state == LISTEN) { + return ERR_CONN; + } + if (shut_rx) { + /* shut down the receive side: free buffered data... */ + if (pcb->refused_data != NULL) { + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + /* ... and set a flag not to receive any more data */ + pcb->flags |= TF_RXCLOSED; + } + if (shut_tx) { + /* This can't happen twice since if it succeeds, the pcb's state is changed. + Only close in these states as the others directly deallocate the PCB */ + switch (pcb->state) { + case SYN_RCVD: + case ESTABLISHED: + case CLOSE_WAIT: + return tcp_close_shutdown(pcb, 0); + default: + /* don't shut down other states */ + break; + } + } + /* @todo: return another err_t if not in correct state or already shut? */ + return ERR_OK; +} + +/** + * Abandons a connection and optionally sends a RST to the remote + * host. Deletes the local protocol control block. This is done when + * a connection is killed because of shortage of memory. + * + * @param pcb the tcp_pcb to abort + * @param reset boolean to indicate whether a reset should be sent + */ +void +tcp_abandon(struct tcp_pcb *pcb, int reset) +{ + u32_t seqno, ackno; + u16_t remote_port, local_port; + ip_addr_t remote_ip, local_ip; +#if LWIP_CALLBACK_API + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + void *errf_arg; + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", + pcb->state != LISTEN); + /* Figure out on which TCP PCB list we are, and remove us. If we + are in an active state, call the receive function associated with + the PCB with a NULL argument, and send an RST to the remote end. */ + if (pcb->state == TIME_WAIT) { + tcp_pcb_remove(&tcp_tw_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; + ip_addr_copy(local_ip, pcb->local_ip); + ip_addr_copy(remote_ip, pcb->remote_ip); + local_port = pcb->local_port; + remote_port = pcb->remote_port; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + tcp_pcb_remove(&tcp_active_pcbs, pcb); + if (pcb->unacked != NULL) { + tcp_segs_free(pcb->unacked); + } + if (pcb->unsent != NULL) { + tcp_segs_free(pcb->unsent); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + tcp_segs_free(pcb->ooseq); + } +#endif /* TCP_QUEUE_OOSEQ */ + if (reset) { + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); + tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); + } + TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); + memp_free(MEMP_TCP_PCB, pcb); + } +} + +/** + * Aborts the connection by sending a RST (reset) segment to the remote + * host. The pcb is deallocated. This function never fails. + * + * ATTENTION: When calling this from one of the TCP callbacks, make + * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + * or you will risk accessing deallocated memory or memory leaks! + * + * @param pcb the tcp pcb to abort + */ +void +tcp_abort(struct tcp_pcb *pcb) +{ + tcp_abandon(pcb, 1); +} + +/** + * Binds the connection to a local portnumber and IP address. If the + * IP address is not given (i.e., ipaddr == NULL), the IP address of + * the outgoing network interface is used instead. + * + * @param pcb the tcp_pcb to bind (no check is done whether this pcb is + * already bound!) + * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind + * to any local address + * @param port the local port to bind to + * @return ERR_USE if the port is already in use + * ERR_OK if bound + */ +err_t +tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) +{ + int i; + int max_pcb_list = NUM_TCP_PCB_LISTS; + struct tcp_pcb *cpcb; + + LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + +#if SO_REUSE + /* Unless the REUSEADDR flag is set, + we have to check the pcbs in TIME-WAIT state, also. + We do not dump TIME_WAIT pcb's; they can still be matched by incoming + packets using both local and remote IP addresses and ports to distinguish. + */ + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; + } +#endif /* SO_REUSE */ + + if (port == 0) { + port = tcp_new_port(); + } + + /* Check if the address already is in use (on all lists) */ + for (i = 0; i < max_pcb_list; i++) { + for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { +#if SO_REUSE + /* Omit checking for the same port if both pcbs have REUSEADDR set. + For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in + tcp_connect. */ + if (((pcb->so_options & SOF_REUSEADDR) == 0) || + ((cpcb->so_options & SOF_REUSEADDR) == 0)) +#endif /* SO_REUSE */ + { + if (ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + //os_printf("Address in use\n"); + return ERR_USE; + } + } + } + } + } + + if (!ip_addr_isany(ipaddr)) { + pcb->local_ip = *ipaddr; + } + pcb->local_port = port; + TCP_REG(&tcp_bound_pcbs, pcb); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); + return ERR_OK; +} +#if LWIP_CALLBACK_API +/** + * Default accept callback if no accept callback is specified by the user. + */ +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(err); + + return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + *��ij���󶨵Ŀ��ƿ���Ϊ����״̬ + * @param pcb the original tcp_pcb �����Ŀ��ƿ���� + * @param backlog the incoming connections queue limit + * @return tcp_pcb used for listening, consumes less memory.ָ������״̬�Ŀ��ƿ� + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen(tpcb); + */ +struct tcp_pcb * +tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + struct tcp_pcb_listen *lpcb; + + LWIP_UNUSED_ARG(backlog); + LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); + + /* already listening? */ + if (pcb->state == LISTEN) { + return pcb; + } +#if SO_REUSE + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage + is declared (listen-/connection-pcb), we have to make sure now that + this port is only used once for every local IP. */ + for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if (lpcb->local_port == pcb->local_port) { + if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + /* this address/port is already used */ + return NULL; + } + } + } + } +#endif /* SO_REUSE */ + lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);//�����ڴ�ؿռ� + if (lpcb == NULL) { + return NULL; + } + lpcb->callback_arg = pcb->callback_arg; + lpcb->local_port = pcb->local_port; + lpcb->state = LISTEN; + lpcb->prio = pcb->prio; + lpcb->so_options = pcb->so_options; + lpcb->so_options |= SOF_ACCEPTCONN; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; + ip_addr_copy(lpcb->local_ip, pcb->local_ip); + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + memp_free(MEMP_TCP_PCB, pcb); +#if LWIP_CALLBACK_API + lpcb->accept = tcp_accept_null;//���ܿͻ������ӵ�Ĭ�ϻص����� +#endif /* LWIP_CALLBACK_API */ +#if TCP_LISTEN_BACKLOG + lpcb->accepts_pending = 0; + lpcb->backlog = (backlog ? backlog : 1); +#endif /* TCP_LISTEN_BACKLOG */ + TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);//���ƿ����tcp_listen_pcbs�����ײ� + return (struct tcp_pcb *)lpcb; +} + +/** + * Update the state that tracks the available window space to advertise. + * + * Returns how much extra window would be advertised if we sent an + * update now. + */ +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) +{ + u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; + + if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { + /* we can advertise more window */ + pcb->rcv_ann_wnd = pcb->rcv_wnd; + return new_right_edge - pcb->rcv_ann_right_edge; + } else { + if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { + /* Can happen due to other end sending out of advertised window, + * but within actual available (but not yet advertised) window */ + pcb->rcv_ann_wnd = 0; + } else { + /* keep the right edge of window constant */ + u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; + LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); + pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd; + } + return 0; + } +} + +/** + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + *Ӧ�ó�����ݴ�����Ϻ�֪ͨ�ں˸��½��մ��� + * @param pcb the tcp_pcb for which data is read + * @param len the amount of bytes that have been read by the application + */ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ + int wnd_inflation; + + LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", + len <= 0xffff - pcb->rcv_wnd ); + + pcb->rcv_wnd += len; + if (pcb->rcv_wnd > TCP_WND) { + pcb->rcv_wnd = TCP_WND; + } + + wnd_inflation = tcp_update_rcv_ann_wnd(pcb); + + /* If the change in the right edge of window is significant (default + * watermark is TCP_WND/4), then send an explicit update now. + * Otherwise wait for a packet to be sent in the normal course of + * events (or more window to be available later) */ + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { + tcp_ack_now(pcb); + tcp_output(pcb); + } + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", + len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); +} + +/** + * A nastly hack featuring 'goto' statements that allocates a + * new TCP local port. + * + * @return a new (free) local TCP port number + */ +static u16_t +tcp_new_port(void) +{ + int i; + struct tcp_pcb *pcb; +#ifndef TCP_LOCAL_PORT_RANGE_START +#define TCP_LOCAL_PORT_RANGE_START 1024 +#define TCP_LOCAL_PORT_RANGE_END 0x7fff +#endif + static u16_t port = TCP_LOCAL_PORT_RANGE_START; + + again: +// if (++port >= TCP_LOCAL_PORT_RANGE_END) { +// port = TCP_LOCAL_PORT_RANGE_START; +// } + port = os_random(); + port %= TCP_LOCAL_PORT_RANGE_END; + if (port < TCP_LOCAL_PORT_RANGE_START) + port += TCP_LOCAL_PORT_RANGE_START; + /* Check all PCB lists. */ + for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { + for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == port) { + goto again; + } + } + } + return port; +} + +/** + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + *�����������һ��SYN���ֱ��� + * @param pcb the tcp_pcb used to establish the connection �����Ŀ��ƿ���� + * @param ipaddr the remote ip address to connect to ������IP��ַ + * @param port the remote tcp port to connect to �������˿ں� + * @param connected callback function to call when connected (or on error) + * @return ERR_VAL if invalid arguments are given + * ERR_OK if connect request has been sent + * other err_t values if connect request couldn't be sent + */ +err_t +tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, + tcp_connected_fn connected) +{ + err_t ret; + u32_t iss; + u16_t old_local_port; + + LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); + if (ipaddr != NULL) { + pcb->remote_ip = *ipaddr;//������IP��ַ��Ч�������Ӽ�¼�м�¼��IP��ַ�����ò·µ»Ø´ï¿½ï¿½ï¿½ + } else { + return ERR_VAL; + } + pcb->remote_port = port;//��¼�������˿�(Ŀ�Ķ˿�) + + /* check if we have a route to the remote host */ + if (ip_addr_isany(&(pcb->local_ip))) { + /* no local IP address set, yet. */ + struct netif *netif = ip_route(&(pcb->remote_ip)); + if (netif == NULL) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } + /* Use the netif's IP address as local address. */ + ip_addr_copy(pcb->local_ip, netif->ip_addr); + } + + old_local_port = pcb->local_port; + if (pcb->local_port == 0) { + pcb->local_port = tcp_new_port(); + + } +#if SO_REUSE + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure + now that the 5-tuple is unique. */ + struct tcp_pcb *cpcb; + int i; + /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ + for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { + for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if ((cpcb->local_port == pcb->local_port) && + (cpcb->remote_port == port) && + ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && + ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { + /* linux returns EISCONN here, but ERR_USE should be OK for us */ + return ERR_USE; + } + } + } + } +#endif /* SO_REUSE */ + iss = tcp_next_iss();//��ʼ����� + pcb->rcv_nxt = 0;//���÷��ʹ��ڵĸ����ֶ� + pcb->snd_nxt = iss; + pcb->lastack = iss - 1; + pcb->snd_lbb = iss - 1; + pcb->rcv_wnd = TCP_WND;//����Ĭ�Ͻ��մ��ڸ����ֶ�ֵ + pcb->rcv_ann_wnd = TCP_WND; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->snd_wnd = TCP_WND; + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;//��ʼ������Ķδ�С +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + pcb->cwnd = 1;//��ʼ������� + pcb->ssthresh = pcb->mss * 10; +#if LWIP_CALLBACK_API + pcb->connected = connected;//ע��connected�ص����� +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(connected); +#endif /* LWIP_CALLBACK_API */ + + /* Send a SYN together with the MSS option. */ + ret = tcp_enqueue_flags(pcb, TCP_SYN); + if (ret == ERR_OK) { + /* SYN segment was enqueued, changed the pcbs state now ���ƿ�����ΪSYN_SENT ״̬*/ + pcb->state = SYN_SENT; + if (old_local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + TCP_REG(&tcp_active_pcbs, pcb); + snmp_inc_tcpactiveopens(); + + tcp_output(pcb);//�����ƿ������ӵı��ķ��ͳ�ȥ + } + return ret; +} + +/** + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_slowtmr(void) +{ + struct tcp_pcb *pcb, *prev; + u16_t eff_wnd; + u8_t pcb_remove; /* flag if a PCB should be removed */ + u8_t pcb_reset; /* flag if a RST should be sent when removing */ + err_t err; + + err = ERR_OK; + + ++tcp_ticks; + + /* Steps through all of the active PCBs. */ + prev = NULL; + pcb = tcp_active_pcbs; + if (pcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); + } + while (pcb != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + + pcb_remove = 0; + pcb_reset = 0; + + if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); + } + else if (pcb->nrtx == TCP_MAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); + } else { + if (pcb->persist_backoff > 0) { + /* If snd_wnd is zero, use persist timer to send 1 byte probes + * instead of using the standard retransmission mechanism. */ + pcb->persist_cnt++; + if (pcb->persist_cnt >= system_get_data_of_array_8(tcp_persist_backoff, pcb->persist_backoff-1)) { + pcb->persist_cnt = 0; + if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { + pcb->persist_backoff++; + } + tcp_zero_window_probe(pcb); + } + } else { + /* Increase the retransmission timer if it is running */ + if(pcb->rtime >= 0) + ++pcb->rtime; + + if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { + /* Time for a retransmission. */ + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F + " pcb->rto %"S16_F"\n", + pcb->rtime, pcb->rto)); + + /* Double retransmission time-out unless we are trying to + * connect to somebody (i.e., we are in SYN_SENT). */ + if (pcb->state != SYN_SENT) { + pcb->rto = ((pcb->sa >> 3) + pcb->sv) << system_get_data_of_array_8(tcp_backoff, pcb->nrtx); +// if (pcb->rto >= TCP_MAXRTO) +// pcb->rto >>= 1; + } + + /* Reset the retransmission timer. */ + pcb->rtime = 0; + + /* Reduce congestion window and ssthresh. */ + eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); + pcb->ssthresh = eff_wnd >> 1; + if (pcb->ssthresh < (pcb->mss << 1)) { + pcb->ssthresh = (pcb->mss << 1); + } + pcb->cwnd = pcb->mss; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F + " ssthresh %"U16_F"\n", + pcb->cwnd, pcb->ssthresh)); + + /* The following needs to be called AFTER cwnd is set to one + mss - STJ */ + tcp_rexmit_rto(pcb); + } + } + } + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if (pcb->state == FIN_WAIT_2) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); + } + } + + /* Check if KEEPALIVE should be sent */ + if((pcb->so_options & SOF_KEEPALIVE) && + ((pcb->state == ESTABLISHED) || + (pcb->state == CLOSE_WAIT))) { +#if LWIP_TCP_KEEPALIVE + if((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) + / TCP_SLOW_INTERVAL) +#else + if((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ + { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + + ++pcb_remove; + ++pcb_reset; + } +#if LWIP_TCP_KEEPALIVE + else if((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) + / TCP_SLOW_INTERVAL) +#else + else if((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) + / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ + { + tcp_keepalive(pcb); + pcb->keep_cnt_sent++; + } + } + + /* If this PCB has queued out of sequence data, but has been + inactive for too long, will drop the data (it will eventually + be retransmitted). */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL && + (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if (pcb->state == SYN_RCVD) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); + } + } + + /* Check if this PCB has stayed too long in LAST-ACK */ + if (pcb->state == LAST_ACK) { + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); + } + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + if (pcb_reset) { + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + } + + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + } else { + /* get the 'next' element now and work with 'prev' below (in case of abort) */ + prev = pcb; + pcb = pcb->next; + + /* We check if we should poll the connection. */ + ++prev->polltmr; + if (prev->polltmr >= prev->pollinterval) { + prev->polltmr = 0; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + TCP_EVENT_POLL(prev, err); + /* if err == ERR_ABRT, 'prev' is already deallocated */ + if (err == ERR_OK) { + tcp_output(prev); + } + } + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while (pcb != NULL) { + LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb = tcp_active_pcbs; + + while(pcb != NULL) { + struct tcp_pcb *next = pcb->next; + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + /* Notify again application with data previously received. */ + err_t err; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); + TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); + if (err == ERR_OK) { + pcb->refused_data = NULL; + } else if (err == ERR_ABRT) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + pcb = NULL; + } + } + + /* send delayed ACKs */ + if (pcb && (pcb->flags & TF_ACK_DELAY)) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + tcp_output(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + + pcb = next; + } +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + * @param seg tcp_seg list of TCP segments to free + */ +void +tcp_segs_free(struct tcp_seg *seg) +{ + while (seg != NULL) { + struct tcp_seg *next = seg->next; + tcp_seg_free(seg); + seg = next; + } +} + +/** + * Frees a TCP segment (tcp_seg structure). + * + * @param seg single tcp_seg to free + */ +void +tcp_seg_free(struct tcp_seg *seg) +{ + if (seg != NULL) { + if (seg->p != NULL) { + pbuf_free(seg->p); +#if TCP_DEBUG + seg->p = NULL; +#endif /* TCP_DEBUG */ + } + memp_free(MEMP_TCP_SEG, seg); + } +} + +/** + * Sets the priority of a connection. + * + * @param pcb the tcp_pcb to manipulate + * @param prio new priority + */ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ + pcb->prio = prio; +} + +#if TCP_QUEUE_OOSEQ +/** + * Returns a copy of the given TCP segment. + * The pbuf and data are not copied, only the pointers + * + * @param seg the old tcp_seg + * @return a copy of seg + */ +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ + struct tcp_seg *cseg; + + cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); + if (cseg == NULL) { + return NULL; + } + SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); + pbuf_ref(cseg->p); + return cseg; +} +#endif /* TCP_QUEUE_OOSEQ */ + +#if LWIP_CALLBACK_API +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } else if (err == ERR_OK) { + return tcp_close(pcb); + } + return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Kills the oldest active connection that has lower priority than prio. + * + * @param prio minimum priority + */ +static void ICACHE_FLASH_ATTR +tcp_kill_prio(u8_t prio) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + u8_t mprio; + + + mprio = TCP_PRIO_MAX; + + /* We kill the oldest active connection that has lower priority than prio. */ + inactivity = 0; + inactive = NULL; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->prio <= prio && + pcb->prio <= mprio && + (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + mprio = pcb->prio; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/** + * Kills the oldest connection that is in TIME_WAIT state. + * Called from tcp_alloc() if no more connections are available. + */ +static void ICACHE_FLASH_ATTR +tcp_kill_timewait(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/** + * Allocate a new tcp_pcb structure. + *����һ��TCP���ƿ�ṹ������ʼ������ֶ� + * @param prio priority for the new pcb �¿��ƿ�����ȼ� + * @return a new tcp_pcb that initially is in state CLOSED ָ���¿��ƿ��ָ�� + */ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + u32_t iss; + + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);//�����ڴ�ؿռ� + if (pcb == NULL) { + //os_printf("tcp_pcb memory is fail\n"); + /* Try killing oldest connection in TIME-WAIT. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); + tcp_kill_timewait(); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing active connections with lower priority than the new one. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); + tcp_kill_prio(prio); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed twice before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: timewait PCB was freed above */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + os_memset(pcb, 0, sizeof(struct tcp_pcb)); //��0 + pcb->prio = prio; //�������ȼ� + pcb->snd_buf = TCP_SND_BUF; //��ʹ�õķ��ͻ������С + pcb->snd_queuelen = 0; //��������ռ�õ�pbuf���� + pcb->rcv_wnd = TCP_WND; //���մ��� + pcb->rcv_ann_wnd = TCP_WND; //ͨ����մ��� + pcb->tos = 0; //�������� + pcb->ttl = TCP_TTL; //ttl�ֶ� + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; //��ʼ������Ķ� + pcb->rto = 1000 / TCP_SLOW_INTERVAL; //��ʼ����ʱʱ�� + pcb->sa = 0; //��ʼ����RTT��صIJ��� + pcb->sv = 1000 / TCP_SLOW_INTERVAL; + pcb->rtime = -1; + pcb->cwnd = 1; //��ʼ������� + iss = tcp_next_iss(); //��ó�ʼ���к� + pcb->snd_wl2 = iss; //��ʼ�����ʹ��ڸ����ֶ� + pcb->snd_nxt = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + pcb->tmr = tcp_ticks; //��¼���ƿ鴴��ϵͳʱ�� + + pcb->polltmr = 0; //����������¼���ʱ�� + +#if LWIP_CALLBACK_API + pcb->recv = tcp_recv_null; //ע�������ݵ�Ĭ���ϲ㺯�� +#endif /* LWIP_CALLBACK_API */ + + /* Init KEEPALIVE timer */ + pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; + +#if LWIP_TCP_KEEPALIVE + pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; + pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; +#endif /* LWIP_TCP_KEEPALIVE */ + + pcb->keep_cnt_sent = 0; //���ķ��ʹ��� + } + return pcb; +} + +/** + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * + * @internal: Maybe there should be a idle TCP PCB list where these + * PCBs are put on. Port reservation using tcp_bind() is implemented but + * allocated pcbs that are not bound can't be killed automatically if wanting + * to allocate a pcb with higher prio (@see tcp_kill_prio()) + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new(void) +{ + return tcp_alloc(TCP_PRIO_NORMAL); +} + +/** + * Used to specify the argument that should be passed callback + * functions. + *����ƿ��callback_arg�ֶ�ע���û���ݣ���tcp_recv�Ⱥ���ص�ʱ�� +* ���ֶν���Ϊ����ݸ�������� + * @param pcb tcp_pcb to set the callback argument + * @param arg void pointer argument to pass to callback functions + */ +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{ + pcb->callback_arg = arg; +} +#if LWIP_CALLBACK_API + +/** + * Used to specify the function that should be called when a TCP + * connection receives data. + *����ƿ��recv�ֶ�ע�ắ���յ����ʱ�ص� + * @param pcb tcp_pcb to set the recv callback + * @param recv callback function to call for this pcb when data is received + */ +void +tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) +{ + pcb->recv = recv; +} + +/** + * Used to specify the function that should be called when TCP data + * has been successfully delivered to the remote host. + *����ƿ�send �ֶ�ע�ắ����ݷ��ͳɹ���ص� + * @param pcb tcp_pcb to set the sent callback + * @param sent callback function to call for this pcb when data is successfully sent + */ +void +tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) +{ + pcb->sent = sent; +} + +/** + * Used to specify the function that should be called when a fatal error + * has occured on the connection. + *����ƿ�err �ֶ�ע�ắ�����������ص� + * @param pcb tcp_pcb to set the err callback + * @param err callback function to call for this pcb when a fatal error + * has occured on the connection + */ +void +tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) +{ + pcb->errf = err; +} + +/** + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + *����ƿ��accept�ֶ�ע�ắ����������ʱ�ص� + * @param pcb tcp_pcb to set the accept callback + * @param accept callback function to call for this pcb when LISTENing + * connection has been connected to another host + */ +void +tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) +{ + pcb->accept = accept; +} +#endif /* LWIP_CALLBACK_API */ + + +/** + * Used to specify the function that should be called periodically + * from TCP. The interval is specified in terms of the TCP coarse + * timer interval, which is called twice a second. + *����ƿ��POLL�ֶ�ע�ắ��ú��������Ա����� + */ +void +tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) +{ +#if LWIP_CALLBACK_API + pcb->poll = poll; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(poll); +#endif /* LWIP_CALLBACK_API */ + pcb->pollinterval = interval; +} + +/** + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory + * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). + * + * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! + */ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ + if (pcb->state != CLOSED && + pcb->state != TIME_WAIT && + pcb->state != LISTEN) { + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + +#if TCP_LISTEN_BACKLOG + if (pcb->state == SYN_RCVD) { + /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ + struct tcp_pcb_listen *lpcb; + LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", + tcp_listen_pcbs.listen_pcbs != NULL); + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((lpcb->local_port == pcb->local_port) && + (ip_addr_isany(&lpcb->local_ip) || + ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { + /* port and address of the listen pcb match the timed-out pcb */ + LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", + lpcb->accepts_pending > 0); + lpcb->accepts_pending--; + break; + } + } + } +#endif /* TCP_LISTEN_BACKLOG */ + + + if (pcb->refused_data != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + if (pcb->unsent != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); + } + if (pcb->unacked != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); + } + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ + + /* Stop the retransmission timer as it will expect data on unacked + queue if it fires */ + pcb->rtime = -1; + + tcp_segs_free(pcb->unsent); + tcp_segs_free(pcb->unacked); + pcb->unacked = pcb->unsent = NULL; +#if TCP_OVERSIZE + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + } +} + +/** + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + * @param pcblist PCB list to purge. + * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! + */ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ + TCP_RMV(pcblist, pcb); + + tcp_pcb_purge(pcb); + + /* if there is an outstanding delayed ACKs, send it */ + if (pcb->state != TIME_WAIT && + pcb->state != LISTEN && + pcb->flags & TF_ACK_DELAY) { + pcb->flags |= TF_ACK_NOW; + tcp_output(pcb); + } + + if (pcb->state != LISTEN) { + LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); + LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); +#if TCP_QUEUE_OOSEQ + LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); +#endif /* TCP_QUEUE_OOSEQ */ + } + + pcb->state = CLOSED; + + LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} + +/** + * Calculates a new initial sequence number for new connections. + * + * @return u32_t pseudo random sequence number + */ +u32_t +tcp_next_iss(void) +{ + static u32_t iss = 6510; + + again: + iss += tcp_ticks; /* XXX */ + if (iss == 0) + goto again; + + return iss; +} + +#if TCP_CALCULATE_EFF_SEND_MSS +/** + * Calcluates the effective send mss that can be used for a specific IP address + * by using ip_route to determin the netif used to send to the address and + * calculating the minimum of TCP_MSS and that netif's mtu (if set). + */ +u16_t +tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) +{ + u16_t mss_s; + struct netif *outif; + + outif = ip_route(addr); + if ((outif != NULL) && (outif->mtu != 0)) { + mss_s = outif->mtu - IP_HLEN - TCP_HLEN; + /* RFC 1122, chap 4.2.2.6: + * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize + * We correct for TCP options in tcp_write(), and don't support IP options. + */ + sendmss = LWIP_MIN(sendmss, mss_s); + } + return sendmss; +} +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if TCP_DEBUG +const char* +tcp_debug_state_str(enum tcp_state s) +{ + system_get_string_from_flash(tcp_state_str_rodata[s], tcp_state_str, 12); + + return tcp_state_str; +} +#endif + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +/** + * Print a tcp header for debugging purposes. + * + * @param tcphdr pointer to a struct tcp_hdr + */ +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ + LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + ntohs(tcphdr->src), ntohs(tcphdr->dest))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", + ntohl(tcphdr->seqno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", + ntohl(tcphdr->ackno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", + TCPH_HDRLEN(tcphdr), + TCPH_FLAGS(tcphdr) >> 5 & 1, + TCPH_FLAGS(tcphdr) >> 4 & 1, + TCPH_FLAGS(tcphdr) >> 3 & 1, + TCPH_FLAGS(tcphdr) >> 2 & 1, + TCPH_FLAGS(tcphdr) >> 1 & 1, + TCPH_FLAGS(tcphdr) & 1, + ntohs(tcphdr->wnd))); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", + ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} + +/** + * Print a tcp state for debugging purposes. + * + * @param s enum tcp_state to print + */ +void +tcp_debug_print_state(enum tcp_state s) +{ + LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); +} + +/** + * Print tcp flags for debugging purposes. + * + * @param flags tcp flags, all active flags are printed + */ +void +tcp_debug_print_flags(u8_t flags) +{ + if (flags & TCP_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); + } + if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); + } + if (flags & TCP_RST) { + LWIP_DEBUGF(TCP_DEBUG, ("RST ")); + } + if (flags & TCP_PSH) { + LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); + } + if (flags & TCP_ACK) { + LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); + } + if (flags & TCP_URG) { + LWIP_DEBUGF(TCP_DEBUG, ("URG ")); + } + if (flags & TCP_ECE) { + LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); + } + if (flags & TCP_CWR) { + LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); +} + +/** + * Print all tcp_pcbs in every list for debugging purposes. + */ +void +tcp_debug_print_pcbs(void) +{ + struct tcp_pcb *pcb; + LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); + for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } +} + +/** + * Check state consistency of the tcp_pcb lists. + */ +s16_t +tcp_pcbs_sane(void) +{ + struct tcp_pcb *pcb; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + } + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + } + return 1; +} +#endif /* TCP_DEBUG */ + +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_in.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_in.c new file mode 100755 index 0000000000..be74a28aca --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_in.c @@ -0,0 +1,1637 @@ +/** + * @file + * Transmission Control Protocol, incoming traffic + * + * The input processing functions of the TCP layer. + * + * These functions are generally called in the order (ip_input() ->) + * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp_impl.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/* These variables are global to all functions involved in the input + processing of TCP segments. They are set by the tcp_input() + function. */ +static struct tcp_seg inseg; //tcp_seg�ṹ����������ı��Ķ� +static struct tcp_hdr *tcphdr; //���Ķ���TCP�ײ� +static struct ip_hdr *iphdr; //IP��ݰ��ײ� +static u32_t seqno, ackno; //TCP�ײ�������ֶ���ȷ�Ϻ��ֶ� +static u8_t flags; //�ײ���־�ֶ� +static u16_t tcplen; //TCP���ij��� + +static u8_t recv_flags; //��ǰ���Ĵ����� +static struct pbuf *recv_data; //���Ķ����pbuf + +struct tcp_pcb *tcp_input_pcb; //��ǰ���Ŀ��ƿ� + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +static void tcp_receive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +static void tcp_parseopt(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +static err_t tcp_listen_input(struct tcp_pcb_listen *pcb)ICACHE_FLASH_ATTR; +static err_t tcp_timewait_input(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +/** + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + * + * @param p received TCP segment to process (p->payload pointing to the IP header) + * @param inp network interface on which this segment was received + */ + /** + * TCP��ʼ�����봦�?��֤��TCPͷ���������IP����� + + * @����p:������յ�TCP��(ָ��IPͷ�ĸ���) + * @����inp:���նε�����ӿ� + */ +void +tcp_input(struct pbuf *p, struct netif *inp) +{ + struct tcp_pcb *pcb, *prev; + struct tcp_pcb_listen *lpcb; +#if SO_REUSE + struct tcp_pcb *lpcb_prev = NULL; + struct tcp_pcb_listen *lpcb_any = NULL; +#endif /* SO_REUSE */ + u8_t hdrlen; + err_t err; + + PERF_START; + + TCP_STATS_INC(tcp.recv); //״̬��1 + snmp_inc_tcpinsegs(); //tcp����μ�1 + + iphdr = (struct ip_hdr *)p->payload;// pointer to the actual data in the buffer + /* + *��ͷ����(IHL)��4�IPЭ���ͷ�ij��ȣ�ָ��IPv4Э���ͷ���ȵ��ֽ������ٸ�32� + *����IPv4�İ�ͷ���ܰ�ɱ������Ŀ�ѡ ���������ֶο�������ȷ��IPv4��ݱ�����ݲ��ֵ�ƫ������ + *IPv4��ͷ����С������20���ֽڣ����IHL����ֶε���Сֵ��ʮ���Ʊ�ʾ����5 (5x4 = 20�ֽ�)�� + *����˵�����ʾ�İ�ͷ�����ֽ�����4�ֽڵı��� + */ + tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); + +#if TCP_INPUT_DEBUG + tcp_debug_print(tcphdr); +#endif + + /* remove header from payload */ + if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); + TCP_STATS_INC(tcp.lenerr);//���󳤶ȼ��� + TCP_STATS_INC(tcp.drop);//��ֹ���� + snmp_inc_tcpinerrs(); + pbuf_free(p);//�ͷ�buffer + return; + } + + /* Don't even process incoming broadcasts/multicasts. */ + if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || + ip_addr_ismulticast(¤t_iphdr_dest)) { + TCP_STATS_INC(tcp.proterr);//�������� + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } + +#if CHECKSUM_CHECK_TCP + /* Verify TCP checksum. */ + if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), + IP_PROTO_TCP, p->tot_len) != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), + IP_PROTO_TCP, p->tot_len))); +#if TCP_DEBUG + tcp_debug_print(tcphdr); +#endif /* TCP_DEBUG */ + TCP_STATS_INC(tcp.chkerr);//�������� + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } +#endif + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + hdrlen = TCPH_HDRLEN(tcphdr);//����ͷ�ij��� + if(pbuf_header(p, -(hdrlen * 4))){//���TCPͷ������0Ϊ�ɹ������� + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); + TCP_STATS_INC(tcp.lenerr);//tcp���ȴ������ + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = ntohs(tcphdr->src); //ת��Դ��ַ + tcphdr->dest = ntohs(tcphdr->dest); //ת��Ŀ�ĵ�ַ + seqno = tcphdr->seqno = ntohl(tcphdr->seqno); //ת�����к� + ackno = tcphdr->ackno = ntohl(tcphdr->ackno); //ת��Ӧ��� + tcphdr->wnd = ntohs(tcphdr->wnd); //ת��tcp���� + + flags = TCPH_FLAGS(tcphdr);//�õ�tcp header�ı�־ + /* + *��־��3λ�����ֶΣ��� + * �����1λ + * ���ֶ�λ��1λ��ȡֵ��0��������ݱ��ֶΣ���1����ݱ����ֶܷΣ� + * �����1λ��ȡֵ��0����ݰ����û�а�1����ݰ�����и��İ� + */ + tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);//TCP_FIN �� TCP_SYN ���1�������0 + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. ���ȣ�����Ƿ�һ��Ҫ����һ������*/ + //////////////////////////////////////////////////////////////////////////////////////// + prev = NULL; + for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {//������б� + LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {//�����صĵ�ַ + + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); + if (prev != NULL) {//���ǰһ���ڵ㲻Ϊ�� + prev->next = pcb->next; + pcb->next = tcp_active_pcbs; + tcp_active_pcbs = pcb;//pcb������ǰ�� + } + LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); + break; + } + prev = pcb;//prevָ��pcb + } + + if (pcb == NULL) { + /* If it did not go to an active connection, we check the connections + in the TIME-WAIT state. */ + for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {//����ȴ�״̬�µ�pcb + LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { + /* We don't really care enough to move this PCB to the front + of the list since we are not very likely to receive that + many segments for connections in TIME-WAIT. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); + tcp_timewait_input(pcb);//����tcp timewait �� + pbuf_free(p); + return; + } + } + + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ + prev = NULL; + for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {//�������״̬�����е�pcb + if (lpcb->local_port == tcphdr->dest) { +#if SO_REUSE + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { + /* found an exact match */ + break; + } else if(ip_addr_isany(&(lpcb->local_ip))) { + /* found an ANY-match */ + lpcb_any = lpcb; + lpcb_prev = prev; + } +#else /* SO_REUSE */ + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || + ip_addr_isany(&(lpcb->local_ip))) { + /* found a match */ + break; + } +#endif /* SO_REUSE */ + } + prev = (struct tcp_pcb *)lpcb; + } +#if SO_REUSE + /* first try specific local IP */ + if (lpcb == NULL) { + /* only pass to ANY if no specific local IP has been found */ + lpcb = lpcb_any; + prev = lpcb_prev; + } +#endif /* SO_REUSE */ + if (lpcb != NULL) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if (prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb);//����tcp������ݰ� + pbuf_free(p); + return; + } + } + +#if TCP_INPUT_DEBUG + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + + if (pcb != NULL) { + /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + + /* Set up a tcp_seg structure. */ + inseg.next = NULL; + inseg.len = p->tot_len; + inseg.p = p; + inseg.tcphdr = tcphdr; + + recv_data = NULL; + recv_flags = 0; + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + /* Notify again application with data previously received. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); + TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);//pcb������� + if (err == ERR_OK) { + pcb->refused_data = NULL; + } else if ((err == ERR_ABRT) || (tcplen > 0)) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + /* Drop incoming packets because pcb is "full" (only if the incoming + segment contains data). */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); + TCP_STATS_INC(tcp.drop);//tcp������� + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } + } + tcp_input_pcb = pcb;//��¼��ǰ���Ĵ���Ŀ��ƿ� + err = tcp_process(pcb);//���?�� + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if (err != ERR_ABRT) { + if (recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb);//ɾ���pcb�б��е�pcb + memp_free(MEMP_TCP_PCB, pcb); + } else if (recv_flags & TF_CLOSED) { + /* The connection has been closed and we will deallocate the + PCB. */ + if (!(pcb->flags & TF_RXCLOSED)) { + /* Connection closed although the application has only shut down the + tx side: call the PCB's err callback and indicate the closure to + ensure the application doesn't continue using the PCB. */ + TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD); + } + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + err = ERR_OK; + /* If the application has registered a "sent" function to be + called when new send buffer space is available, we call it + now. */ + if (pcb->acked > 0) { + TCP_EVENT_SENT(pcb, pcb->acked, err);//����ݱ�ȷ�ϣ��ص��û���send���� + if (err == ERR_ABRT) { + goto aborted; + } + } + + if (recv_data != NULL) {//����ݽ��յ� + LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); + if (pcb->flags & TF_RXCLOSED) { + /* received data although already closed -> abort (send RST) to + notify the remote host that not all data has been processed */ + pbuf_free(recv_data); + tcp_abort(pcb); + goto aborted; + } + + //PSH��־ PSH ����� + //��PSH=1ʱ��Ҫ���ͷ����Ϸ��͸÷ֶΣ� + //����շ�����Ľ����Ľ���Ӧ�ò㣬�������д��? + + if (flags & TCP_PSH) { + recv_data->flags |= PBUF_FLAG_PUSH;//���bufferӦ������������ + } + + /* Notify application that data has been received. */ + TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + if (err == ERR_ABRT) { + goto aborted; + } + + /* If the upper layer can't receive this data, store it */ + if (err != ERR_OK) { + pcb->refused_data = recv_data; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); + } + } + + /* If a FIN segment was received, we call the callback + function with a NULL buffer to indicate EOF. */ + if (recv_flags & TF_GOT_FIN) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto aborted; + } + } + + tcp_input_pcb = NULL;//���ȫ�ֱ��� + /* Try to send something out. */ + tcp_output(pcb);//����������� +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + } + } + /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). + Below this line, 'pcb' may not be dereferenced! */ +aborted: + tcp_input_pcb = NULL; + recv_data = NULL; + + /* give up our reference to inseg.p */ + if (inseg.p != NULL) + { + pbuf_free(inseg.p);//�ͷ�buffer + inseg.p = NULL; + } + + /*add processing queue segments that arrive out of order by LiuHan*/ +#if TCP_QUEUE_OOSEQ + extern char RxNodeNum(void); + if (RxNodeNum() < 2){ + extern void pbuf_free_ooseq_new(void* arg); +// os_printf("reclaim some memory from queued\n"); + pbuf_free_ooseq_new(NULL); + } +#endif + } else { + + /* If no matching PCB was found, send a TCP RST (reset) to the + sender. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); + if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { + TCP_STATS_INC(tcp.proterr);//�������� + TCP_STATS_INC(tcp.drop);//tcp������� + tcp_rst(ackno, seqno + tcplen, + ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src);//����TCP��λ + } + pbuf_free(p); + } + + LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); +} + +/** + * Called by tcp_input() when a segment arrives for a listening + * connection (from tcp_input()). + * + * @param pcb the tcp_pcb_listen for which a segment arrived + * @return ERR_OK if the segment was processed + * another err_t on error + * + * @note the return value is not (yet?) used in tcp_input() + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ + /* +*����LISTEN״̬�Ŀ��ƿ���øú��� +*ͨ���Ƿ�������������һ���˿ڲ�����ͻ���SYN�������� +* +*/ +static err_t +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + struct tcp_pcb *pactive_pcb; + u8_t active_pcb_num = 0; + err_t rc; + + /* In the LISTEN state, we check for incoming SYN segments, + creates a new PCB, and responds with a SYN|ACK. */ + if (flags & TCP_ACK) { + /* For incoming segments with the ACK flag set, respond with a + RST. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); + tcp_rst(ackno + 1, seqno + tcplen, + ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } else if (flags & TCP_SYN) {//�յ�SYN���� + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); +#if TCP_LISTEN_BACKLOG + if (pcb->accepts_pending >= pcb->backlog) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); + return ERR_ABRT; + } +#endif /* TCP_LISTEN_BACKLOG */ + for(pactive_pcb = tcp_active_pcbs; pactive_pcb != NULL; pactive_pcb = pactive_pcb->next){ + if (pactive_pcb->state == ESTABLISHED){ + active_pcb_num ++; + } + } + if (active_pcb_num == MEMP_NUM_TCP_PCB){ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: exceed the number of active TCP connections\n")); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + npcb = tcp_alloc(pcb->prio);//�������ƿ� + /* If a new PCB could not be created (probably due to lack of memory), + we don't do anything, but rely on the sender will retransmit the + SYN at a time when we have more memory available. */ + if (npcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); + TCP_STATS_INC(tcp.memerr);//TCP�ڴ������� + return ERR_MEM; + } + +#if TCP_LISTEN_BACKLOG + pcb->accepts_pending++; +#endif /* TCP_LISTEN_BACKLOG */ + /* Set up the new PCB. */ + //���ƿ���������ص�4���ֶ� + ip_addr_copy(npcb->local_ip, current_iphdr_dest); + npcb->local_port = pcb->local_port; + ip_addr_copy(npcb->remote_ip, current_iphdr_src); + npcb->remote_port = tcphdr->src; + + //���ƿ��������ֶ� + npcb->state = SYN_RCVD;//��������״̬ + npcb->rcv_nxt = seqno + 1;//������һ������������ + npcb->rcv_ann_right_edge = npcb->rcv_nxt; + npcb->snd_wnd = tcphdr->wnd;//���÷��ʹ��� + npcb->ssthresh = npcb->snd_wnd; + npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ + npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API + npcb->accept = pcb->accept; +#endif /* LWIP_CALLBACK_API */ + /* inherit socket options */ + npcb->so_options = pcb->so_options & SOF_INHERITED; + /* Register the new PCB so that we can begin receiving segments + for it. */ + TCP_REG(&tcp_active_pcbs, npcb); + + /* Parse any options in the SYN. */ + tcp_parseopt(npcb); +#if TCP_CALCULATE_EFF_SEND_MSS + npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + snmp_inc_tcppassiveopens(); + + /* Send a SYN|ACK together with the MSS option. */ + rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); + if (rc != ERR_OK) {//��������ͷ��¿��ƿ� + tcp_abandon(npcb, 0); + return rc; + } + return tcp_output(npcb);//���ͱ��� + } + return ERR_OK; +} + +/** + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ + /* +*����TIME_WAIT״̬�Ŀ��ƿ���øú������յ��ı��ĶΣ� +*��״̬�£��ر����ӵ����ֹ���Ѿ��������ڵȴ�2MSL��ʱ�� +*��״̬�µı��Ķ����������еľ���ݣ�ֱ��ɾ��ɡ� +*����Ҫ���ͷ�����ACK���� +*/ +static err_t +tcp_timewait_input(struct tcp_pcb *pcb) +{ + + if (flags & TCP_RST) { //RST��λ��ֱ�ӷ��� + return ERR_OK; + } + + if (flags & TCP_SYN) { //��SYN������Ϣ����������ݱ���ڽ��մ����ڣ����ͷ�����RST���� + + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { + + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + return ERR_OK; + } + } else if (flags & TCP_FIN) { //����FIN������Ϣ + + pcb->tmr = tcp_ticks; //��λ�ȴ�2MSLʱ�䣬���ƿ����µȴ�2MSL + } + + if ((tcplen > 0)) { //��������ݵı��Ļ����ڽ��մ������SYN���� + pcb->flags |= TF_ACK_NOW;//����һ��ACK���� + return tcp_output(pcb); + } + return ERR_OK; +} + +/** + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static err_t +tcp_process(struct tcp_pcb *pcb) +{ + struct tcp_seg *rseg; + u8_t acceptable = 0; + err_t err; + + err = ERR_OK; + + /* Process incoming RST segments. */ + if (flags & TCP_RST) { + /* First, determine if the reset is acceptable. */ + if (pcb->state == SYN_SENT) { + if (ackno == pcb->snd_nxt) { + acceptable = 1; + } + } else { + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt+pcb->rcv_wnd)) { + acceptable = 1; + } + } + + if (acceptable) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); + LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); + recv_flags |= TF_RESET; + pcb->flags &= ~TF_ACK_DELAY; + return ERR_RST; + } else { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + return ERR_OK; + } + } + + if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { + /* Cope with new connection attempt after remote end crashed */ + tcp_ack_now(pcb); + return ERR_OK; + } + + if ((pcb->flags & TF_RXCLOSED) == 0) { + /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ + pcb->tmr = tcp_ticks; + } + pcb->keep_cnt_sent = 0; + + tcp_parseopt(pcb); + + /* Do different things depending on the TCP state. */ + switch (pcb->state) { + case SYN_SENT: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, + pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); + /* received SYN ACK with expected sequence number? */ + if ((flags & TCP_ACK) && (flags & TCP_SYN) + && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { + pcb->snd_buf++; + pcb->rcv_nxt = seqno + 1; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->lastack = ackno; + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ + pcb->state = ESTABLISHED; + +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + /* Set ssthresh again after changing pcb->mss (already set in tcp_connect + * but for the default value of pcb->mss) */ + pcb->ssthresh = pcb->mss * 10; + + pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); + LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); + --pcb->snd_queuelen; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + rseg = pcb->unacked; + pcb->unacked = rseg->next; + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if(pcb->unacked == NULL) + pcb->rtime = -1; + else { + pcb->rtime = 0; +// pcb->nrtx = 0; + } + pcb->nrtx = 0; + + tcp_seg_free(rseg); + + /* Call the user specified function to call when sucessfully + * connected. */ + TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + tcp_ack_now(pcb); + } + /* received ACK? possibly a half-open connection */ + else if (flags & TCP_ACK) { + /* send a RST to bring the other side in a non-synchronized state. */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + break; + case SYN_RCVD: + if (flags & TCP_ACK) { + /* expected ACK number? */ + if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { + u16_t old_cwnd; + pcb->state = ESTABLISHED; + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +#if LWIP_CALLBACK_API + LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); +#endif + /* Call the accept function. */ + TCP_EVENT_ACCEPT(pcb, ERR_OK, err); + if (err != ERR_OK) { + /* If the accept function returns with an error, we abort + * the connection. */ + /* Already aborted? */ + if (err != ERR_ABRT) { + tcp_abort(pcb); + } + return ERR_ABRT; + } + old_cwnd = pcb->cwnd; + /* If there was any data contained within this ACK, + * we'd better pass it on to the application as well. */ + tcp_receive(pcb); + + /* Prevent ACK for SYN to generate a sent event */ + if (pcb->acked != 0) { + pcb->acked--; + } + + pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); + + if (recv_flags & TF_GOT_FIN) { + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + } else { + /* incorrect ACK number, send RST */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { /* passive close */ + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { + LWIP_DEBUGF(TCP_DEBUG, + ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_pcb_purge(pcb); + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if (flags & TCP_ACK && ackno == pcb->snd_nxt) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ + recv_flags |= TF_CLOSED; + } + break; + default: + break; + } + return ERR_OK; +} + +#if TCP_QUEUE_OOSEQ +/** + * Insert segment into the list (segments covered with new one will be deleted) + * + * Called from tcp_receive() + */ +static void ICACHE_FLASH_ATTR +tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) +{ + struct tcp_seg *old_seg; + + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + /* received segment overlaps all following segments */ + tcp_segs_free(next); + next = NULL; + } + else { + /* delete some following segments + oos queue may have segments with FIN flag */ + while (next && + TCP_SEQ_GEQ((seqno + cseg->len), + (next->tcphdr->seqno + next->len))) { + /* cseg with FIN already processed */ + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); + } + old_seg = next; + next = next->next; + tcp_seg_free(old_seg); + } + if (next && + TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + cseg->len = (u16_t)(next->tcphdr->seqno - seqno); + pbuf_realloc(cseg->p, cseg->len); + } + } + cseg->next = next; +} +#endif /* TCP_QUEUE_OOSEQ */ + +/** + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, is places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * i it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + * + * Called from tcp_process(). + */ +static void +tcp_receive(struct tcp_pcb *pcb) +{ + struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ + struct tcp_seg *prev, *cseg; +#endif /* TCP_QUEUE_OOSEQ */ + struct pbuf *p; + s32_t off; + s16_t m; + u32_t right_wnd_edge; + u16_t new_tot_len; + int found_dupack = 0; + + if (flags & TCP_ACK) {//����ACK + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;//���ʹ��� + ����Ӧ����󴰿ڸ��� + + // first /* Update window. */ + /*seqno > snd_wl1���������ֹ�̲��ô��ָ���; + *seqno = snd_wl1����ackno > snd_wl2;��ʱ���Է�û�з�����ݣ�ֻ���յ���ݵ�ȷ��; + *ackno = snd_wl2�ұ����ײ��б�snd_wnd���Ĵ���.����������Ӧֵ + */ + if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wl1 = seqno; + pcb->snd_wl2 = ackno; + if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { + pcb->persist_backoff = 0;//�����ʱ���˳� + } + LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG + } else { + if (pcb->snd_wnd != tcphdr->wnd) { + LWIP_DEBUGF(TCP_WND_DEBUG, + ("tcp_receive: no window update lastack %"U32_F" ackno %" + U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", + pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + } +#endif /* TCP_WND_DEBUG */ + } + + /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a + * duplicate ack if: + * 1) It doesn't ACK new data û��ȷ������� + * 2) length of received packet is zero (i.e. no payload) ���Ķ����κ���� + * 3) the advertised window hasn't changed ���ش���û�и��� + * 4) There is outstanding unacknowledged data (retransmission timer running)������ݵȴ�ȷ�� + * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) ackno = lastack + * + * If it passes all five, should process as a dupack: + * a) dupacks < 3: do nothing + * b) dupacks == 3: fast retransmit + * c) dupacks > 3: increase cwnd + * + * If it only passes 1-3, should reset dupack counter (and add to + * stats, which we don't do in lwIP) + * + * If it only passes 1, should reset dupack counter + * + */ + + /* Clause 1 */ + if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {//���ظ�ACK? + pcb->acked = 0; + /* Clause 2 */ + if (tcplen == 0) { + /* Clause 3 */ + if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ + /* Clause 4 */ + if (pcb->rtime >= 0) { + /* Clause 5 */ + if (pcb->lastack == ackno) { + found_dupack = 1; + if (pcb->dupacks + 1 > pcb->dupacks) + ++pcb->dupacks; + if (pcb->dupacks > 3) { + /* Inflate the congestion window, but not if it means that + the value overflows. */ + if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + } else if (pcb->dupacks == 3) {//���ظ�ACK + /* Do fast retransmit */ + tcp_rexmit_fast(pcb); + } + } + } + } + } + /* If Clause (1) or more is true, but not a duplicate ack, reset + * count of consecutive duplicate acks */ + if (!found_dupack) { + pcb->dupacks = 0; + } + } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){//ackno��lastack+1��snd_nxt֮�䣬�жϷ��ʹ�������� + /* We come here when the ACK acknowledges new data. */ + + if (pcb->flags & TF_INFR) { + pcb->flags &= ~TF_INFR;// Reset the "IN Fast Retransmit" flag,since we are no longer in fast retransmit + pcb->cwnd = pcb->ssthresh;//Reset the congestion window to the "slow start threshold". + } + + /* Reset the number of retransmissions. */ + pcb->nrtx = 0; + + /* Reset the retransmission time-out. */ + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + /* Update the send buffer space. Diff between the two can never exceed 64K? */ + pcb->acked = (u16_t)(ackno - pcb->lastack); + + pcb->snd_buf += pcb->acked; + + /* Reset the fast retransmit variables. */ + pcb->dupacks = 0; + pcb->lastack = ackno; + + /* Update the congestion control variables (cwnd and + ssthresh). */ + if (pcb->state >= ESTABLISHED) {//״̬Ϊ�������ӱ�־ + if (pcb->cwnd < pcb->ssthresh) { + if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); + } else { + u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); + if (new_cwnd > pcb->cwnd) { + pcb->cwnd = new_cwnd; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); + } + } + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", + ackno, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno): 0, + pcb->unacked != NULL? + ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); + + /* Remove segment from the unacknowledged list if the incoming + ACK acknowlegdes them. + *�ͷ�unacked�����ϱ�ȷ�ϵı��ĶΣ� + *ֱ��unacked����Ϊ��ֹͣ*/ + while (pcb->unacked != NULL && + TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked), ackno)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", + ntohl(pcb->unacked->tcphdr->seqno), + ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked))); + + next = pcb->unacked;//pcb unacked��־ + pcb->unacked = pcb->unacked->next;//pcb unacked ��һ����־ + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); + LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); + /* Prevent ACK for FIN to generate a sent event */ + if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { + pcb->acked--; + } + + pcb->snd_queuelen -= pbuf_clen(next->p);//�������������pbufs���� + tcp_seg_free(next);//�ͷ�tcp�� + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + } + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if(pcb->unacked == NULL) //����ݵȴ�ȷ�� + pcb->rtime = -1; //ֹͣ�ش���ʱ�� + else + pcb->rtime = 0; //��λ�ش���ʱ�� + + pcb->polltmr = 0; + } else { + /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ + pcb->acked = 0; + } + + /* We go through the ->unsent list to see if any of the segments + on the list are acknowledged by the ACK. This may seem + strange since an "unsent" segment shouldn't be acked. The + rationale is that lwIP puts all outstanding segments on the + ->unsent list after a retransmission, so these segments may + in fact have been sent once. */ + /** unsent�������Ƿ��ܱ�acknoȷ�ϵı��ĶΣ������ͷ�**/ + while (pcb->unsent != NULL && + TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", + ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent))); + + next = pcb->unsent;//pcbδ���ͱ�־ + pcb->unsent = pcb->unsent->next;//δ���͵���һ�� + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); + LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); + /* Prevent ACK for FIN to generate a sent event */ + if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { + pcb->acked--; + } + pcb->snd_queuelen -= pbuf_clen(next->p);//������pbuf�ĸ��� + tcp_seg_free(next);//�ͷŶ� + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) {//��������� + LWIP_ASSERT("tcp_receive: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + } + /* End of ACK for new data processing. */ + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", + pcb->rttest, pcb->rtseq, ackno)); + + /* RTT estimation calculations. This is done by checking if the + incoming segment acknowledges the segment we use to take a + round-trip time measurement. */ + if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {//RTT���ڽ����Ҹñ��Ķα�ȷ�� + /* diff between this shouldn't exceed 32K since this are tcp timer ticks + and a round-trip shouldn't be that long... */ + m = (s16_t)(tcp_ticks - pcb->rttest);//����MÖµ + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", + m, m * TCP_SLOW_INTERVAL)); + + /* This is taken directly from VJs original code in his paper �����RTT���㹫ʽ*/ + m = m - (pcb->sa >> 3); + pcb->sa += m; + if (m < 0) { + m = -m; + } + m = m - (pcb->sv >> 2); + pcb->sv += m; + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", + pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); + + pcb->rttest = 0; + } + } + + /* If the incoming segment contains data, we must process it + further. */ + if (tcplen > 0) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ + if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ + if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){// seqno < rcv_nxt < seqno + tcplen + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + //ȥ�����Ķ�����ݱ�ŵ���rcv_nxt����� + off = pcb->rcv_nxt - seqno; + p = inseg.p; + LWIP_ASSERT("inseg.p != NULL", inseg.p); + LWIP_ASSERT("insane offset!", (off < 0x7fff)); + if (inseg.p->len < off) { + LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); + new_tot_len = (u16_t)(inseg.p->tot_len - off); + while (p->len < off) { + off -= p->len; + /* KJM following line changed (with addition of new_tot_len var) + to fix bug #9076 + inseg.p->tot_len -= p->len; */ + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + if(pbuf_header(p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } else { + if(pbuf_header(inseg.p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } + inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } + else { + if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){//seqno < rcv_nxt + /* the whole segment is < rcv_nxt */ + /* must be a duplicate of a packet that has already been correctly handled */ + //���Ķ���������ݱ�ž�С��rcv_nxt����˱������ظ����ģ� + //ֱ����Դ����ӦACK���Ĵ��� + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); + tcp_ack_now(pcb); + } + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd - 1)){//rcv_nxt < seqno < rcv_nxt + rcv_wnd - 1,������ڽ��շ�Χ�� + if (pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ + tcplen = TCP_TCPLEN(&inseg);//���㱨�Ķγ��� + + if (tcplen > pcb->rcv_wnd) {//������մ��ڴ�С��������β���ض� + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + inseg.len = pcb->rcv_wnd; + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } +#if TCP_QUEUE_OOSEQ + /* Received in-sequence data, adjust ooseq data if: + - FIN has been received or + - inseq overlaps with ooseq */ + if (pcb->ooseq != NULL) { + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: received in-order FIN, binning ooseq queue\n")); + /* Received in-order FIN means anything that was received + * out of order must now have been received in-order, so + * bin the ooseq queue */ + while (pcb->ooseq != NULL) { + struct tcp_seg *old_ooseq = pcb->ooseq; + pcb->ooseq = pcb->ooseq->next; + tcp_seg_free(old_ooseq); + } + } + else { + next = pcb->ooseq; + /* Remove all segments on ooseq that are covered by inseg already. + * FIN is copied from ooseq to inseg if present. */ + while (next && + TCP_SEQ_GEQ(seqno + tcplen, + next->tcphdr->seqno + next->len)) { + /* inseg cannot have FIN here (already processed above) */ + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && + (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { + TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); + tcplen = TCP_TCPLEN(&inseg); + } + prev = next; + next = next->next; + tcp_seg_free(prev); + } + /* Now trim right side of inseg if it overlaps with the first + * segment on ooseq */ + if (next && + TCP_SEQ_GT(seqno + tcplen, + next->tcphdr->seqno)) { + /* inseg cannot have FIN here (already processed above) */ + inseg.len = (u16_t)(next->tcphdr->seqno - seqno); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", + (seqno + tcplen) == next->tcphdr->seqno); + } + pcb->ooseq = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + pcb->rcv_nxt = seqno + tcplen; + + /* Update the receiver's (our) window. */ + LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); + pcb->rcv_wnd -= tcplen; + + tcp_update_rcv_ann_wnd(pcb); + + /* If there is data in the segment, we make preparations to + pass this up to the application. The ->recv_data variable + is used for holding the pbuf that goes to the + application. The code for reassembling out-of-sequence data + chains its data on this pbuf as well. + + If the segment was a FIN, we set the TF_GOT_FIN flag that will + be used to indicate to the application that the remote side has + closed its end of the connection. */ + if (inseg.p->tot_len > 0) { + recv_data = inseg.p; + /* Since this pbuf now is the responsibility of the + application, we delete our reference to it so that we won't + (mistakingly) deallocate it. */ + inseg.p = NULL; + } + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); + recv_flags |= TF_GOT_FIN; + } + +#if TCP_QUEUE_OOSEQ + /* We now check if we have segments on the ->ooseq queue that + are now in sequence. */ + while (pcb->ooseq != NULL && + pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + + cseg = pcb->ooseq; + seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += TCP_TCPLEN(cseg); + LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", + pcb->rcv_wnd >= TCP_TCPLEN(cseg)); + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + + tcp_update_rcv_ann_wnd(pcb); + + if (cseg->p->tot_len > 0) { + /* Chain this pbuf onto the pbuf that we will pass to + the application. */ + if (recv_data) { + pbuf_cat(recv_data, cseg->p); + } else { + recv_data = cseg->p; + } + cseg->p = NULL; + } + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); + recv_flags |= TF_GOT_FIN; + if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ + pcb->state = CLOSE_WAIT; + } + } + + pcb->ooseq = cseg->next; + tcp_seg_free(cseg); + } +#endif /* TCP_QUEUE_OOSEQ */ + + + /* Acknowledge the segment(s). */ + tcp_ack(pcb); + + } else { + /* We get here if the incoming segment is out-of-sequence. */ + tcp_send_empty_ack(pcb); +#if TCP_QUEUE_OOSEQ + /* We queue the segment on the ->ooseq queue. */ + if (pcb->ooseq == NULL) { + pcb->ooseq = tcp_seg_copy(&inseg); + } else { + /* If the queue is not empty, we walk through the queue and + try to find a place where the sequence number of the + incoming segment is between the sequence numbers of the + previous and the next segment on the ->ooseq queue. That is + the place where we put the incoming segment. If needed, we + trim the second edges of the previous and the incoming + segment so that it will fit into the sequence. + + If the incoming segment has the same sequence number as a + segment on the ->ooseq queue, we discard the segment that + contains less data. */ + + prev = NULL; + for(next = pcb->ooseq; next != NULL; next = next->next) {//��ooseqȡ�µ�M�����ĶΣ��ñ��Ķηǿգ�M++ + if (seqno == next->tcphdr->seqno) {//�ñ��Ķ���ʼ���== Ҫ����ı��Ķα�� + /* The sequence number of the incoming segment is the + same as the sequence number of the segment on + ->ooseq. We check the lengths to see which one to + discard. */ + if (inseg.len > next->len) {//Ҫ����ı��Ķα�Ÿ� + /* The incoming segment is larger than the old + segment. We replace some segments with the new + one. */ + cseg = tcp_seg_copy(&inseg);//Ҫ����ı��Ķδ����M�����Ķ� + if (cseg != NULL) { + if (prev != NULL) { + prev->next = cseg; + } else { + pcb->ooseq = cseg; + } + tcp_oos_insert_segment(cseg, next); + } + break; + } else { + /* Either the lenghts are the same or the incoming + segment was smaller than the old one; in either + case, we ditch the incoming segment. */ + break; + } + } else { + if (prev == NULL) { + if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is lower + than the sequence number of the first segment on the + queue. We put the incoming segment first on the + queue. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + pcb->ooseq = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } else { + /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && + TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ + if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { + /* The sequence number of the incoming segment is in + between the sequence numbers of the previous and + the next segment on ->ooseq. We trim trim the previous + segment, delete next segments that included in received segment + and trim received, if needed. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { + /* We need to trim the prev segment. */ + prev->len = (u16_t)(seqno - prev->tcphdr->seqno); + pbuf_realloc(prev->p, prev->len); + } + prev->next = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } + /* If the "next" segment is the last segment on the + ooseq queue, we add the incoming segment to the end + of the list. */ + if (next->next == NULL && + TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + /* segment "next" already contains all data */ + break; + } + next->next = tcp_seg_copy(&inseg); + if (next->next != NULL) { + if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { + /* We need to trim the last segment. */ + next->len = (u16_t)(seqno - next->tcphdr->seqno); + pbuf_realloc(next->p, next->len); + } + /* check if the remote side overruns our receive window */ + if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; + pbuf_realloc(next->next->p, next->next->len); + tcplen = TCP_TCPLEN(next->next); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } + } + break; + } + } + prev = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + } + } else { + /* The incoming segment is not withing the window. */ + tcp_send_empty_ack(pcb); + } + } else { + /* Segments with length 0 is taken care of here. Segments that + fall out of the window are ACKed. */ + /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || + TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ + if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ + tcp_ack_now(pcb);//��Դ�˷���һ������ȷ�ϱ��� + } + } +} + +/** + * Parses the options contained in the incoming segment. + * + * Called from tcp_listen_input() and tcp_process(). + * Currently, only the MSS option is supported! + * + * @param pcb the tcp_pcb for which a segment arrived + */ +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ + u16_t c, max_c; + u16_t mss; + u8_t *opts, opt; +#if LWIP_TCP_TIMESTAMPS + u32_t tsval; +#endif + + opts = (u8_t *)tcphdr + TCP_HLEN; + + /* Parse the TCP MSS option, if present. */ + if(TCPH_HDRLEN(tcphdr) > 0x5) { + max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; + for (c = 0; c < max_c; ) { + opt = opts[c]; + switch (opt) { + case 0x00: + /* End of options. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); + return; + case 0x01: + /* NOP option. */ + ++c; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); + break; + case 0x02: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); + if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* An MSS option with the right option length. */ + mss = (opts[c + 2] << 8) | opts[c + 3]; + /* Limit the mss to the configured TCP_MSS and prevent division by zero */ + pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; + /* Advance to next option */ + c += 0x04; + break; +#if LWIP_TCP_TIMESTAMPS + case 0x08: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); + if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* TCP timestamp option with valid length */ + tsval = (opts[c+2]) | (opts[c+3] << 8) | + (opts[c+4] << 16) | (opts[c+5] << 24); + if (flags & TCP_SYN) { + pcb->ts_recent = ntohl(tsval); + pcb->flags |= TF_TIMESTAMP; + } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { + pcb->ts_recent = ntohl(tsval); + } + /* Advance to next option */ + c += 0x0A; + break; +#endif + default: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); + if (opts[c + 1] == 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + /* If the length field is zero, the options are malformed + and we don't process them further. */ + return; + } + /* All other options have a length field, so that we easily + can skip past them. */ + c += opts[c + 1]; + } + } + } +} + +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_out.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_out.c new file mode 100755 index 0000000000..b9d69e4677 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/tcp_out.c @@ -0,0 +1,1531 @@ +/** + * @file + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp_impl.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "netif/etharp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/* Define some copy-macros for checksum-on-copy so that the code looks + nicer by preventing too many ifdef's. */ +#if TCP_CHECKSUM_ON_COPY +#define TCP_DATA_COPY(dst, src, len, seg) do { \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ + len, &seg->chksum, &seg->chksum_swapped); \ + seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); +#else /* TCP_CHECKSUM_ON_COPY*/ +#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) +#endif /* TCP_CHECKSUM_ON_COPY*/ + +/** Define this to 1 for an extra check that the output checksum is valid + * (usefule when the checksum is generated by the application, not the stack) */ +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 +#endif + +/* Forward declarations.*/ +static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); + +/** Allocate a pbuf and create a tcphdr at p->payload, used for output + * functions other than the default tcp_output -> tcp_output_segment + * (e.g. tcp_send_empty_ack, etc.) + * + * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) + * @param optlen length of header-options + * @param datalen length of tcp data to reserve in pbuf + * @param seqno_be seqno in network byte order (big-endian) + * @return pbuf with p->payload being the tcp_hdr + */ +static struct pbuf *ICACHE_FLASH_ATTR +tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, + u32_t seqno_be /* already in network byte order */) +{ + struct tcp_hdr *tcphdr; + struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= TCP_HLEN + optlen)); + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = seqno_be; + tcphdr->ackno = htonl(pcb->rcv_nxt); + TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); + tcphdr->wnd = htons(pcb->rcv_ann_wnd); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + + /* If we're sending a packet, update the announced right window edge */ + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + } + return p; +} + +/** + * Called by tcp_close() to send a segment including FIN flag but not data. + * + * @param pcb the tcp_pcb over which to send a segment + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_fin(struct tcp_pcb *pcb) +{ + /* first, try to add the fin to the last unsent segment */ + if (pcb->unsent != NULL) { + struct tcp_seg *last_unsent; + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { + /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ + TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); + return ERR_OK; + } + } + /* no data, no length, flags, copy=1, no optdata */ + return tcp_enqueue_flags(pcb, TCP_FIN); +} + +/** + * Create a TCP segment with prefilled header. + * + * Called by tcp_write and tcp_enqueue_flags. + * + * @param pcb Protocol control block for the TCP connection. + * @param p pbuf that is used to hold the TCP header. + * @param flags TCP flags for header. + * @param seqno TCP sequence number of this packet + * @param optflags options to include in TCP header + * @return a new tcp_seg pointing to p, or NULL. + * The TCP header is filled in except ackno and wnd. + * p is freed on failure. + */ +static struct tcp_seg *ICACHE_FLASH_ATTR +tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) +{ + struct tcp_seg *seg; + u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); + + if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); + pbuf_free(p); + return NULL; + } + seg->flags = optflags; + seg->next = NULL; + seg->p = p; + seg->len = p->tot_len - optlen; +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = 0; + seg->chksum_swapped = 0; + /* check optflags */ + LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", + (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* build TCP header */ + if (pbuf_header(p, TCP_HLEN)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); + TCP_STATS_INC(tcp.err); + tcp_seg_free(seg); + return NULL; + } + seg->tcphdr = (struct tcp_hdr *)seg->p->payload; + seg->tcphdr->src = htons(pcb->local_port); + seg->tcphdr->dest = htons(pcb->remote_port); + seg->tcphdr->seqno = htonl(seqno); + /* ackno is set in tcp_output */ + TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); + /* wnd and chksum are set in tcp_output */ + seg->tcphdr->urgp = 0; + return seg; +} + +/** + * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. + * + * This function is like pbuf_alloc(layer, length, PBUF_RAM) except + * there may be extra bytes available at the end. + * + * @param layer flag to define header size. + * @param length size of the pbuf's payload. + * @param max_length maximum usable size of payload+oversize. + * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. + * @param pcb The TCP connection that willo enqueue the pbuf. + * @param apiflags API flags given to tcp_write. + * @param first_seg true when this pbuf will be used in the first enqueued segment. + * @param + */ +#if TCP_OVERSIZE +static struct pbuf *ICACHE_FLASH_ATTR +tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, + u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, + u8_t first_seg) +{ + struct pbuf *p; + u16_t alloc = length; + +#if LWIP_NETIF_TX_SINGLE_PBUF + LWIP_UNUSED_ARG(max_length); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(apiflags); + LWIP_UNUSED_ARG(first_seg); + /* always create MSS-sized pbufs */ + alloc = pcb->mss; //TCP_MSS; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (length < max_length) { + /* Should we allocate an oversized pbuf, or just the minimum + * length required? If tcp_write is going to be called again + * before this segment is transmitted, we want the oversized + * buffer. If the segment will be transmitted immediately, we can + * save memory by allocating only length. We use a simple + * heuristic based on the following information: + * + * Did the user set TCP_WRITE_FLAG_MORE? + * + * Will the Nagle algorithm defer transmission of this segment? + */ + if ((apiflags & TCP_WRITE_FLAG_MORE) || + (!(pcb->flags & TF_NODELAY) && + (!first_seg || + pcb->unsent != NULL || + pcb->unacked != NULL))) { + alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE)); + } + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(layer, alloc, PBUF_RAM); + if (p == NULL) { + return NULL; + } + LWIP_ASSERT("need unchained pbuf", p->next == NULL); + *oversize = p->len - length; + /* trim p->len to the currently used size */ + p->len = p->tot_len = length; + return p; +} +#else /* TCP_OVERSIZE */ +#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) +#endif /* TCP_OVERSIZE */ + +#if TCP_CHECKSUM_ON_COPY +/** Add a checksum of newly added data to the segment */ +static void ICACHE_FLASH_ATTR +tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, + u8_t *seg_chksum_swapped) +{ + u32_t helper; + /* add chksum to old chksum and fold to u16_t */ + helper = chksum + *seg_chksum; + chksum = FOLD_U32T(helper); + if ((len & 1) != 0) { + *seg_chksum_swapped = 1 - *seg_chksum_swapped; + chksum = SWAP_BYTES_IN_WORD(chksum); + } + *seg_chksum = chksum; +} +#endif /* TCP_CHECKSUM_ON_COPY */ + +/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). + * + * @param pcb the tcp pcb to check for + * @param len length of data to send (checked agains snd_buf) + * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise + */ +static err_t ICACHE_FLASH_ATTR +tcp_write_checks(struct tcp_pcb *pcb, u16_t len) +{ + /* connection is in invalid state for data transmission? */ + if ((pcb->state != ESTABLISHED) && + (pcb->state != CLOSE_WAIT) && + (pcb->state != SYN_SENT) && + (pcb->state != SYN_RCVD)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); + return ERR_CONN; + } else if (len == 0) { + return ERR_OK; + } + + /* fail on too much data */ + if (len > pcb->snd_buf) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", + len, pcb->snd_buf)); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + /* If total number of pbufs on the unsent/unacked queues exceeds the + * configured maximum, return an error */ + /* check for configured max queuelen and possible overflow */ + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", + pcb->unacked != NULL || pcb->unsent != NULL); + } else { + LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", + pcb->unacked == NULL && pcb->unsent == NULL); + } + return ERR_OK; +} + +/** + * Write data for sending (but does not send it immediately). + *��������һ��������ݣ��ú�����һ�����Ķβ����ڿ��ƿ黺������� + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + * + * @param pcb Protocol control block for the TCP connection to enqueue data for.��Ӧ���ӿ��ƿ� + * @param arg Pointer to the data to be enqueued for sending.���������ʼ��ַ + * @param len Data length in bytes������ݳ��� + * @param apiflags combination of following flags :����Ƿ���п������Լ����Ķ��ײ��Ƿ������PSH��־ + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) +{ + struct pbuf *concat_p = NULL; + struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; + u16_t pos = 0; /* position in 'arg' data */ + u16_t queuelen; + u8_t optlen = 0; + u8_t optflags = 0; +#if TCP_OVERSIZE + u16_t oversize = 0; + u16_t oversize_used = 0; +#endif /* TCP_OVERSIZE */ +#if TCP_CHECKSUM_ON_COPY + u16_t concat_chksum = 0; + u8_t concat_chksum_swapped = 0; + u16_t concat_chksummed = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + err_t err; + +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Always copy to try to create single pbufs for TX */ + apiflags |= TCP_WRITE_FLAG_COPY; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)apiflags)); + LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", + arg != NULL, return ERR_ARG;); + + err = tcp_write_checks(pcb, len); + if (err != ERR_OK) { + return err; + } + queuelen = pcb->snd_queuelen; + +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + optflags = TF_SEG_OPTS_TS; + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif /* LWIP_TCP_TIMESTAMPS */ + + + /* + * TCP segmentation is done in three phases with increasing complexity: + * + * 1. Copy data directly into an oversized pbuf. + * 2. Chain a new pbuf to the end of pcb->unsent. + * 3. Create new segments. + * + * We may run out of memory at any point. In that case we must + * return ERR_MEM and not change anything in pcb. Therefore, all + * changes are recorded in local variables and committed at the end + * of the function. Some pcb fields are maintained in local copies: + * + * queuelen = pcb->snd_queuelen + * oversize = pcb->unsent_oversize + * + * These variables are set consistently by the phases: + * + * seg points to the last segment tampered with. + * + * pos records progress as data is segmented. + */ + + /* Find the tail of the unsent queue. */ + if (pcb->unsent != NULL) { + u16_t space = 0; + u16_t unsent_optlen = 0; + + /* @todo: this could be sped up by keeping last_unsent in the pcb */ + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + /* Usable space at the end of the last unsent segment */ + unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); + space = pcb->mss - (last_unsent->len + unsent_optlen); + + /* + * Phase 1: Copy data directly into an oversized pbuf. + * + * The number of bytes copied is recorded in the oversize_used + * variable. The actual copying is done at the bottom of the + * function. + */ +#if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ + oversize = pcb->unsent_oversize; + if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); + seg = last_unsent; + oversize_used = oversize < len ? oversize : len; + pos += oversize_used; + oversize -= oversize_used; + space -= oversize_used; + } + /* now we are either finished or oversize is zero */ + LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); +#endif /* TCP_OVERSIZE */ + + if (pos > len) { + return ERR_MEM; + } + + /* + * Phase 2: Chain a new pbuf to the end of pcb->unsent. + * + * We don't extend segments containing SYN/FIN flags or options + * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at + * the end. + */ + if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { + u16_t seglen = space < len - pos ? space : len - pos; + seg = last_unsent; + + /* Create a pbuf with a copy or reference to seglen bytes. We + * can use PBUF_RAW here since the data appears in the middle of + * a segment. A header will never be prepended. */ + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* Data is copied */ + if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", + seglen)); + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ + TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); +#if TCP_CHECKSUM_ON_COPY + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + } else { + /* Data is not copied */ + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, + &concat_chksum, &concat_chksum_swapped); + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + concat_p->payload = (u8_t*)arg + pos; + } + + pos += seglen; + queuelen += pbuf_clen(concat_p); + } + } else { +#if TCP_OVERSIZE + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); +#endif /* TCP_OVERSIZE */ + } + + /* + * Phase 3: Create new segments. + * + * The new segments are chained together in the local 'queue' + * variable, ready to be appended to pcb->unsent. + */ + while (pos < len) { + struct pbuf *p; + u16_t left = len - pos; + u16_t max_len = pcb->mss - optlen; + u16_t seglen = left > max_len ? max_len : left; +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* If copy is set, memory should be allocated and data copied + * into pbuf */ + if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + goto memerr; + } + LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", + (p->len >= seglen)); + TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); + } else { + /* Copy is not set: First allocate a pbuf for holding the data. + * Since the referenced data is available at least until it is + * sent out on the link (as it has to be ACKed by the remote + * party) we can safely use PBUF_ROM instead of PBUF_REF here. + */ + struct pbuf *p2; +#if TCP_OVERSIZE + LWIP_ASSERT("oversize == 0", oversize == 0); +#endif /* TCP_OVERSIZE */ + if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + chksum = ~inet_chksum((u8_t*)arg + pos, seglen); +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + p2->payload = (u8_t*)arg + pos; + + /* Second, allocate a pbuf for the headers. */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + /* If allocation fails, we have to deallocate the data pbuf as + * well. */ + pbuf_free(p2); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n")); + goto memerr; + } + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(p/*header*/, p2/*data*/); + } + + queuelen += pbuf_clen(p); + + /* Now that there are more segments queued, we check again if the + * length of the queue exceeds the configured maximum or + * overflows. */ + if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + pbuf_free(p); + goto memerr; + } + + if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = chksum; + seg->chksum_swapped = chksum_swapped; + seg->flags |= TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* first segment of to-be-queued data? */ + if (queue == NULL) { + queue = seg; + } else { + /* Attach the segment to the end of the queued segments */ + LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); + prev_seg->next = seg; + } + /* remember last segment of to-be-queued data for next iteration */ + prev_seg = seg; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", + ntohl(seg->tcphdr->seqno), + ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); + + pos += seglen; + } + + /* + * All three segmentation phases were successful. We can commit the + * transaction. + */ + + /* + * Phase 1: If data has been added to the preallocated tail of + * last_unsent, we update the length fields of the pbuf chain. + */ +#if TCP_OVERSIZE + if (oversize_used > 0) { + struct pbuf *p; + /* Bump tot_len of whole chain, len of tail */ + for (p = last_unsent->p; p; p = p->next) { + p->tot_len += oversize_used; + if (p->next == NULL) { + TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); + p->len += oversize_used; + } + } + last_unsent->len += oversize_used; +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ + } + pcb->unsent_oversize = oversize; +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: concat_p can be concatenated onto last_unsent->p + */ + if (concat_p != NULL) { + LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", + (last_unsent != NULL)); + pbuf_cat(last_unsent->p, concat_p); + last_unsent->len += concat_p->tot_len; +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, + &last_unsent->chksum_swapped); + last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; + } +#endif /* TCP_CHECKSUM_ON_COPY */ + } + + /* + * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that + * is harmless + */ + if (last_unsent == NULL) { + pcb->unsent = queue; + } else { + last_unsent->next = queue; + } + + /* + * Finally update the pcb state. + */ + pcb->snd_lbb += len; + pcb->snd_buf -= len; + pcb->snd_queuelen = queuelen; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", + pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + /* Set the PSH flag in the last segment that we enqueued. */ + if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { + TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); + } + + return ERR_OK; +memerr: + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + + if (concat_p != NULL) { + pbuf_free(concat_p); + } + if (queue != NULL) { + tcp_segs_free(queue); + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); + return ERR_MEM; +} + +/** + * Enqueue TCP options for transmission. + * + * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). + * + * @param pcb Protocol control block for the TCP connection. + * @param flags TCP header flags to set in the outgoing segment. + * @param optdata pointer to TCP options, or NULL. + * @param optlen length of TCP options in bytes. + */ +err_t +tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) +{ + struct pbuf *p; + struct tcp_seg *seg; + u8_t optflags = 0; + u8_t optlen = 0; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", + (flags & (TCP_SYN | TCP_FIN)) != 0); + + /* check for configured max queuelen and possible overflow */ + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + + if (flags & TCP_SYN) { + optflags = TF_SEG_OPTS_MSS; + } +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + optflags |= TF_SEG_OPTS_TS; + } +#endif /* LWIP_TCP_TIMESTAMPS */ + optlen = LWIP_TCP_OPT_LENGTH(optflags); + + /* tcp_enqueue_flags is always called with either SYN or FIN in flags. + * We need one available snd_buf byte to do that. + * This means we can't send FIN while snd_buf==0. A better fix would be to + * not include SYN and FIN sequence numbers in the snd_buf count. */ + if (pcb->snd_buf == 0) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n")); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + + /* Allocate pbuf with room for TCP header + options */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", + (p->len >= optlen)); + + /* Allocate memory for tcp_seg, and fill in fields. */ + if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, + ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", + ntohl(seg->tcphdr->seqno), + ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), + (u16_t)flags)); + + /* Now append seg to pcb->unsent queue */ + if (pcb->unsent == NULL) { + pcb->unsent = seg; + } else { + struct tcp_seg *useg; + for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); + useg->next = seg; + } +#if TCP_OVERSIZE + /* The new unsent tail has no space */ + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + + /* SYN and FIN bump the sequence number */ + if ((flags & TCP_SYN) || (flags & TCP_FIN)) { + pcb->snd_lbb++; + /* optlen does not influence snd_buf */ + pcb->snd_buf--; + } + if (flags & TCP_FIN) { + pcb->flags |= TF_FIN; + } + + /* update number of segments on the queues */ + pcb->snd_queuelen += pbuf_clen(seg->p); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + return ERR_OK; +} + + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void ICACHE_FLASH_ATTR +tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) +{ + /* Pad with two NOP options to make everything nicely aligned */ + opts[0] = PP_HTONL(0x0101080A); + opts[1] = htonl(sys_now()); + opts[2] = htonl(pcb->ts_recent); +} +#endif + +/** Send an ACK without data. + * + * @param pcb Protocol control block for the TCP connection to send the ACK + */ +err_t +tcp_send_empty_ack(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + u8_t optlen = 0; + +#if LWIP_TCP_TIMESTAMPS + if (pcb->flags & TF_TIMESTAMP) { + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif + + p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); + if (p == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); + return ERR_BUF; + } + tcphdr = (struct tcp_hdr *)p->payload; + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, + ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); + /* remove ACK flags from the PCB, as we send an empty ACK now */ + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + + /* NB. MSS option is only sent on SYNs, so ignore it here */ +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (pcb->flags & TF_TIMESTAMP) { + tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); + } +#endif + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), + IP_PROTO_TCP, p->tot_len); +#endif +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + pbuf_free(p); + + return ERR_OK; +} + +/** + * Find out what we can send and send it + *���Ϳ��ƿ黺����еı��Ķ� + * @param pcb Protocol control block for the TCP connection to send data + * @return ERR_OK if data has been sent or nothing to send + * another err_t on error + */ +err_t ICACHE_FLASH_ATTR +tcp_output(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg, *useg; + u32_t wnd, snd_nxt; +#if TCP_CWND_DEBUG + s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ + /* First, check if we are invoked by the TCP input processing + code. If so, we do not output anything. Instead, we rely on the + input processing code to call us when input processing is done + with. �����ƿ鵱ǰ������ݱ����?ֱ�ӷ���*/ + if (tcp_input_pcb == pcb) { + return ERR_OK; + } + + wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);//�ӷ��ʹ��ں������ȡС�ߵõ���Ч���ʹ��� + + seg = pcb->unsent; + + /* If the TF_ACK_NOW flag is set and no data will be sent (either + * because the ->unsent queue is empty or because the window does + * not allow it), construct an empty ACK segment and send it. + * + * If data is to be sent, we will just piggyback the ACK (see below). + */ + if (pcb->flags & TF_ACK_NOW && + (seg == NULL || + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { + return tcp_send_empty_ack(pcb);//����ֻ��ACK�ı��Ķ� + } + + /* useg should point to last segment on unacked queue */ + useg = pcb->unacked; + if (useg != NULL) { + for (; useg->next != NULL; useg = useg->next);//�õ�β�� + } + +#if TCP_OUTPUT_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", + (void*)pcb->unsent)); + } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F + ", cwnd %"U16_F", wnd %"U32_F + ", seg == NULL, ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); + } else { + LWIP_DEBUGF(TCP_CWND_DEBUG, + ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F + ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, + ntohl(seg->tcphdr->seqno), pcb->lastack)); + } +#endif /* TCP_CWND_DEBUG */ + /* data available and window allows it to be sent? + *��ǰ��Ч�������?�ķ��ͣ�ѭ�����ͱ��ģ�ֱ�������*/ + while (seg != NULL && + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd + && (seg->p->ref<2) ) { + LWIP_ASSERT("RST not expected here!", + (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); + /* Stop sending if the nagle algorithm would prevent it + * Don't stop: + * - if tcp_write had a memory error before (prevent delayed ACK timeout) or + * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - + * either seg->next != NULL or pcb->unacked == NULL; + * RST is no sent using tcp_write/tcp_output. + */ + if((tcp_do_output_nagle(pcb) == 0) && + ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ + break; + } +#if TCP_CWND_DEBUG + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + ntohl(seg->tcphdr->seqno) + seg->len - + pcb->lastack, + ntohl(seg->tcphdr->seqno), pcb->lastack, i)); + ++i; +#endif /* TCP_CWND_DEBUG */ + + pcb->unsent = seg->next; + + if (pcb->state != SYN_SENT) { + TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);//��д�ײ�ACK��־ + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//����־λ + } + + tcp_output_segment(seg, pcb);//���ú����ͱ��Ķ� + + snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);//����snd_nxt + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt;//����Ҫ���͵���ݱ�� + } + /* put segment on unacknowledged list if length > 0 + */ + if (TCP_TCPLEN(seg) > 0) { + seg->next = NULL; + /* unacked list is empty? ֱ�ӹҽ�*/ + if (pcb->unacked == NULL) { + pcb->unacked = seg; + useg = seg; + /* unacked list is not empty?����ǰ���İ�˳����֯�ڶ����� */ + } else { + /* In the case of fast retransmit, the packet should not go to the tail + * of the unacked queue, but rather somewhere before it. We need to check for + * this case. -STJ Jul 27, 2004 */ //���ǰ���ĵ����кŵ��ڶ���β���������кţ� + //�Ӷ����ײ���ʼ + if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; + } else {//���������ߣ������δȷ�϶���ĩβ + /* add segment to tail of unacked list */ + useg->next = seg; + useg = useg->next; + } + } + /* do not queue empty segments on the unacked list */ + } else {//���Ķγ���Ϊ0��ֱ��ɾ�������ش� + tcp_seg_free(seg); + } + seg = pcb->unsent;//������һ�����Ķ� + } +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + +//���ʹ��������±��IJ��ܷ��ͣ��������㴰��̽�⡣ + if (seg != NULL && pcb->persist_backoff == 0 && + ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { + /* prepare for persist timer */ + pcb->persist_cnt = 0; + pcb->persist_backoff = 1; + } + + pcb->flags &= ~TF_NAGLEMEMERR;//���ڴ�����־ + return ERR_OK; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + */ + +static void +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) +{ + u16_t len; + struct netif *netif; + u32_t *opts; + /** @bug Exclude retransmitted segments from this count. */ + snmp_inc_tcpoutsegs(); + + /* The TCP header has already been constructed, but the ackno and + wnd fields remain. */ + seg->tcphdr->ackno = htonl(pcb->rcv_nxt); + + /* advertise our receive window size in this TCP segment */ + seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); + + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + + /* Add any requested options. NB MSS option is only set on SYN + packets, so ignore it here */ + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); + opts = (u32_t *)(void *)(seg->tcphdr + 1); + if (seg->flags & TF_SEG_OPTS_MSS) { + TCP_BUILD_MSS_OPTION(*opts); + opts += 1; + } +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (seg->flags & TF_SEG_OPTS_TS) { + tcp_build_timestamp_option(pcb, opts); + opts += 3; + } +#endif + + /* Set retransmission timer running if it is not currently enabled + This must be set before checking the route. modify by ives at 2014.4.24*/ + if (pcb->rtime == -1) { + pcb->rtime = 0; + } + + /* If we don't have a local IP address, we get one by + calling ip_route(). */ + if (ip_addr_isany(&(pcb->local_ip))) { + netif = ip_route(&(pcb->remote_ip)); + if (netif == NULL) { + return; + } + ip_addr_copy(pcb->local_ip, netif->ip_addr); + } + + if (pcb->rttest == 0) { + pcb->rttest = tcp_ticks; + pcb->rtseq = ntohl(seg->tcphdr->seqno); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", + htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + + seg->len)); + + len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + + seg->p->len -= len; + seg->p->tot_len -= len; + + seg->p->payload = seg->tcphdr; + + seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP +#if TCP_CHECKSUM_ON_COPY + { + u32_t acc; +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { + LWIP_ASSERT("data included but not checksummed", + seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); + } + + /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ + acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); + /* add payload checksum */ + if (seg->chksum_swapped) { + seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); + seg->chksum_swapped = 0; + } + acc += (u16_t)~(seg->chksum); + seg->tcphdr->chksum = FOLD_U32T(acc); +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + if (chksum_slow != seg->tcphdr->chksum) { + LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", + seg->tcphdr->chksum, chksum_slow)); + seg->tcphdr->chksum = chksum_slow; + } +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + } +#else /* TCP_CHECKSUM_ON_COPY */ + seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#endif /* TCP_CHECKSUM_ON_COPY */ +#endif /* CHECKSUM_GEN_TCP */ + TCP_STATS_INC(tcp.xmit); + +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, + IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) either to + * abort a connection or to show that there is no matching local connection + * for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(u32_t seqno, u32_t ackno, + ip_addr_t *local_ip, ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= sizeof(struct tcp_hdr))); + + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = htons(local_port); + tcphdr->dest = htons(remote_port); + tcphdr->seqno = htonl(seqno); + tcphdr->ackno = htonl(ackno); + TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); + tcphdr->wnd = PP_HTONS(TCP_WND); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, + IP_PROTO_TCP, p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + snmp_inc_tcpoutrsts(); + /* Send output with hardcoded TTL since we have no access to the pcb */ + ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); + pbuf_free(p); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + struct tcp_seg *t0_head = NULL, *t0_tail = NULL; /* keep in unacked */ + struct tcp_seg *t1_head = NULL, *t1_tail = NULL; /* link to unsent */ + bool t0_1st = true, t1_1st = true; + + if (pcb->unacked == NULL) { + return; + } + +#if 1 /* by Snake: resolve the bug of pbuf reuse */ + seg = pcb->unacked; + while (seg != NULL) { + if (seg->p->eb) { + if (t0_1st) { + t0_head = t0_tail = seg; + t0_1st = false; + } else { + t0_tail->next = seg; + t0_tail = seg; + } + seg = seg->next; + t0_tail->next = NULL; + } else { + if (t1_1st) { + t1_head = t1_tail = seg; + t1_1st = false; + } else { + t1_tail->next = seg; + t1_tail = seg; + } + seg = seg->next; + t1_tail->next = NULL; + } + } + if (t1_head && t1_tail) { + t1_tail->next = pcb->unsent; + pcb->unsent = t1_head; + } + pcb->unacked = t0_head; + +#else + + /* Move all unacked segments to the head of the unsent queue */ + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); + /* concatenate unsent queue after unacked queue */ + seg->next = pcb->unsent; + /* unsent queue is the concatenated queue (of unacked, unsent) */ + pcb->unsent = pcb->unacked; + /* unacked queue is now empty */ + pcb->unacked = NULL; +#endif + /* last unsent hasn't changed, no need to reset unsent_oversize */ + + /* increment number of retransmissions */ + ++pcb->nrtx; + + /* Don't take any RTT measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission */ + tcp_output(pcb); +} + +/** + * Requeue the first unacked segment for retransmission + * + * Called by tcp_receive() for fast retramsmit. + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + struct tcp_seg **cur_seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move the first unacked segment to the unsent queue */ + /* Keep the unsent queue sorted. */ + seg = pcb->unacked; + pcb->unacked = seg->next; + + cur_seg = &(pcb->unsent); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = *cur_seg; + *cur_seg = seg; + + ++pcb->nrtx; + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + snmp_inc_tcpretranssegs(); + /* No need to call tcp_output: we are always called from tcp_input() + and thus tcp_output directly returns. */ +} + + +/** + * Handle retransmission after three dupacks received + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit_fast(struct tcp_pcb *pcb) +{ + if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: dupacks %"U16_F" (%"U32_F + "), fast retransmit %"U32_F"\n", + (u16_t)pcb->dupacks, pcb->lastack, + ntohl(pcb->unacked->tcphdr->seqno))); + tcp_rexmit(pcb); + + /* Set ssthresh to half of the minimum of the current + * cwnd and the advertised window */ + if (pcb->cwnd > pcb->snd_wnd) { + pcb->ssthresh = pcb->snd_wnd / 2; + } else { + pcb->ssthresh = pcb->cwnd / 2; + } + + /* The minimum value for ssthresh should be 2 MSS */ + if (pcb->ssthresh < 2*pcb->mss) { + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: The minimum value for ssthresh %"U16_F + " should be min 2 mss %"U16_F"...\n", + pcb->ssthresh, 2*pcb->mss)); + pcb->ssthresh = 2*pcb->mss; + } + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + pcb->flags |= TF_INFR; + } +} + + +/** + * Send keepalive packets to keep a connection active although + * no data is sent over it. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a keepalive packet + */ +void +tcp_keepalive(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); + + p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1)); + if(p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_keepalive: could not allocate memory for pbuf\n")); + return; + } + tcphdr = (struct tcp_hdr *)p->payload; + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, + IP_PROTO_TCP, p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + + pbuf_free(p); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", + pcb->snd_nxt - 1, pcb->rcv_nxt)); +} + + +/** + * Send persist timer zero-window probes to keep a connection active + * when a window update is lost. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a zero-window probe packet + */ +void +tcp_zero_window_probe(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + struct tcp_seg *seg; + u16_t offset = 0; + u16_t len; + u8_t is_fin; + + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" + U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_zero_window_probe: tcp_ticks %"U32_F + " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); + + seg = pcb->unacked; + + if(seg == NULL) { + seg = pcb->unsent; + } else { + struct ip_hdr *iphdr = NULL; + iphdr = (struct ip_hdr *)((char*)seg->p->payload + SIZEOF_ETH_HDR); + offset = IPH_HL(iphdr)*4; + offset += SIZEOF_ETH_HDR; + } + if(seg == NULL) { + return; + } + + is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); + /* we want to send one seqno: either FIN or data (no options) */ + len = is_fin ? 0 : 1; + + p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); + if(p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); + return; + } + tcphdr = (struct tcp_hdr *)p->payload; + + if (is_fin) { + /* FIN segment, no data */ + TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); + } else { + /* Data segment, copy in one byte from the head of the unacked queue */ + struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload; + char *d = ((char *)p->payload + TCP_HLEN); + if (pcb->unacked == NULL) + pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); + else { + thdr = (struct tcp_hdr *)((char*)seg->p->payload + offset); + pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4 + offset); + } + } + +#if CHECKSUM_GEN_TCP + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, + IP_PROTO_TCP, p->tot_len); +#endif + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + + pbuf_free(p); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F + " ackno %"U32_F".\n", + pcb->snd_nxt - 1, pcb->rcv_nxt)); +} +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/timers.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/timers.c new file mode 100755 index 0000000000..e682bd2d7c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/timers.c @@ -0,0 +1,513 @@ +/** + * @file + * Stack-internal timers implementation. + * This file includes timer callbacks for stack-internal timers as well as + * functions to set up or stop timers and check for expired timers. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#include "lwip/timers.h" +#include "lwip/tcp_impl.h" + +#if LWIP_TIMERS + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/tcpip.h" + +#include "lwip/ip_frag.h" +#include "netif/etharp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** The one and only timeout list */ +static struct sys_timeo *next_timeout = NULL; +#if NO_SYS +static u32_t timeouts_last_time; +#endif /* NO_SYS */ + +#if LWIP_TCP +/** global variable that shows if the tcp timer is currently scheduled or not */ +static int tcpip_tcp_timer_active; + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void ICACHE_FLASH_ATTR +tcpip_tcp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + /* call TCP timer handler */ + tcp_tmr(); + /* timer still needed? */ + if (tcp_active_pcbs || tcp_tw_pcbs) { + /* restart timer */ + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } else { + /* disable timer */ + tcpip_tcp_timer_active = 0; + } +} + +/** + * Called from TCP_REG when registering a new PCB: + * the reason is to have the TCP timer only running when + * there are active (or time-wait) PCBs. + */ +void +tcp_timer_needed(void) +{ + /* timer is off but needed again? */ + if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { + /* enable and start timer */ + tcpip_tcp_timer_active = 1; + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } +} + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ + +static void ICACHE_FLASH_ATTR +tcp_timer_coarse(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: tcp_tmr()\n")); + tcp_tmr(); + sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL); +} + +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +/** + * Timer callback function that calls ip_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void ICACHE_FLASH_ATTR +ip_reass_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); + ip_reass_tmr(); + sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +} +#endif /* IP_REASSEMBLY */ + +#if LWIP_ARP +/** + * Timer callback function that calls etharp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void ICACHE_FLASH_ATTR +arp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); + etharp_tmr(); + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +} +#endif /* LWIP_ARP */ + +#if LWIP_DHCP +/** + * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. + * + * @param arg unused argument + */ +extern void dhcps_coarse_tmr(void); +static void +dhcp_timer_coarse(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); + dhcp_coarse_tmr(); + dhcps_coarse_tmr(); + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); +} + +/** + * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dhcp_timer_fine(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); + dhcp_fine_tmr(); + sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +} +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP +/** + * Timer callback function that calls autoip_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +autoip_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); + autoip_tmr(); + sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +} +#endif /* LWIP_AUTOIP */ + +#if LWIP_IGMP +/** + * Timer callback function that calls igmp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +igmp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); + igmp_tmr(); + sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Timer callback function that calls dns_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dns_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); + dns_tmr(); + sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +} +#endif /* LWIP_DNS */ + +/** Initialize this module */ +void sys_timeouts_init(void) +{ +#if IP_REASSEMBLY + sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +#endif /* IP_REASSEMBLY */ +#if LWIP_ARP + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +#endif /* LWIP_ARP */ +#if LWIP_DHCP + DHCP_MAXRTX = 0; + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); + sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP + sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +#endif /* LWIP_IGMP */ +#if LWIP_DNS + sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +#endif /* LWIP_DNS */ + +#if LWIP_TCP + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); +// sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL); +#endif + +#if NO_SYS + /* Initialise timestamp for sys_check_timeouts */ + timeouts_last_time = NOW(); +#endif +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_timeouts_mbox_fetch() + * - by calling sys_check_timeouts() (NO_SYS==1 only) + * + * @param msecs time in milliseconds after that the timer should expire + * @param handler callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +#if LWIP_DEBUG_TIMERNAMES +void +sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) +#else /* LWIP_DEBUG_TIMERNAMES */ +void +sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +#endif /* LWIP_DEBUG_TIMERNAMES */ +{ + struct sys_timeo *timeout, *t; + + timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); + return; + } + timeout->next = NULL; + timeout->h = handler; + timeout->arg = arg; + timeout->time = msecs; +#if LWIP_DEBUG_TIMERNAMES + timeout->handler_name = handler_name; + LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", + (void *)timeout, msecs, handler_name, (void *)arg)); +#endif /* LWIP_DEBUG_TIMERNAMES */ + + if (next_timeout == NULL) { + next_timeout = timeout; + return; + } + + if (next_timeout->time > msecs) { + next_timeout->time -= msecs; + timeout->next = next_timeout; + next_timeout = timeout; + } else { + for(t = next_timeout; t != NULL; t = t->next) { + timeout->time -= t->time; + if (t->next == NULL || t->next->time > timeout->time) { + if (t->next != NULL) { + t->next->time -= timeout->time; + } + timeout->next = t->next; + t->next = timeout; + break; + } + } + } +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry, even though the timeout has not triggered yet. + * + * @note This function only works as expected if there is only one timeout + * calling 'handler' in the list of timeouts. + * + * @param handler callback function that would be called by the timeout + * @param arg callback argument that would be passed to handler +*/ +void +sys_untimeout(sys_timeout_handler handler, void *arg) +{ + struct sys_timeo *prev_t, *t; + + if (next_timeout == NULL) { + return; + } + + for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { + if ((t->h == handler) && (t->arg == arg)) { + /* We have a match */ + /* Unlink from previous in list */ + if (prev_t == NULL) { + next_timeout = t->next; + } else { + prev_t->next = t->next; + } + /* If not the last one, add time of this one back to next */ + if (t->next != NULL) { + t->next->time += t->time; + } + memp_free(MEMP_SYS_TIMEOUT, t); + return; + } + } + return; +} + +#if NO_SYS +extern uint8 timer2_ms_flag; +/** Handle timeouts for NO_SYS==1 (i.e. without using + * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout + * handler functions when timeouts expire. + * + * Must be called periodically from your main loop. + */ +void +sys_check_timeouts(void) +{ + struct sys_timeo *tmptimeout; + u32_t diff; + sys_timeout_handler handler; + void *arg; + int had_one; + u32_t now; + + now = NOW(); + if (next_timeout) { + /* this cares for wraparounds */ + if (timer2_ms_flag == 0) { + diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>4)/1000); + } else { + diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>8)/1000); + } + do + { + had_one = 0; + tmptimeout = next_timeout; + if (tmptimeout->time <= diff) { + /* timeout has expired */ + had_one = 1; + timeouts_last_time = now; + diff -= tmptimeout->time; + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", + tmptimeout->handler_name, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { + handler(arg); + } + } + /* repeat until all expired timers have been called */ + }while(had_one); + } +} + +/** Set back the timestamp of the last call to sys_check_timeouts() + * This is necessary if sys_check_timeouts() hasn't been called for a long + * time (e.g. while saving energy) to prevent all timer functions of that + * period being called. + */ +void +sys_restart_timeouts(void) +{ + timeouts_last_time = NOW(); +} + +#else /* NO_SYS */ + +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +void +sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +{ + u32_t time_needed; + struct sys_timeo *tmptimeout; + sys_timeout_handler handler; + void *arg; + + again: + if (!next_timeout) { + time_needed = sys_arch_mbox_fetch(mbox, msg, 0); + } else { + if (next_timeout->time > 0) { + time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); + } else { + time_needed = SYS_ARCH_TIMEOUT; + } + + if (time_needed == SYS_ARCH_TIMEOUT) { + /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message + could be fetched. We should now call the timeout handler and + deallocate the memory allocated for the timeout. */ + tmptimeout = next_timeout; + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", + tmptimeout->handler_name, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { + /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the + timeout handler function. */ + LOCK_TCPIP_CORE(); + handler(arg); + UNLOCK_TCPIP_CORE(); + } + LWIP_TCPIP_THREAD_ALIVE(); + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout + occured. The time variable is set to the number of + milliseconds we waited for the message. */ + if (time_needed < next_timeout->time) { + next_timeout->time -= time_needed; + } else { + next_timeout->time = 0; + } + } + } +} + +#endif /* NO_SYS */ + +#else /* LWIP_TIMERS */ +/* Satisfy the TCP code which calls this function */ +void +tcp_timer_needed(void) +{ +} +#endif /* LWIP_TIMERS */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/udp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/udp.c new file mode 100755 index 0000000000..db12c48e93 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/core/udp.c @@ -0,0 +1,977 @@ +/** + * @file + * User Datagram Protocol module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +/* udp.c + * + * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). + * + */ + +/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! + */ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" +#include "lwip/dhcp.h" + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * Process an incoming UDP datagram. + * + * Given an incoming UDP datagram (as a chain of pbufs) this function + * finds a corresponding UDP PCB and hands over the pbuf to the pcbs + * recv function. If no pcb is found or the datagram is incorrect, the + * pbuf is freed. + * + * @param p pbuf to be demultiplexed to a UDP PCB. + * @param inp network interface on which the datagram was received. + * + */ +void ICACHE_FLASH_ATTR +udp_input(struct pbuf *p, struct netif *inp) +{ + struct udp_hdr *udphdr; + struct udp_pcb *pcb, *prev; + struct udp_pcb *uncon_pcb; + struct ip_hdr *iphdr; + u16_t src, dest; + u8_t local_match; + u8_t broadcast; + + PERF_START; + + UDP_STATS_INC(udp.recv); + + iphdr = (struct ip_hdr *)p->payload; + + /* Check minimum length (IP header + UDP header) + * and move payload pointer to UDP header */ + if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { + /* drop short packets */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); + UDP_STATS_INC(udp.lenerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + + udphdr = (struct udp_hdr *)p->payload; + + /* is broadcast packet ? */ + broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); + + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); + + /* convert src and dest ports to host byte order */ + src = ntohs(udphdr->src); + dest = ntohs(udphdr->dest); + + udp_debug_print(udphdr); + + /* print the UDP source and destination */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " + "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", + ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), + ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), + ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), + ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); + +#if LWIP_DHCP + pcb = NULL; + /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by + the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ + if (dest == DHCP_CLIENT_PORT) { + /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ + if (src == DHCP_SERVER_PORT) { + if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { + /* accept the packe if + (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! + - inp->dhcp->pcb->remote == ANY or iphdr->src */ + if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || + ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { + pcb = inp->dhcp->pcb; + } + } + } + } else if (dest == DHCP_SERVER_PORT) { + if (src == DHCP_CLIENT_PORT) { + if ( inp->dhcps_pcb != NULL ) { + if ((ip_addr_isany(&inp->dhcps_pcb->local_ip) || + ip_addr_cmp(&(inp->dhcps_pcb->local_ip), ¤t_iphdr_dest))) { + pcb = inp->dhcps_pcb; + } + } + } + } else +#endif /* LWIP_DHCP */ + { + prev = NULL; + local_match = 0; + uncon_pcb = NULL; + /* Iterate through the UDP pcb list for a matching pcb. + * 'Perfect match' pcbs (connected to the remote port & ip address) are + * preferred. If no perfect match is found, the first unconnected pcb that + * matches the local port and ip address gets the datagram. */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + local_match = 0; + /* print the PCB local and remote address */ + LWIP_DEBUGF(UDP_DEBUG, + ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " + "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); + + /* compare PCB local addr+port to UDP destination addr+port */ + if ((pcb->local_port == dest) && + ((!broadcast && ip_addr_isany(&pcb->local_ip)) || + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || +#if LWIP_IGMP + ip_addr_ismulticast(¤t_iphdr_dest) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && (pcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ + local_match = 1; + if ((uncon_pcb == NULL) && + ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; + } + } + /* compare PCB remote addr+port to UDP source addr+port */ + if ((local_match != 0) && + (pcb->remote_port == src) && + (ip_addr_isany(&pcb->remote_ip) || + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { + /* the first fully matching PCB */ + if (prev != NULL) { + /* move the pcb to the front of udp_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } else { + UDP_STATS_INC(udp.cachehit); + } + break; + } + prev = pcb; + } + /* no fully matching pcb found? then look for an unconnected pcb */ + if (pcb == NULL) { + pcb = uncon_pcb; + } + } + + /* Check checksum if this is a match or if it was directed at us. */ + if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); +#if LWIP_UDPLITE + if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ +#if CHECKSUM_CHECK_UDP + u16_t chklen = ntohs(udphdr->len); + if (chklen < sizeof(struct udp_hdr)) { + if (chklen == 0) { + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet (See RFC 3828 chap. 3.1) */ + chklen = p->tot_len; + } else { + /* At least the UDP-Lite header must be covered by the + checksum! (Again, see RFC 3828 chap. 3.1) */ + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + } + if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, + IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } +#endif /* CHECKSUM_CHECK_UDP */ + } else +#endif /* LWIP_UDPLITE */ + { +#if CHECKSUM_CHECK_UDP + if (udphdr->chksum != 0) { + if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), + IP_PROTO_UDP, p->tot_len) != 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + } +#endif /* CHECKSUM_CHECK_UDP */ + } + if(pbuf_header(p, -UDP_HLEN)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + if (pcb != NULL) { + snmp_inc_udpindatagrams(); +#if SO_REUSE && SO_REUSE_RXTOALL + if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && + ((pcb->so_options & SOF_REUSEADDR) != 0)) { + /* pass broadcast- or multicast packets to all multicast pcbs + if SOF_REUSEADDR is set on the first match */ + struct udp_pcb *mpcb; + u8_t p_header_changed = 0; + for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { + if (mpcb != pcb) { + /* compare PCB local addr+port to UDP destination addr+port */ + if ((mpcb->local_port == dest) && + ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || + ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || +#if LWIP_IGMP + ip_addr_ismulticast(¤t_iphdr_dest) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && (mpcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ + /* pass a copy of the packet to all local matches */ + if (mpcb->recv != NULL) { + struct pbuf *q; + /* for that, move payload to IP header again */ + if (p_header_changed == 0) { + pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + p_header_changed = 1; + } + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + err_t err = pbuf_copy(q, p); + if (err == ERR_OK) { + /* move payload to UDP data */ + pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + } + } + } + } + } + } + if (p_header_changed) { + /* and move payload to UDP data again */ + pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + } + } +#endif /* SO_REUSE && SO_REUSE_RXTOALL */ + /* callback */ + if (pcb->recv != NULL) { + /* now the recv function is responsible for freeing p */ + pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); + } else { + /* no recv function registered? then we have to free the pbuf! */ + pbuf_free(p); + goto end; + } + } else { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); + +#if LWIP_ICMP + /* No match was found, send ICMP destination port unreachable unless + destination address was broadcast/multicast. */ + if (!broadcast && + !ip_addr_ismulticast(¤t_iphdr_dest)) { + /* move payload pointer back to ip header */ + pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); + LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); + icmp_dest_unreach(p, ICMP_DUR_PORT); + } +#endif /* LWIP_ICMP */ + UDP_STATS_INC(udp.proterr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpnoports(); + pbuf_free(p); + } + } else { + pbuf_free(p); + } +end: + PERF_STOP("udp_input"); +} + +/** + * Send data using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * + * The datagram will be sent to the current remote_ip & remote_port + * stored in pcb. If the pcb is not bound to a port, it will + * automatically be bound to a random port. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. + * + * @see udp_disconnect() udp_sendto() + */ +err_t ICACHE_FLASH_ATTR +udp_send(struct udp_pcb *pcb, struct pbuf *p) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); +} + +#if LWIP_CHECKSUM_ON_COPY +/** Same as udp_send() but with checksum + */ +err_t ICACHE_FLASH_ATTR +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + +/** + * Send data to a specified address using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * If the PCB already has a remote address association, it will + * be restored after the data is sent. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t ICACHE_FLASH_ATTR +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port) +{ +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** Same as udp_sendto(), but with checksum */ +err_t ICACHE_FLASH_ATTR +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ + struct netif *netif; + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); + + /* find the outgoing network interface for this packet */ +#if LWIP_IGMP + netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); +#else + netif = ip_route(dst_ip); +#endif /* LWIP_IGMP */ + + /* no outgoing network interface could be found? */ + if (netif == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY */ + return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY */ +} + +/** + * Send data to a specified address using UDP. + * The netif used for sending can be specified. + * + * This function exists mainly for DHCP, to be able to send UDP packets + * on a netif that is still down. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * @param netif the netif used for sending. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t ICACHE_FLASH_ATTR +udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) +{ +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t ICACHE_FLASH_ATTR +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ + struct udp_hdr *udphdr; + ip_addr_t *src_ip; + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + +#if IP_SOF_BROADCAST + /* broadcast filter? */ + if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + return ERR_VAL; + } +#endif /* IP_SOF_BROADCAST */ + + /* if the PCB is not yet bound to a port, bind it here */ + if (pcb->local_port == 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); + err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); + return err; + } + } + + /* not enough space to add an UDP header to first pbuf in given p chain? */ + if (pbuf_header(p, UDP_HLEN)) { + /* allocate header in a separate new pbuf */ + q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p (only if p contains data) */ + pbuf_chain(q, p); + } + /* first pbuf q points to header pbuf */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* adding space for header within p succeeded */ + /* first pbuf q equals given pbuf */ + q = p; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); + } + LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", + (q->len >= sizeof(struct udp_hdr))); + /* q now represents the packet to be sent */ + udphdr = (struct udp_hdr *)q->payload; + udphdr->src = htons(pcb->local_port); + udphdr->dest = htons(dst_port); + /* in UDP, 0 checksum means 'no checksum' */ + udphdr->chksum = 0x0000; + + /* Multicast Loop? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_IGMP */ + + + /* PCB local address is IP_ANY_ADDR? */ + if (ip_addr_isany(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = &(netif->ip_addr); + } else { + /* check if UDP PCB local IP address is correct + * this could be an old address if netif->ip_addr has changed */ + if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { + /* local_ip doesn't match, drop the packet */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + q = NULL; + /* p is still referenced by the caller, and will live on */ + } + return ERR_VAL; + } + /* use UDP PCB local IP address as source address */ + src_ip = &(pcb->local_ip); + } + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); + +#if LWIP_UDPLITE + /* UDP Lite protocol? */ + if (pcb->flags & UDP_FLAGS_UDPLITE) { + u16_t chklen, chklen_hdr; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); + /* set UDP message length in UDP header */ + chklen_hdr = chklen = pcb->chksum_len_tx; + if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { + if (chklen != 0) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); + } + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet. (See RFC 3828 chap. 3.1) + At least the UDP-Lite header must be covered by the + checksum, therefore, if chksum_len has an illegal + value, we generate the checksum over the complete + packet to be safe. */ + chklen_hdr = 0; + chklen = q->tot_len; + } + udphdr->len = htons(chklen_hdr); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, + IP_PROTO_UDPLITE, q->tot_len, +#if !LWIP_CHECKSUM_ON_COPY + chklen); +#else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* !LWIP_CHECKSUM_ON_COPY */ + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } +#endif /* CHECKSUM_GEN_UDP */ + /* output to IP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ + } else +#endif /* LWIP_UDPLITE */ + { /* UDP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); + udphdr->len = htons(q->tot_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + q->tot_len, UDP_HLEN); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); + } + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; + } +#endif /* CHECKSUM_GEN_UDP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); + /* output to IP */ +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); +#if LWIP_NETIF_HWADDRHINT + netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ + } + /* TODO: must this be increased even if error occured? */ + snmp_inc_udpoutdatagrams(); + + /* did we chain a separate header pbuf earlier? */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + q = NULL; + /* p is still referenced by the caller, and will live on */ + } + + UDP_STATS_INC(udp.xmit); + return err; +} + +/** + * Bind an UDP PCB. + * + * @param pcb UDP PCB to be bound with a local address ipaddr and port. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * @param port local UDP port to bind with. Use 0 to automatically bind + * to a random port between UDP_LOCAL_PORT_RANGE_START and + * UDP_LOCAL_PORT_RANGE_END. + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified ipaddr and port are already bound to by + * another UDP PCB. + * + * @see udp_disconnect() + */ +err_t ICACHE_FLASH_ATTR +udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + u8_t rebind; + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); + ip_addr_debug_print(UDP_DEBUG, ipaddr); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); + + rebind = 0; + /* Check for double bind and rebind of the same pcb */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + /* is this UDP PCB already on active list? */ + if (pcb == ipcb) { + /* pcb may occur at most once in active list */ + LWIP_ASSERT("rebind == 0", rebind == 0); + /* pcb already in list, just rebind */ + rebind = 1; + } + + /* By default, we don't allow to bind to a port that any other udp + PCB is alread bound to, unless *all* PCBs with that port have tha + REUSEADDR flag set. */ +#if SO_REUSE + else if (((pcb->so_options & SOF_REUSEADDR) == 0) && + ((ipcb->so_options & SOF_REUSEADDR) == 0)) { +#else /* SO_REUSE */ + /* port matches that of PCB in list and REUSEADDR not set -> reject */ + else { +#endif /* SO_REUSE */ + if ((ipcb->local_port == port) && + /* IP address matches, or one is IP_ADDR_ANY? */ + (ip_addr_isany(&(ipcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { + /* other PCB already binds to this local IP and port */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); + return ERR_USE; + } + } + } + + ip_addr_set(&pcb->local_ip, ipaddr); + + /* no port specified? */ + if (port == 0) { +#ifndef UDP_LOCAL_PORT_RANGE_START +#define UDP_LOCAL_PORT_RANGE_START 4096 +#define UDP_LOCAL_PORT_RANGE_END 0x7fff +#endif + port = UDP_LOCAL_PORT_RANGE_START; + ipcb = udp_pcbs; + while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { + if (ipcb->local_port == port) { + /* port is already used by another udp_pcb */ + port++; + /* restart scanning all udp pcbs */ + ipcb = udp_pcbs; + } else { + /* go on with next udp pcb */ + ipcb = ipcb->next; + } + } + if (ipcb != NULL) { + /* no more ports available in local range */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); + return ERR_USE; + } + } + pcb->local_port = port; + snmp_insert_udpidx_tree(pcb); + /* pcb not active yet? */ + if (rebind == 0) { + /* place the PCB on the active list if not already there */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), + pcb->local_port)); + return ERR_OK; +} +/** + * Connect an UDP PCB. + * + * This will associate the UDP PCB with the remote address. + * + * @param pcb UDP PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * @param port remote UDP port to connect with. + * + * @return lwIP error code + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * The udp pcb is bound to a random local port if not already bound. + * + * @see udp_disconnect() + */ +err_t ICACHE_FLASH_ATTR +udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + + if (pcb->local_port == 0) { + err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + return err; + } + } + + ip_addr_set(&pcb->remote_ip, ipaddr); + pcb->remote_port = port; + pcb->flags |= UDP_FLAGS_CONNECTED; +/** TODO: this functionality belongs in upper layers */ +#ifdef LWIP_UDP_TODO + /* Nail down local IP for netconn_addr()/getsockname() */ + if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { + struct netif *netif; + + if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + /** TODO: this will bind the udp pcb locally, to the interface which + is used to route output packets to the remote address. However, we + might want to accept incoming packets on any interface! */ + pcb->local_ip = netif->ip_addr; + } else if (ip_addr_isany(&pcb->remote_ip)) { + pcb->local_ip.addr = 0; + } +#endif + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), + pcb->local_port)); + + /* Insert UDP PCB into the list of active UDP PCBs. */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb == ipcb) { + /* already on the list, just return */ + return ERR_OK; + } + } + /* PCB not yet on the list, add PCB now */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + return ERR_OK; +} + +/** + * Disconnect a UDP PCB + * + * @param pcb the udp pcb to disconnect. + */ +void ICACHE_FLASH_ATTR +udp_disconnect(struct udp_pcb *pcb) +{ + /* reset remote address association */ + ip_addr_set_any(&pcb->remote_ip); + pcb->remote_port = 0; + /* mark PCB as unconnected */ + pcb->flags &= ~UDP_FLAGS_CONNECTED; +} + +/** + * Set a receive callback for a UDP PCB + * + * This callback will be called when receiving a datagram for the pcb. + * + * @param pcb the pcb for wich to set the recv callback + * @param recv function pointer of the callback function + * @param recv_arg additional argument to pass to the callback function + */ +void ICACHE_FLASH_ATTR +udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * Remove an UDP PCB. + * + * @param pcb UDP PCB to be removed. The PCB is removed from the list of + * UDP PCB's and the data structure is freed from memory. + * + * @see udp_new() + */ +void ICACHE_FLASH_ATTR +udp_remove(struct udp_pcb *pcb) +{ + struct udp_pcb *pcb2; + + snmp_delete_udpidx_tree(pcb); + /* pcb to be removed is first in list? */ + if (udp_pcbs == pcb) { + /* make list start at 2nd pcb */ + udp_pcbs = udp_pcbs->next; + /* pcb not 1st in list */ + } else { + for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in udp_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + } + } + } + memp_free(MEMP_UDP_PCB, pcb); +} + +/** + * Create a UDP PCB. + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * ICACHE_FLASH_ATTR +udp_new(void) +{ + struct udp_pcb *pcb; + pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); + /* could allocate UDP PCB? */ + if (pcb != NULL) { + /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 + * which means checksum is generated over the whole datagram per default + * (recommended as default by RFC 3828). */ + /* initialize PCB to all zeroes */ + os_memset(pcb, 0, sizeof(struct udp_pcb)); + pcb->ttl = UDP_TTL; + } + return pcb; +} + +#if UDP_DEBUG +/** + * Print UDP header information for debug purposes. + * + * @param udphdr pointer to the udp header in memory. + */ +void ICACHE_FLASH_ATTR +udp_debug_print(struct udp_hdr *udphdr) +{ + LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + ntohs(udphdr->src), ntohs(udphdr->dest))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", + ntohs(udphdr->len), ntohs(udphdr->chksum))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/Makefile new file mode 100755 index 0000000000..f03613f6ed --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblwipnetif.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/etharp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/etharp.c new file mode 100755 index 0000000000..7eb328ace4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/lwip/netif/etharp.c @@ -0,0 +1,1413 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_gratuitous(our_netif) upon address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET + +#include "lwip/ip_addr.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +const struct eth_addr ethzero = {{0,0,0,0,0,0}}; + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 5000, this is + * (240 * 5) seconds = 20 minutes. + */ +#define ARP_MAXAGE 240 +/** Re-request a used ARP entry 1 minute before it would expire to prevent + * breaking a steadily used connection because the ARP entry timed out. */ +#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12) +/** the time an ARP entry stays pending after first request, + * for ARP_TMR_INTERVAL = 5000, this is + * (2 * 5) seconds = 10 seconds. + * + * @internal Keep this number at least 2, otherwise it might + * run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 2 + +#define HWTYPE_ETHERNET 1 + +enum etharp_state { + ETHARP_STATE_EMPTY = 0, + ETHARP_STATE_PENDING, + ETHARP_STATE_STABLE, + ETHARP_STATE_STABLE_REREQUESTING +}; + +struct etharp_entry { +#if ARP_QUEUEING + /** Pointer to queue of pending outgoing packets on this ARP entry. */ + struct etharp_q_entry *q; +#else /* ARP_QUEUEING */ + /** Pointer to a single pending outgoing packet on this ARP entry. */ + struct pbuf *q; +#endif /* ARP_QUEUEING */ + ip_addr_t ipaddr; + struct eth_addr ethaddr; +#if LWIP_SNMP || LWIP_ARP + struct netif *netif; +#endif /* LWIP_SNMP */ + u8_t state; + u8_t ctime; +#if ETHARP_SUPPORT_STATIC_ENTRIES + u8_t static_entry; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +}; + +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; + +#if !LWIP_NETIF_HWADDRHINT +static u8_t etharp_cached_entry; +#endif /* !LWIP_NETIF_HWADDRHINT */ + +/** Try hard to create a new entry - we want the IP address to appear in + the cache (even if this means removing an active entry or so). */ +#define ETHARP_FLAG_TRY_HARD 1 +#define ETHARP_FLAG_FIND_ONLY 2 +#define ETHARP_FLAG_STATIC_ENTRY 4 + +#if LWIP_NETIF_HWADDRHINT +#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ + *((netif)->addr_hint) = (hint); +#else /* LWIP_NETIF_HWADDRHINT */ +#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) +#endif /* LWIP_NETIF_HWADDRHINT */ + +static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags); + + +/* Some checks, instead of etharp_init(): */ +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) + #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" +#endif + + +#if ARP_QUEUEING +/** + * Free a complete queue of etharp entries + * + * @param q a qeueue of etharp_q_entry's to free + */ +static void +free_etharp_q(struct etharp_q_entry *q) +{ + struct etharp_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ARP_QUEUE, r); + } +} +#else /* ARP_QUEUEING */ + +/** Compatibility define: free the queued pbuf */ +#define free_etharp_q(q) pbuf_free(q) + +#endif /* ARP_QUEUEING */ + +/** Clean up ARP table entries */ +static void ICACHE_FLASH_ATTR +free_entry(int i) +{ + /* remove from SNMP ARP index tree */ + snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); + /* and empty packet queue */ + if (arp_table[i].q != NULL) { + /* remove all queued packets */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + free_etharp_q(arp_table[i].q); + arp_table[i].q = NULL; + } + /* recycle entry for re-use */ + arp_table[i].state = ETHARP_STATE_EMPTY; +#if ETHARP_SUPPORT_STATIC_ENTRIES + arp_table[i].static_entry = 0; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +#ifdef LWIP_DEBUG + /* for debugging, clean out the complete entry */ + arp_table[i].ctime = 0; +#if LWIP_SNMP + arp_table[i].netif = NULL; +#endif /* LWIP_SNMP */ + ip_addr_set_zero(&arp_table[i].ipaddr); + arp_table[i].ethaddr = ethzero; +#endif /* LWIP_DEBUG */ +} + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ + u8_t i; + + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); + /* remove expired entries from the ARP table */ + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if (state != ETHARP_STATE_EMPTY +#if ETHARP_SUPPORT_STATIC_ENTRIES + && (arp_table[i].static_entry == 0) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + ) { + arp_table[i].ctime++; + if ((arp_table[i].ctime >= ARP_MAXAGE) || + ((arp_table[i].state == ETHARP_STATE_PENDING) && + (arp_table[i].ctime >= ARP_MAXPENDING))) { + /* pending or stable entry has become old! */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", + arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); + /* clean up entries that have just been expired */ + free_entry(i); + } + else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { + /* Reset state to stable, so that the next transmitted packet will + re-send an ARP request. */ + arp_table[i].state = ETHARP_STATE_STABLE; + } +#if ARP_QUEUEING + /* still pending entry? (not expired) */ + if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* resend an ARP query here? */ + } +#endif /* ARP_QUEUEING */ + } + } +} + +/** + * Search the ARP table for a matching or new entry. + * + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + * + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + * + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags @see definition of ETHARP_FLAG_* + * @param netif netif related to this address (used for NETIF_HWADDRHINT) + * + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s8_t ICACHE_FLASH_ATTR +find_entry(ip_addr_t *ipaddr, u8_t flags) +{ + s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; + s8_t empty = ARP_TABLE_SIZE; + u8_t i = 0, age_pending = 0, age_stable = 0; + /* oldest entry with packets on queue */ + s8_t old_queue = ARP_TABLE_SIZE; + /* its age */ + u8_t age_queue = 0; + + /** + * a) do a search through the cache, remember candidates + * b) select candidate entry + * c) create new entry + */ + + /* a) in a single search sweep, do all of this + * 1) remember the first empty entry (if any) + * 2) remember the oldest stable entry (if any) + * 3) remember the oldest pending entry without queued packets (if any) + * 4) remember the oldest pending entry with queued packets (if any) + * 5) search for a matching IP entry, either pending or stable + * until 5 matches, or all entries are searched for. + */ + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + /* no empty entry found yet and now we do find one? */ + if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { + LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); + /* remember first empty entry */ + empty = i; + } else if (state != ETHARP_STATE_EMPTY) { + LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", + state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); + /* if given, does IP address match IP address in ARP entry? */ + if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i)); + /* found exact IP address match, simply bail out */ + return i; + } + /* pending entry? */ + if (state == ETHARP_STATE_PENDING) { + /* pending with queued packets? */ + if (arp_table[i].q != NULL) { + if (arp_table[i].ctime >= age_queue) { + old_queue = i; + age_queue = arp_table[i].ctime; + } + } else + /* pending without queued packets? */ + { + if (arp_table[i].ctime >= age_pending) { + old_pending = i; + age_pending = arp_table[i].ctime; + } + } + /* stable entry? */ + } else if (state >= ETHARP_STATE_STABLE) { +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* don't record old_stable for static entries since they never expire */ + if (arp_table[i].static_entry == 0) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* remember entry with oldest stable entry in oldest, its age in maxtime */ + if (arp_table[i].ctime >= age_stable) { + old_stable = i; + age_stable = arp_table[i].ctime; + } + } + } + } + } + /* { we have no match } => try to create a new entry */ + + /* don't create new entry, only search? */ + if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || + /* or no empty entry found and not allowed to recycle? */ + ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); + return (s8_t)ERR_MEM; + } + + /* b) choose the least destructive entry to recycle: + * 1) empty entry + * 2) oldest stable entry + * 3) oldest pending entry without queued packets + * 4) oldest pending entry with queued packets + * + * { ETHARP_FLAG_TRY_HARD is set at this point } + */ + + /* 1) empty entry available? */ + if (empty < ARP_TABLE_SIZE) { + i = empty; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); + } else { + /* 2) found recyclable stable entry? */ + if (old_stable < ARP_TABLE_SIZE) { + /* recycle oldest stable*/ + i = old_stable; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); + /* no queued packets should exist on stable entries */ + LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); + /* 3) found recyclable pending entry without queued packets? */ + } else if (old_pending < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_pending; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); + /* 4) found recyclable pending entry with queued packets? */ + } else if (old_queue < ARP_TABLE_SIZE) { + /* recycle oldest pending (queued packets are free in free_entry) */ + i = old_queue; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); + /* no empty or recyclable entries found */ + } else { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n")); + return (s8_t)ERR_MEM; + } + + /* { empty or recyclable entry found } */ + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + free_entry(i); + } + + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", + arp_table[i].state == ETHARP_STATE_EMPTY); + + /* IP address given? */ + if (ipaddr != NULL) { + /* set IP address */ + ip_addr_copy(arp_table[i].ipaddr, *ipaddr); + } + arp_table[i].ctime = 0; +#if ETHARP_SUPPORT_STATIC_ENTRIES + arp_table[i].static_entry = 0; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + return (err_t)i; +} + +/** + * Send an IP packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t ICACHE_FLASH_ATTR +etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; + + LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", + (netif->hwaddr_len == ETHARP_HWADDR_LEN)); + ETHADDR32_COPY(ðhdr->dest, dst); + ETHADDR16_COPY(ðhdr->src, src); + ethhdr->type = PP_HTONS(ETHTYPE_IP); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); + /* send the packet */ + return netif->linkoutput(netif, p); +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + * + * @param netif netif related to this entry (used for NETIF_ADDRHINT) + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags @see definition of ETHARP_FLAG_* + * + * @return + * - ERR_OK Succesfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t ICACHE_FLASH_ATTR +update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ + s8_t i; + LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], + ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); + /* non-unicast address? */ + if (ip_addr_isany(ipaddr) || + ip_addr_isbroadcast(ipaddr, netif) || + ip_addr_ismulticast(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + /* find or create ARP entry */ + i = find_entry(ipaddr, flags); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + +#if ETHARP_SUPPORT_STATIC_ENTRIES + if (flags & ETHARP_FLAG_STATIC_ENTRY) { + /* record static type */ + arp_table[i].static_entry = 1; + } +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + + /* mark it stable */ + arp_table[i].state = ETHARP_STATE_STABLE; + +#if LWIP_SNMP + /* record network interface */ + arp_table[i].netif = netif; +#endif /* LWIP_SNMP */ + /* insert in SNMP ARP index tree */ + snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + /* update address */ + ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); + /* reset time stamp */ + arp_table[i].ctime = 0; + /* this is where we will send out queued packets! */ +#if ARP_QUEUEING + while (arp_table[i].q != NULL) { + struct pbuf *p; + /* remember remainder of queue */ + struct etharp_q_entry *q = arp_table[i].q; + /* pop first item off the queue */ + arp_table[i].q = q->next; + /* get the packet pointer */ + p = q->p; + /* now queue entry can be freed */ + memp_free(MEMP_ARP_QUEUE, q); +#else /* ARP_QUEUEING */ + if (arp_table[i].q != NULL) { + struct pbuf *p = arp_table[i].q; + arp_table[i].q = NULL; +#endif /* ARP_QUEUEING */ + /* send the queued IP packet */ + etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); + /* free the queued IP packet */ + pbuf_free(p); + } + return ERR_OK; +} + +#if ETHARP_SUPPORT_STATIC_ENTRIES +/** Add a new static entry to the ARP table. If an entry exists for the + * specified IP address, this entry is overwritten. + * If packets are queued for the specified IP address, they are sent out. + * + * @param ipaddr IP address for the new static entry + * @param ethaddr ethernet address for the new static entry + * @return @see return values of etharp_add_static_entry + */ +err_t +etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) +{ + struct netif *netif; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], + ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); + + netif = ip_route(ipaddr); + if (netif == NULL) { + return ERR_RTE; + } + + return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); +} + +/** Remove a static entry from the ARP table previously added with a call to + * etharp_add_static_entry. + * + * @param ipaddr IP address of the static entry to remove + * @return ERR_OK: entry removed + * ERR_MEM: entry wasn't found + * ERR_ARG: entry wasn't a static entry but a dynamic one + */ +err_t +etharp_remove_static_entry(ip_addr_t *ipaddr) +{ + s8_t i; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); + + /* find or create ARP entry */ + i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + + if ((arp_table[i].state != ETHARP_STATE_STABLE) || + (arp_table[i].static_entry == 0)) { + /* entry wasn't a static entry, cannot remove it */ + return ERR_ARG; + } + /* entry found, free it */ + free_entry(i); + return ERR_OK; +} +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +/** + * Remove all ARP table entries of the specified netif. + * + * @param netif points to a network interface + */ +void ICACHE_FLASH_ATTR etharp_cleanup_netif(struct netif *netif) +{ + u8_t i; + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { + free_entry(i); + } + } +} + +/** + * Finds (stable) ethernet/IP address pair from ARP table + * using interface and IP address index. + * @note the addresses in the ARP table are in network order! + * + * @param netif points to interface index + * @param ipaddr points to the (network order) IP address index + * @param eth_ret points to return pointer + * @param ip_ret points to return pointer + * @return table index if found, -1 otherwise + */ +s8_t +etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret) +{ + s8_t i; + + LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", + eth_ret != NULL && ip_ret != NULL); + + LWIP_UNUSED_ARG(netif); + + i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); + if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { + *eth_ret = &arp_table[i].ethaddr; + *ip_ret = &arp_table[i].ipaddr; + return i; + } + return -1; +} + +#if ETHARP_TRUST_IP_MAC +/** + * Updates the ARP table using the given IP packet. + * + * Uses the incoming IP packet's source address to update the + * ARP cache for the local network. The function does not alter + * or free the packet. This function must be called before the + * packet p is passed to the IP layer. + * + * @param netif The lwIP network interface on which the IP packet pbuf arrived. + * @param p The IP packet that arrived on netif. + * + * @return NULL + * + * @see pbuf_free() + */ +static void ICACHE_FLASH_ATTR +etharp_ip_input(struct netif *netif, struct pbuf *p) +{ + struct eth_hdr *ethhdr; + struct ip_hdr *iphdr; + ip_addr_t iphdr_src; + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + /* Only insert an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + ethhdr = (struct eth_hdr *)p->payload; + iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); +#if ETHARP_SUPPORT_VLAN + if (ethhdr->type == ETHTYPE_VLAN) { + iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); + } +#endif /* ETHARP_SUPPORT_VLAN */ + + ip_addr_copy(iphdr_src, iphdr->src); + + /* source is not on the local network? */ + if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) { + /* do nothing */ + return; + } + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); + /* update the source IP address in the cache, if present */ + /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk + * back soon (for example, if the destination IP address is ours. */ + update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); +} +#endif /* ETHARP_TRUST_IP_MAC */ + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param ethaddr Ethernet address of netif. + * @param p The ARP packet that arrived on netif. Is freed by this function. + * + * @return NULL + * + * @see pbuf_free() + */ +static void ICACHE_FLASH_ATTR +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ + struct etharp_hdr *hdr; + struct eth_hdr *ethhdr; + /* these are aligned properly, whereas the ARP header fields might not be */ + ip_addr_t sipaddr, dipaddr; + u8_t for_us; +#if LWIP_AUTOIP + const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ +#ifdef EBUF_LWIP + struct pbuf *q; +#endif /* EBUF_LWIP */ + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + /* drop short ARP packets: we have to check for p->len instead of p->tot_len here + since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ + if (p->len < SIZEOF_ETHARP_PACKET) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, + (s16_t)SIZEOF_ETHARP_PACKET)); + ETHARP_STATS_INC(etharp.lenerr); + ETHARP_STATS_INC(etharp.drop); + pbuf_free(p); + return; + } + + ethhdr = (struct eth_hdr *)p->payload; + hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); +#if ETHARP_SUPPORT_VLAN + if (ethhdr->type == ETHTYPE_VLAN) { + hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); + } +#endif /* ETHARP_SUPPORT_VLAN */ + + /* RFC 826 "Packet Reception": */ + if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || + (hdr->hwlen != ETHARP_HWADDR_LEN) || + (hdr->protolen != sizeof(ip_addr_t)) || + (hdr->proto != PP_HTONS(ETHTYPE_IP)) || + (ethhdr->type != PP_HTONS(ETHTYPE_ARP))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", + hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type)); + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + pbuf_free(p); + return; + } + ETHARP_STATS_INC(etharp.recv); + +#if LWIP_AUTOIP + /* We have to check if a host already has configured our random + * created link local address and continously check if there is + * a host with this IP-address so we can detect collisions */ + autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). */ + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); + + /* this interface is not configured? */ + if (ip_addr_isany(&netif->ip_addr)) { + for_us = 0; + } else { + /* ARP packet directed to us? */ + for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr)); + } + + /* ARP message directed to us? + -> add IP address in ARP cache; assume requester wants to talk to us, + can result in directly sending the queued packets for this host. + ARP message not directed to us? + -> update the source IP address in the cache, if present */ + update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), + for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); + + /* now act on the message itself */ + switch (hdr->opcode) { + /* ARP request? */ + case PP_HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + * reply. In any case, we time-stamp any existing ARP entry, + * and possiby send out an IP packet that was queued on it. */ + + LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); + /* ARP request for our address? */ + if (for_us) { + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); + /* Re-use pbuf to send ARP reply. + Since we are re-using an existing pbuf, we can't call etharp_raw since + that would allocate a new pbuf. */ + hdr->opcode = htons(ARP_REPLY); + + IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); + IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr); + + LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", + (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +#if LWIP_AUTOIP + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; +#endif /* LWIP_AUTOIP */ + + ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); +#if LWIP_AUTOIP + ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); +#else /* LWIP_AUTOIP */ + ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); +#endif /* LWIP_AUTOIP */ + ETHADDR16_COPY(&hdr->shwaddr, ethaddr); + ETHADDR16_COPY(ðhdr->src, ethaddr); + + /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header + are already correct, we tested that before */ +#ifdef EBUF_LWIP + /* + * don't do flip-flop here... do a copy here. + * otherwise, we need to handle existing pbuf->eb in ieee80211_output.c + */ + + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + pbuf_copy(q, p); + //pbuf_free(p); + } else { + LWIP_ASSERT("q != NULL", q != NULL); + } + + netif->linkoutput(netif, q); + pbuf_free(q); +#else + + /* return ARP reply */ + netif->linkoutput(netif, p); +#endif /* ESF_LWIP */ + /* we are not configured? */ + } else if (ip_addr_isany(&netif->ip_addr)) { + /* { for_us == 0 and netif->ip_addr.addr == 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); + /* request was not directed to us */ + } else { + /* { for_us == 0 and netif->ip_addr.addr != 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); + } + break; + case PP_HTONS(ARP_REPLY): + /* ARP reply. We already updated the ARP cache earlier. */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) + /* DHCP wants to know about ARP replies from any host with an + * IP address also offered to us by the DHCP server. We do not + * want to take a duplicate IP address on a single network. + * @todo How should we handle redundant (fail-over) interfaces? */ + dhcp_arp_reply(netif, &sipaddr); +#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ + break; + default: + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); + ETHARP_STATS_INC(etharp.err); + break; + } + /* free ARP packet */ + pbuf_free(p); +} + +/** Just a small helper function that sends a pbuf to an ethernet address + * in the arp_table specified by the index 'arp_idx'. + */ +static err_t ICACHE_FLASH_ATTR +etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) +{ + LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", + arp_table[arp_idx].state >= ETHARP_STATE_STABLE); + /* if arp table entry is about to expire: re-request it, + but only if its state is ETHARP_STATE_STABLE to prevent flooding the + network with ARP requests if this address is used frequently. */ + if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && + (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { + if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; + } + } + + return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), + &arp_table[arp_idx].ethaddr); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t +etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) +{ + struct eth_addr *dest, mcastaddr; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_output: could not allocate room for header.\n")); + LINK_STATS_INC(link.lenerr); + return ERR_BUF; + } + + /* assume unresolved Ethernet address */ + dest = NULL; + /* Determine on destination hardware address. Broadcasts and multicasts + * are special, other IP addresses are looked up in the ARP table. */ + + /* broadcast destination IP address? */ + if (ip_addr_isbroadcast(ipaddr, netif)) { + /* broadcast on Ethernet also */ + dest = (struct eth_addr *)ðbroadcast; + /* multicast destination IP address? */ + } else if (ip_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address.*/ + mcastaddr.addr[0] = 0x01; + mcastaddr.addr[1] = 0x00; + mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + /* destination Ethernet address is multicast */ + dest = &mcastaddr; + /* unicast destination IP address? */ + } else { + s8_t i; + /* outside local network? if so, this can neither be a global broadcast nor + a subnet broadcast. */ + if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && + !ip_addr_islinklocal(ipaddr)) { +#if LWIP_AUTOIP + struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + + sizeof(struct eth_hdr)); + /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with + a link-local source address must always be "directly to its destination + on the same physical link. The host MUST NOT send the packet to any + router for forwarding". */ + if (!ip_addr_islinklocal(&iphdr->src)) +#endif /* LWIP_AUTOIP */ + { + /* interface has default gateway? */ + if (!ip_addr_isany(&netif->gw)) { + /* send to hardware address of default gateway IP address */ + ipaddr = &(netif->gw); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + } +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t etharp_cached_entry = *(netif->addr_hint); + if (etharp_cached_entry < ARP_TABLE_SIZE) { +#endif /* LWIP_NETIF_HWADDRHINT */ + if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && + (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) { + /* the per-pcb-cached entry is stable and the right one! */ + ETHARP_STATS_INC(etharp.cachehit); + return etharp_output_to_arp_index(netif, q, etharp_cached_entry); + } +#if LWIP_NETIF_HWADDRHINT + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + /* find stable entry: do this here since this is a critical path for + throughput and etharp_find_entry() is kind of slow */ + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if ((arp_table[i].state >= ETHARP_STATE_STABLE) && + (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr))) { + /* found an existing, stable entry */ + ETHARP_SET_HINT(netif, i); + return etharp_output_to_arp_index(netif, q, i); + } + } + /* queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, ipaddr, q); + } + + /* continuation for multicast/broadcast destinations */ + /* obtain source Ethernet address of the given interface */ + /* send packet directly on the link */ + return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out. + * + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + * + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + * to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) +{ + struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; + err_t result = ERR_MEM; + s8_t i; /* ARP entry index */ + + /* non-unicast address? */ + if (ip_addr_isbroadcast(ipaddr, netif) || + ip_addr_ismulticast(ipaddr) || + ip_addr_isany(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + + /* find entry in ARP cache, ask to create entry if queueing packet */ + i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); + + /* could not find or create entry? */ + if (i < 0) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); + if (q) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); + ETHARP_STATS_INC(etharp.memerr); + } + return (err_t)i; + } + + /* mark a fresh entry as pending (we just sent a request) */ + if (arp_table[i].state == ETHARP_STATE_EMPTY) { + arp_table[i].state = ETHARP_STATE_PENDING; + } + + /* { i is either a STABLE or (new or existing) PENDING entry } */ + LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", + ((arp_table[i].state == ETHARP_STATE_PENDING) || + (arp_table[i].state >= ETHARP_STATE_STABLE))); + + /* do we have a pending entry? or an implicit query request? */ + if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { + /* try to resolve it; send out ARP request */ + result = etharp_request(netif, ipaddr); + if (result != ERR_OK) { + /* ARP request couldn't be sent */ + /* We don't re-send arp request in etharp_tmr, but we still queue packets, + since this failure could be temporary, and the next packet calling + etharp_query again could lead to sending the queued packets. */ + } + if (q == NULL) { + return result; + } + } + + /* packet given? */ + LWIP_ASSERT("q != NULL", q != NULL); + /* stable entry? */ + if (arp_table[i].state >= ETHARP_STATE_STABLE) { + /* we have a valid IP->Ethernet address mapping */ + ETHARP_SET_HINT(netif, i); + /* send the packet */ + result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* entry is still pending, queue the given packet 'q' */ + struct pbuf *p; + int copy_needed = 0; + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); + if(p->type != PBUF_ROM) { + copy_needed = 1; + break; + } + p = p->next; + } + if(copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet could be taken over? */ + if (p != NULL) { + /* queue packet ... */ +#if ARP_QUEUEING + struct etharp_q_entry *new_entry; + /* allocate a new arp queue entry */ + new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); + if (new_entry != NULL) { + unsigned int qlen = 0; + new_entry->next = 0; + new_entry->p = p; + if(arp_table[i].q != NULL) { + /* queue was already existent, append the new entry to the end */ + struct etharp_q_entry *r; + r = arp_table[i].q; + qlen++; + while (r->next != NULL) { + r = r->next; + qlen++; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + arp_table[i].q = new_entry; + } + if(qlen >= 3) { + struct etharp_q_entry *old; + old = arp_table[i].q; + arp_table[i].q = arp_table[i].q->next; + pbuf_free(old->p); + memp_free(MEM_ARP_QUEUE, old); + } + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + result = ERR_OK; + } else { + /* the pool MEMP_ARP_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } +#else /* ARP_QUEUEING */ + /* always queue one packet per ARP request only, freeing a previously queued packet */ + if (arp_table[i].q != NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + pbuf_free(arp_table[i].q); + } + arp_table[i].q = p; + result = ERR_OK; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +#endif /* ARP_QUEUEING */ + } else { + ETHARP_STATS_INC(etharp.memerr); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } + } + return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +#if !LWIP_AUTOIP +static +#endif /* LWIP_AUTOIP */ +err_t ICACHE_FLASH_ATTR +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, + const u16_t opcode) +{ + struct pbuf *p; + err_t result = ERR_OK; + struct eth_hdr *ethhdr; + struct etharp_hdr *hdr; +#if LWIP_AUTOIP + const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + + /* allocate a pbuf for the outgoing ARP request packet */ + p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM); + /* could allocate a pbuf for an ARP request? */ + if (p == NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_raw: could not allocate pbuf for ARP request.\n")); + ETHARP_STATS_INC(etharp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", + (p->len >= SIZEOF_ETHARP_PACKET)); + + ethhdr = (struct eth_hdr *)p->payload; + hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); + hdr->opcode = htons(opcode); + + LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", + (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +#if LWIP_AUTOIP + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; +#endif /* LWIP_AUTOIP */ + /* Write the ARP MAC-Addresses */ + ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); + ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); + /* Write the Ethernet MAC-Addresses */ +#if LWIP_AUTOIP + ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); +#else /* LWIP_AUTOIP */ + ETHADDR16_COPY(ðhdr->dest, ethdst_addr); +#endif /* LWIP_AUTOIP */ + ETHADDR16_COPY(ðhdr->src, ethsrc_addr); + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without + * structure packing. */ + IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); + IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); + + hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); + hdr->proto = PP_HTONS(ETHTYPE_IP); + /* set hwlen and protolen */ + hdr->hwlen = ETHARP_HWADDR_LEN; + hdr->protolen = sizeof(ip_addr_t); + + ethhdr->type = PP_HTONS(ETHTYPE_ARP); + /* send ARP query */ + result = netif->linkoutput(netif, p); + ETHARP_STATS_INC(etharp.xmit); + /* free ARP query packet */ + pbuf_free(p); + p = NULL; + /* could not allocate pbuf for ARP request */ + + return result; +} + +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, ip_addr_t *ipaddr) +{ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, + (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, + ipaddr, ARP_REQUEST); +} +#endif /* LWIP_ARP */ + +/** + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access. + * + * @param p the recevied packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + */ +err_t +ethernet_input(struct pbuf *p, struct netif *netif) +{ + struct eth_hdr* ethhdr; + u16_t type; + s16_t ip_hdr_offset = SIZEOF_ETH_HDR; + + if (p->len <= SIZEOF_ETH_HDR) { + /* a packet with only an ethernet header (or less) is not valid for us modify by ives at 2014.4.24*/ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = (struct eth_hdr *)p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", + (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], + (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], + (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], + (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], + (unsigned)htons(ethhdr->type))); + + type = ethhdr->type; +#if ETHARP_SUPPORT_VLAN + if (type == PP_HTONS(ETHTYPE_VLAN)) { + struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); + if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { + /* a packet with only an ethernet/vlan header (or less) is not valid for us modify by ives at 2014.4.24*/ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } +#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ + if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { + /* silently ignore this packet: not for our VLAN */ + pbuf_free(p); + return ERR_OK; + } +#endif /* ETHARP_VLAN_CHECK */ + type = vlan->tpid; + ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; + } +#endif /* ETHARP_SUPPORT_VLAN */ + +#if LWIP_ARP_FILTER_NETIF + netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); +#endif /* LWIP_ARP_FILTER_NETIF*/ + + switch (type) { +#if LWIP_ARP + /* IP packet? */ + case PP_HTONS(ETHTYPE_IP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } +#if ETHARP_TRUST_IP_MAC + /* update ARP table */ + etharp_ip_input(netif, p); +#endif /* ETHARP_TRUST_IP_MAC */ + /* skip Ethernet header */ + if(pbuf_header(p, -ip_hdr_offset)) { + LWIP_ASSERT("Can't move over header in packet", 0); + goto free_and_return; + } else { + /* pass to IP layer */ + ip_input(p, netif); + } + break; + + case PP_HTONS(ETHTYPE_ARP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } + /* pass p to ARP module */ + etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); + break; +#endif /* LWIP_ARP */ +#if PPPOE_SUPPORT + case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ + pppoe_disc_input(netif, p); + break; + + case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ + pppoe_data_input(netif, p); + break; +#endif /* PPPOE_SUPPORT */ + + default: + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } + + /* This means the pbuf is freed or consumed, + so the caller doesn't have to free it again */ + return ERR_OK; + +free_and_return: + pbuf_free(p); + return ERR_OK; +} +#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/make_lib.sh b/Sming/third-party/ESP8266_NONOS_SDK/third_party/make_lib.sh new file mode 100755 index 0000000000..ce7a48ad06 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/make_lib.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +export SDK_PATH=$(dirname $(pwd)) + +echo "make_lib.sh version 20150924" +echo "" + +if [ $SDK_PATH ]; then + echo "SDK_PATH:" + echo "$SDK_PATH" + echo "" +else + echo "ERROR: Please export SDK_PATH in make_lib.sh firstly, exit!!!" + exit +fi + +cd $1 +make clean +make COMPILE=gcc + +# Make sure the lib folder is exist. + +cp .output/eagle/debug/lib/lib$1.a ../../lib/lib$1.a +xtensa-lx106-elf-strip --strip-unneeded ../../lib/lib$1.a +cd .. diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/Makefile new file mode 100644 index 0000000000..dd6399cca2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/Makefile @@ -0,0 +1,49 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +UP_EXTRACT_DIR = .. +GEN_LIBS = libmbedtls.a +COMPONENTS_libmbedtls = library/liblibrary.a platform/libplatform.a app/libapp.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +DEFINES += -DMBEDTLS_CONFIG_FILE='"config_esp.h"' +#CCFLAGS += --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ../$(PDIR)include/lwip/posix +INCLUDES += -I ../$(PDIR)include/mbedtls +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/Makefile new file mode 100644 index 0000000000..4a3dbd16b7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = libapp.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_mbedtls.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_mbedtls.c new file mode 100644 index 0000000000..1f3666d1d9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_mbedtls.c @@ -0,0 +1,1270 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#if !defined(ESPCONN_MBEDTLS) + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/ssl_internal.h" + +#include "mem.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#include "sys/socket.h" +#include "sys/espconn_mbedtls.h" + +static os_event_t lwIPThreadQueue[lwIPThreadQueueLen]; +static bool lwIPThreadFlag = false; +extern espconn_msg *plink_active; +static espconn_msg *plink_server = NULL; +static pmbedtls_parame def_certificate = NULL; +static pmbedtls_parame def_private_key = NULL; + +#if defined(ESP8266_PLATFORM) +#define MBEDTLS_SSL_OUTBUFFER_LEN ( MBEDTLS_SSL_PLAIN_ADD \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ + ) +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static pmbedtls_parame mbedtls_parame_new(size_t capacity) +{ + pmbedtls_parame rb = (pmbedtls_parame)os_zalloc(sizeof(mbedtls_parame)); + if (rb && capacity != 0){ + rb->parame_datalen = capacity; + rb->parame_data = (uint8*)os_zalloc(rb->parame_datalen + 1); + if (rb->parame_data){ + + } else{ + os_free(rb); + rb = NULL; + } + } + return rb; +} + +static void mbedtls_parame_free(pmbedtls_parame *fp) +{ + lwIP_ASSERT(fp); + lwIP_ASSERT(*fp); + + os_free((*fp)->parame_data); + os_free(*fp); + *fp = NULL; +} + +bool mbedtls_load_default_obj(uint32 flash_sector, int obj_type, const unsigned char *load_buf, uint16 length) +{ + pmbedtls_parame mbedtls_write = NULL; + uint32 mbedtls_head = 0; + bool mbedtls_load_flag = false; + + if (flash_sector != 0){ + spi_flash_read(flash_sector * FLASH_SECTOR_SIZE, (uint32*)&mbedtls_head, 4); + if (mbedtls_head != ESPCONN_INVALID_TYPE){ + mbedtls_write = mbedtls_parame_new(0); + mbedtls_write->parame_datalen = length; + } + } else{ + const char* const begin = "-----BEGIN"; + int format_type = ESPCONN_FORMAT_INIT; + /* + * Determine data content. data contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(load_buf, begin) != NULL){ + format_type = ESPCONN_FORMAT_PEM; + }else{ + format_type = ESPCONN_FORMAT_DER; + } + + if (format_type == ESPCONN_FORMAT_PEM){ + length += 1; + } + + mbedtls_write = mbedtls_parame_new(length); + if (mbedtls_write){ + os_memcpy(mbedtls_write->parame_data, load_buf, length); + if (format_type == ESPCONN_FORMAT_PEM) + mbedtls_write->parame_data[length - 1] = '\0'; + } + } + + if (mbedtls_write){ + mbedtls_load_flag = true; + mbedtls_write->parame_type = obj_type; + mbedtls_write->parame_sec = flash_sector; + if (obj_type == ESPCONN_PK){ + def_private_key = mbedtls_write; + } else{ + def_certificate = mbedtls_write; + } + } + return mbedtls_load_flag; +} + +static unsigned char* mbedtls_get_default_obj(uint32 *sec, uint32 type, uint32 *len) +{ + const char* const begin = "-----BEGIN"; + unsigned char *parame_data = NULL; + pmbedtls_parame mbedtls_obj = NULL; + + if (type == ESPCONN_PK){ + mbedtls_obj = def_private_key; + } else{ + mbedtls_obj = def_certificate; + } + + if (mbedtls_obj->parame_sec != 0){ + #define DATA_OFFSET 4 + uint32 data_len = mbedtls_obj->parame_datalen; + parame_data = (unsigned char *)os_zalloc(data_len + DATA_OFFSET); + if (parame_data){ + spi_flash_read(mbedtls_obj->parame_sec * FLASH_SECTOR_SIZE, (uint32*)parame_data, data_len); + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(parame_data, begin) != NULL){ + data_len ++; + parame_data[data_len - 1] = '\0'; + } + } + *len = data_len; + } else{ + parame_data = mbedtls_obj->parame_data; + *len = mbedtls_obj->parame_datalen; + } + + *sec = mbedtls_obj->parame_sec; + return parame_data; +} + +static int mbedtls_setsockopt(int sock_id, int level, int optname, int optval) +{ + return setsockopt(sock_id, level, optname, (void*)&optval, sizeof(optval)); +} + +static int mbedtls_keep_alive(int sock_id, int onoff, int idle, int intvl, int cnt) +{ + int ret = ERR_OK; + if (onoff == 0) + return mbedtls_setsockopt(sock_id, SOL_SOCKET, SO_KEEPALIVE, onoff);; + + ret = mbedtls_setsockopt(sock_id, SOL_SOCKET, SO_KEEPALIVE, onoff); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPALIVE, onoff); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPIDLE, idle); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPINTVL, intvl); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_setsockopt(sock_id, IPPROTO_TCP, TCP_KEEPCNT, cnt); + lwIP_REQUIRE_NOERROR(ret, exit); + +exit: + return ret; +} + +#if defined(ESP8266_PLATFORM) +static pmbedtls_finished mbedtls_finished_new(int len) +{ + pmbedtls_finished finished = (pmbedtls_finished)os_zalloc(sizeof(mbedtls_finished)); + if (finished) + { + finished->finished_len = len; + finished->finished_buf = (uint8*)os_zalloc(finished->finished_len + 1); + if (finished->finished_buf) + { + + } + else + { + os_free(finished); + finished = NULL; + } + } + return finished; +} + +static void mbedtls_finished_free(pmbedtls_finished *pfinished) +{ + lwIP_ASSERT(pfinished); + lwIP_ASSERT(*pfinished); + os_free((*pfinished)->finished_buf); + os_free(*pfinished); + *pfinished = NULL; +} +#endif +static pmbedtls_espconn mbedtls_espconn_new(void) +{ + pmbedtls_espconn mbedtls_conn = NULL; + mbedtls_conn = (pmbedtls_espconn)os_zalloc(sizeof(mbedtls_espconn)); + if (mbedtls_conn){ + mbedtls_conn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + if (mbedtls_conn->proto.tcp == NULL){ + os_free(mbedtls_conn); + mbedtls_conn = NULL; + } + } + + return mbedtls_conn; +} + +static void mbedtls_espconn_free(pmbedtls_espconn *mbedtlsconn) +{ + lwIP_ASSERT(mbedtlsconn); + lwIP_ASSERT(*mbedtlsconn); + + os_free((*mbedtlsconn)->proto.tcp); + (*mbedtlsconn)->proto.tcp = NULL; + + os_free((*mbedtlsconn)); + *mbedtlsconn = NULL; +} + +static pmbedtls_session mbedtls_session_new(void) +{ + pmbedtls_session session = (pmbedtls_session)os_zalloc(sizeof(mbedtls_session)); + if (session){ + mbedtls_x509_crt_init(&session->cacert); + mbedtls_x509_crt_init(&session->clicert); + mbedtls_pk_init(&session->pkey); +// mbedtls_entropy_init(&session->entropy); + } + return session; +} + +static void mbedtls_session_free(pmbedtls_session *session) +{ + lwIP_ASSERT(session); + lwIP_ASSERT(*session); + + mbedtls_x509_crt_free(&(*session)->cacert); + mbedtls_x509_crt_free(&(*session)->clicert); + mbedtls_pk_free(&(*session)->pkey); +// mbedtls_entropy_free(&(*session)->entropy); + os_free(*session); + *session = NULL; +} + +static pmbedtls_msg mbedtls_msg_new(void) +{ + pmbedtls_msg msg = (pmbedtls_msg)os_zalloc( sizeof(mbedtls_msg)); + if (msg) { + os_bzero(msg, sizeof(mbedtls_msg)); + msg->psession = mbedtls_session_new(); + if (msg->psession){ + mbedtls_net_init(&msg->listen_fd); + mbedtls_net_init(&msg->fd); + mbedtls_ssl_init(&msg->ssl); + mbedtls_ssl_config_init(&msg->conf); + mbedtls_ctr_drbg_init(&msg->ctr_drbg); + mbedtls_entropy_init(&msg->entropy); + } else{ + os_free(msg); + msg = NULL; + } + } + return msg; +} + +static void mbedtls_msg_server_step(pmbedtls_msg msg) +{ + lwIP_ASSERT(msg); + + /*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/ + if (msg->psession){ + mbedtls_session_free(&msg->psession); + } +#if defined(ESP8266_PLATFORM) + if (msg->quiet && msg->ssl.out_buf) + { + mbedtls_zeroize(msg->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN); + os_free(msg->ssl.out_buf); + msg->ssl.out_buf = NULL; + } +#endif + mbedtls_entropy_free(&msg->entropy); + mbedtls_ssl_free(&msg->ssl); + mbedtls_ssl_config_free(&msg->conf); + mbedtls_ctr_drbg_free(&msg->ctr_drbg); + + /*New connection ensure that each initial for next handshake */ + os_bzero(msg, sizeof(mbedtls_msg)); + msg->psession = mbedtls_session_new(); + if (msg->psession){ + mbedtls_net_init(&msg->fd); + mbedtls_ssl_init(&msg->ssl); + mbedtls_ssl_config_init(&msg->conf); + mbedtls_ctr_drbg_init(&msg->ctr_drbg); + mbedtls_entropy_init(&msg->entropy); + } +} + +static void mbedtls_msg_free(pmbedtls_msg *msg) +{ + lwIP_ASSERT(msg); + lwIP_ASSERT(*msg); + + /*to prevent memory leaks, ensure that each allocated is deleted at every handshake*/ + if ((*msg)->psession){ + mbedtls_session_free(&((*msg)->psession)); + } +#if defined(ESP8266_PLATFORM) + if ((*msg)->quiet && (*msg)->ssl.out_buf) + { + mbedtls_zeroize((*msg)->ssl.out_buf, MBEDTLS_SSL_OUTBUFFER_LEN); + os_free((*msg)->ssl.out_buf); + (*msg)->ssl.out_buf = NULL; + } +#endif + mbedtls_entropy_free(&(*msg)->entropy); + mbedtls_ssl_free(&(*msg)->ssl); + mbedtls_ssl_config_free(&(*msg)->conf); + mbedtls_ctr_drbg_free(&(*msg)->ctr_drbg); + + os_free(*msg); + *msg = NULL; +} + +static espconn_msg* mbedtls_msg_find(int sock) +{ + espconn_msg *plist = NULL; + pmbedtls_msg msg = NULL; + + for (plist = plink_active; plist != NULL; plist = plist->pnext) { + if(plist->pssl != NULL){ + msg = plist->pssl; + if (msg->fd.fd == sock) + return plist; + } + } + + for (plist = plink_server; plist != NULL; plist = plist->pnext){ + if(plist->pssl != NULL){ + msg = plist->pssl; + if (msg->listen_fd.fd == sock) + return plist; + } + } + return NULL; +} + +void mbedtls_handshake_heap(mbedtls_ssl_context *ssl) +{ + os_printf("mbedtls_handshake_heap %d %d\n", ssl->state, system_get_free_heap_size()); +} + +static bool mbedtls_handshake_result(const pmbedtls_msg Threadmsg) +{ + if (Threadmsg == NULL) + return false; + + if (Threadmsg->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { + int ret = 0; + if (Threadmsg->listen_fd.fd == -1) + ret = ssl_option.client.cert_ca_sector.flag; + else + ret = ssl_option.server.cert_ca_sector.flag; + + if (ret == 1){ + ret = mbedtls_ssl_get_verify_result(&Threadmsg->ssl); + if (ret != 0) { + char vrfy_buf[512]; + os_memset(vrfy_buf, 0, sizeof(vrfy_buf)-1); + mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "!", ret); + os_printf("%s\n", vrfy_buf); + Threadmsg->verify_result = ret; + return false; + } else + return true; + } else + return true; + }else + return false; +} + +static void mbedtls_fail_info(espconn_msg *pinfo, int ret) +{ + pmbedtls_msg TLSmsg = NULL; + lwIP_REQUIRE_ACTION(pinfo,exit,ret = ERR_ARG); + TLSmsg = pinfo->pssl; + lwIP_REQUIRE_ACTION(TLSmsg,exit,ret = ERR_ARG); + + if (TLSmsg->quiet){ + if (pinfo->preverse != NULL) { + os_printf("server's data invalid protocol\n"); + } else { + os_printf("client's data invalid protocol\n"); + } + mbedtls_ssl_close_notify(&TLSmsg->ssl); + } else{ + if (pinfo->preverse != NULL) { + os_printf("server handshake failed!\n"); + } else { + os_printf("client handshake failed!\n"); + } + } + + os_printf("Reason:[-0x%2x]\n",-ret); + /*Error code convert*/ + ret = -ret; + if ((ret & 0xFF) != 0){ + ret = ((ret >> 8) + ret); + } else{ + ret >>= 8; + } + pinfo->hs_status = -ret; + pinfo->pespconn->state = ESPCONN_CLOSE; + + mbedtls_net_free(&TLSmsg->fd); + +exit: + return; +} + +#if defined(ESP8266_PLATFORM) +int mbedtls_write_finished(mbedtls_ssl_context *ssl) +{ + lwIP_ASSERT(ssl); + lwIP_ASSERT(ssl->p_bio); + int ret = ERR_OK; + int fd = ((mbedtls_net_context *) ssl->p_bio)->fd; + espconn_msg *Threadmsg = mbedtls_msg_find(fd); + lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM); + pmbedtls_msg TLSmsg = Threadmsg->pssl; + lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); + TLSmsg->pfinished = mbedtls_finished_new(ssl->out_msglen + 29); + lwIP_REQUIRE_ACTION(TLSmsg->pfinished, exit, ret = ERR_MEM); + os_memcpy(TLSmsg->pfinished->finished_buf, ssl->out_ctr, TLSmsg->pfinished->finished_len); +exit: + return ret; +} + +static int mbedtls_hanshake_finished(mbedtls_msg *msg) +{ + lwIP_ASSERT(msg); + int ret = ERR_OK; + const size_t len = MBEDTLS_SSL_OUTBUFFER_LEN; + + mbedtls_ssl_context *ssl = &msg->ssl; + lwIP_REQUIRE_ACTION(ssl, exit, ret = ERR_MEM); + + pmbedtls_finished finished = msg->pfinished; + lwIP_REQUIRE_ACTION(finished, exit, ret = ERR_MEM); + + ssl->out_buf = (unsigned char*)os_zalloc(len); + lwIP_REQUIRE_ACTION(ssl->out_buf, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); + + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 29; + os_memcpy(ssl->out_ctr, finished->finished_buf, finished->finished_len); + mbedtls_finished_free(&msg->pfinished); + +exit: + return ret; +} +#endif +static void mbedtls_handshake_succ(mbedtls_ssl_context *ssl) +{ + lwIP_ASSERT(ssl); + if( ssl->handshake ) + { + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + os_free( ssl->handshake ); + os_free( ssl->transform_negotiate ); + os_free( ssl->session_negotiate ); + ssl->handshake = NULL; + ssl->transform_negotiate = NULL; + ssl->session_negotiate = NULL; + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + os_free( ssl->session ); + ssl->session = NULL; + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ssl->hostname != NULL ) + { + mbedtls_zeroize( ssl->hostname, os_strlen( ssl->hostname ) ); + os_free( ssl->hostname ); + ssl->hostname = NULL; + } +#endif +} + +/****************************************************************************** + * FunctionName : espconn_ssl_reconnect + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +static void espconn_close_internal(void *arg, netconn_event event_type) +{ + espconn_msg *pssl_recon = arg; + struct espconn *espconn = NULL; + sint8 ssl_reerr = 0; + sint16 hs_status = 0; + lwIP_ASSERT(pssl_recon); + + espconn = pssl_recon->preverse; + ssl_reerr = pssl_recon->pcommon.err; + hs_status = pssl_recon->hs_status; + if (espconn != NULL) { + espconn = pssl_recon->preverse; + } else { + espconn = pssl_recon->pespconn; + os_free(pssl_recon); + pssl_recon = NULL; + } + + espconn_kill_oldest_pcb(); + switch (event_type){ + case NETCONN_EVENT_ERROR: + if (hs_status == ESPCONN_OK) + ESPCONN_EVENT_ERROR(espconn, ssl_reerr); + else + ESPCONN_EVENT_ERROR(espconn, hs_status); + break; + case NETCONN_EVENT_CLOSE: + if (hs_status == ESPCONN_OK) + ESPCONN_EVENT_CLOSED(espconn); + else + ESPCONN_EVENT_ERROR(espconn, hs_status); + break; + default: + break; + } +} + +/****************************************************************************** + * FunctionName : espconn_ssl_read_param_from_flash + * Description : load parameter from flash, toggle use two sector by flag value. + * Parameters : param--the parame point which write the flash + * Returns : none +*******************************************************************************/ +static bool espconn_ssl_read_param_from_flash(void *param, uint16 len, int32 offset, mbedtls_auth_info *auth_info) +{ + if (param == NULL || (len + offset) > ESPCONN_SECURE_MAX_SIZE) { + return false; + } + + uint32 FILE_PARAM_START_SEC = 0x3B; + switch (auth_info->auth_level) { + case ESPCONN_CLIENT: + switch (auth_info->auth_type) { + case ESPCONN_CERT_AUTH: + FILE_PARAM_START_SEC = ssl_option.client.cert_ca_sector.sector; + break; + case ESPCONN_CERT_OWN: + case ESPCONN_PK: + FILE_PARAM_START_SEC = ssl_option.client.cert_req_sector.sector; + break; + default: + return false; + } + break; + case ESPCONN_SERVER: + switch (auth_info->auth_type) { + case ESPCONN_CERT_AUTH: + FILE_PARAM_START_SEC = ssl_option.server.cert_ca_sector.sector; + break; + case ESPCONN_CERT_OWN: + case ESPCONN_PK: + FILE_PARAM_START_SEC = ssl_option.server.cert_req_sector.sector; + break; + default: + return false; + } + break; + default: + return false; + break; + } + + spi_flash_read(FILE_PARAM_START_SEC * 4096 + offset, param, len); + + return true; +} + +static bool mbedtls_msg_info_load(mbedtls_msg *msg, mbedtls_auth_info *auth_info) +{ + const char* const begin = "-----BEGIN"; + const char* const type_name = "private_key"; + #define FILE_OFFSET 4 + int ret = 0; + int32 offerset = 0; + uint8* load_buf = NULL; + size_t load_len = 0; + file_param *pfile_param = NULL; + pfile_param = (file_param *)os_zalloc( sizeof(file_param)); + if (pfile_param==NULL) + return false; + +again: + espconn_ssl_read_param_from_flash(&pfile_param->file_head, sizeof(file_head), offerset, auth_info); + pfile_param->file_offerset = offerset; + os_printf("%s %d, type[%s],length[%d]\n", __FILE__, __LINE__, pfile_param->file_head.file_name, pfile_param->file_head.file_length); + if (pfile_param->file_head.file_length == 0xFFFF){ + os_free(pfile_param); + return false; + } else{ + /*Optional is load the private key*/ + if (auth_info->auth_type == ESPCONN_PK && os_memcmp(pfile_param->file_head.file_name, type_name, os_strlen(type_name)) != 0){ + offerset += sizeof(file_head) + pfile_param->file_head.file_length; + goto again; + } + load_buf = (uint8_t *) os_zalloc( pfile_param->file_head.file_length + FILE_OFFSET); + if (load_buf == NULL){ + os_free(pfile_param); + return false; + } + offerset = sizeof(file_head) + pfile_param->file_offerset; + espconn_ssl_read_param_from_flash(load_buf, pfile_param->file_head.file_length, offerset, auth_info); + } + + load_len = pfile_param->file_head.file_length; + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ + if ((char*)os_strstr(load_buf, begin) != NULL){ + load_len += 1; + load_buf[load_len - 1] = '\0'; + } + switch (auth_info->auth_type){ + case ESPCONN_CERT_AUTH: + /*Optional is not optimal for security*/ + ret = mbedtls_x509_crt_parse(&msg->psession->cacert, (const uint8*) load_buf,load_len); + lwIP_REQUIRE_NOERROR(ret, exit); + mbedtls_ssl_conf_authmode(&msg->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&msg->conf, &msg->psession->cacert, NULL); + break; + case ESPCONN_CERT_OWN: + ret = mbedtls_x509_crt_parse(&msg->psession->clicert, (const uint8*) load_buf,load_len); + break; + case ESPCONN_PK: + ret = mbedtls_pk_parse_key(&msg->psession->pkey, (const uint8*) load_buf,load_len, NULL, 0); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_ssl_conf_own_cert(&msg->conf, &msg->psession->clicert, &msg->psession->pkey); + break; + } +exit: + os_free(load_buf); + os_free(pfile_param); + if (ret < 0){ + return false; + }else{ + return true; + } +} + +static bool mbedtls_msg_config(mbedtls_msg *msg) +{ + const char *pers = NULL; + uint8 auth_type = 0; + bool load_flag = false; + int ret = ESPCONN_OK; + mbedtls_auth_info auth_info; + + /*end_point mode*/ + if (msg->listen_fd.fd == -1){ + pers = "client"; + auth_type = MBEDTLS_SSL_IS_CLIENT; + } else { + pers = "server"; + auth_type = MBEDTLS_SSL_IS_SERVER; + } + + /*Initialize the RNG and the session data*/ + ret = mbedtls_ctr_drbg_seed(&msg->ctr_drbg, mbedtls_entropy_func, &msg->entropy, (const unsigned char*) pers, os_strlen(pers)); + lwIP_REQUIRE_NOERROR(ret, exit); + + if (auth_type == MBEDTLS_SSL_IS_SERVER){ + uint32 flash_sector = 0; + /*Load the certificate*/ + unsigned int def_certificate_len = 0;unsigned char *def_certificate = NULL; + def_certificate = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_CERT_OWN, &def_certificate_len); + lwIP_REQUIRE_ACTION(def_certificate, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); + ret = mbedtls_x509_crt_parse(&msg->psession->clicert, (const unsigned char *)def_certificate, def_certificate_len); + if (flash_sector != 0) + os_free(def_certificate); + lwIP_REQUIRE_NOERROR(ret, exit); + + /*Load the private RSA key*/ + unsigned int def_private_key_len = 0;unsigned char *def_private_key = NULL; + def_private_key = (unsigned char *)mbedtls_get_default_obj(&flash_sector,ESPCONN_PK, &def_private_key_len); + lwIP_REQUIRE_ACTION(def_private_key, exit, ret = MBEDTLS_ERR_SSL_ALLOC_FAILED); + ret = mbedtls_pk_parse_key(&msg->psession->pkey, (const unsigned char *)def_private_key, def_private_key_len, NULL, 0); + if (flash_sector != 0) + os_free(def_private_key); + lwIP_REQUIRE_NOERROR(ret, exit); + ret = mbedtls_ssl_conf_own_cert(&msg->conf, &msg->psession->clicert, &msg->psession->pkey); + lwIP_REQUIRE_NOERROR(ret, exit); + + /*Load the trusted CA*/ + if (ssl_option.server.cert_ca_sector.flag) { + auth_info.auth_level = ESPCONN_SERVER; + auth_info.auth_type = ESPCONN_CERT_AUTH; + load_flag = mbedtls_msg_info_load(msg, &auth_info); + lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM); + } + } else{ + /*Load the certificate and private RSA key*/ + if (ssl_option.client.cert_req_sector.flag) { + auth_info.auth_level = ESPCONN_CLIENT; + auth_info.auth_type = ESPCONN_CERT_OWN; + load_flag = mbedtls_msg_info_load(msg, &auth_info); + lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM); + auth_info.auth_type = ESPCONN_PK; + load_flag = mbedtls_msg_info_load(msg, &auth_info); + lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM); + } + + /*Load the trusted CA*/ + if(ssl_option.client.cert_ca_sector.flag){ + auth_info.auth_level = ESPCONN_CLIENT; + auth_info.auth_type = ESPCONN_CERT_AUTH; + load_flag = mbedtls_msg_info_load(msg, &auth_info); + lwIP_REQUIRE_ACTION(load_flag, exit, ret = ESPCONN_MEM); + } + } + + /*Setup the stuff*/ + ret = mbedtls_ssl_config_defaults(&msg->conf, auth_type, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + lwIP_REQUIRE_NOERROR(ret, exit); + + /*OPTIONAL is not optimal for security, but makes interop easier in this session*/ + if (auth_type == MBEDTLS_SSL_IS_CLIENT && ssl_option.client.cert_ca_sector.flag == false){ + mbedtls_ssl_conf_authmode(&msg->conf, MBEDTLS_SSL_VERIFY_NONE); + } + mbedtls_ssl_conf_rng(&msg->conf, mbedtls_ctr_drbg_random, &msg->ctr_drbg); + mbedtls_ssl_conf_dbg(&msg->conf, NULL, NULL); + + ret = mbedtls_ssl_setup(&msg->ssl, &msg->conf); + lwIP_REQUIRE_NOERROR(ret, exit); + + mbedtls_ssl_set_bio(&msg->ssl, &msg->fd, mbedtls_net_send, mbedtls_net_recv, NULL); + +exit: + if (ret != 0){ + return false; + } else{ + return true; + } +} + +int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error) +{ + int ret = ERR_OK; + bool config_flag = false; + espconn_msg *Threadmsg = NULL; + pmbedtls_msg TLSmsg = NULL; + Threadmsg = mbedtls_msg_find(socket); + lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM); + TLSmsg = Threadmsg->pssl; + lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); + + if (error == ERR_OK){ + if (TLSmsg->quiet){ + uint8 *TheadBuff = NULL; + size_t ThreadLen = MBEDTLS_SSL_PLAIN_ADD; + TheadBuff = (uint8 *)os_zalloc(ThreadLen + 1); + lwIP_REQUIRE_ACTION(TheadBuff, exit, ret = ERR_MEM); + do { + os_memset(TheadBuff, 0, ThreadLen); + ret = mbedtls_ssl_read(&TLSmsg->ssl, TheadBuff, ThreadLen); + if (ret > 0){ + ESPCONN_EVENT_RECV(Threadmsg->pespconn, TheadBuff, ret); + } else{ + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == 0){ + ret = ESPCONN_OK; + break; + } else{ + break; + } + } + } while(1); + os_free(TheadBuff); + TheadBuff = NULL; + lwIP_REQUIRE_NOERROR(ret, exit); + } else{ + if (TLSmsg->ssl.state == MBEDTLS_SSL_HELLO_REQUEST){ + if (Threadmsg->preverse != NULL){ + struct espconn *accept_conn = NULL; + struct espconn *espconn = Threadmsg->preverse; + struct sockaddr_in name; + socklen_t name_len = sizeof(name); + remot_info *pinfo = NULL; + espconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL); + if (espconn->link_cnt == 0x01) + return ERR_ISCONN; + + ret = mbedtls_net_accept(&TLSmsg->listen_fd, &TLSmsg->fd, NULL, 0, NULL); + lwIP_REQUIRE_NOERROR(ret, exit); + accept_conn = mbedtls_espconn_new(); + lwIP_REQUIRE_ACTION(accept_conn, exit, ret = ERR_MEM); + Threadmsg->pespconn = accept_conn; + /*get the remote information*/ + getpeername(TLSmsg->fd.fd, (struct sockaddr*)&name, &name_len); + Threadmsg->pcommon.remote_port = htons(name.sin_port); + os_memcpy(Threadmsg->pcommon.remote_ip, &name.sin_addr.s_addr, 4); + + espconn->proto.tcp->remote_port = htons(name.sin_port); + os_memcpy(espconn->proto.tcp->remote_ip, &name.sin_addr.s_addr, 4); + + espconn_copy_partial(accept_conn, espconn); + + /*insert the node to the active connection list*/ + espconn_list_creat(&plink_active, Threadmsg); + os_printf("server handshake start.\n"); + } else{ + os_printf("client handshake start.\n"); + } + config_flag = mbedtls_msg_config(TLSmsg); + if (config_flag){ +// mbedtls_keep_alive(TLSmsg->fd.fd, 1, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT); + system_overclock(); + } else{ + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + lwIP_REQUIRE_NOERROR(ret, exit); + } + } + + system_soft_wdt_stop(); + while ((ret = mbedtls_ssl_handshake(&TLSmsg->ssl)) != 0) { + + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + ret = ESPCONN_OK; + break; + } else{ + break; + } + } + system_soft_wdt_restart(); + lwIP_REQUIRE_NOERROR(ret, exit); + /**/ + TLSmsg->quiet = mbedtls_handshake_result(TLSmsg); + if (TLSmsg->quiet){ + if (Threadmsg->preverse != NULL) { + os_printf("server handshake ok!\n"); + } else { + os_printf("client handshake ok!\n"); + } +// mbedtls_keep_alive(TLSmsg->fd.fd, 0, SSL_KEEP_IDLE, SSL_KEEP_INTVL, SSL_KEEP_CNT); + mbedtls_session_free(&TLSmsg->psession); + mbedtls_handshake_succ(&TLSmsg->ssl); +#if defined(ESP8266_PLATFORM) + mbedtls_hanshake_finished(TLSmsg); +#endif + system_restoreclock(); + + TLSmsg->SentFnFlag = true; + ESPCONN_EVENT_CONNECTED(Threadmsg->pespconn); + } else{ + lwIP_REQUIRE_NOERROR_ACTION(TLSmsg->verify_result, exit, ret = TLSmsg->verify_result); + } + } + } else if (error < 0){ + Threadmsg->pcommon.err = error; + Threadmsg->pespconn->state = ESPCONN_CLOSE; + mbedtls_net_free(&TLSmsg->fd); + ets_post(lwIPThreadPrio, NETCONN_EVENT_ERROR, (uint32)Threadmsg); + } else { + ret = MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY; + lwIP_REQUIRE_NOERROR(ret, exit); + } + +exit: + if (ret != ESPCONN_OK){ + mbedtls_fail_info(Threadmsg, ret); + ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg); + } + return ret; +} + +int __attribute__((weak)) mbedtls_parse_thread(int socket, int event, int error) +{ + int ret = ERR_OK; + espconn_msg *Threadmsg = NULL; + pmbedtls_msg TLSmsg = NULL; + Threadmsg = mbedtls_msg_find(socket); + lwIP_REQUIRE_ACTION(Threadmsg, exit, ret = ERR_MEM); + TLSmsg = Threadmsg->pssl; + lwIP_REQUIRE_ACTION(TLSmsg, exit, ret = ERR_MEM); + if (TLSmsg->quiet){ + int out_msglen = TLSmsg->ssl.out_msglen + 5; + if (Threadmsg->pcommon.write_flag) + TLSmsg->record.record_len += error; + + if (TLSmsg->record.record_len == out_msglen){ + TLSmsg->record.record_len = 0; + Threadmsg->pcommon.write_flag = false; + if (Threadmsg->pcommon.cntr != 0){ + espconn_ssl_sent(Threadmsg, Threadmsg->pcommon.ptrbuf, Threadmsg->pcommon.cntr); + } else{ + TLSmsg->SentFnFlag = true; + ESPCONN_EVENT_SEND(Threadmsg->pespconn); + } + } else{ + + } + } else{ + + } +exit: + return ret; +} + +/** + * @brief Api_Thread. + * @param events: contain the Api_Thread processing data + * @retval None + */ +static void +mbedtls_thread(os_event_t *events) +{ + int ret = ESP_OK; + bool active_flag = false; + espconn_msg *Threadmsg = NULL; + espconn_msg *ListMsg = NULL; + pmbedtls_msg TLSmsg = NULL; + Threadmsg = (espconn_msg *)events->par; + lwIP_REQUIRE_ACTION(Threadmsg,exit,ret = ERR_ARG); + TLSmsg = Threadmsg->pssl; + lwIP_REQUIRE_ACTION(TLSmsg,exit,ret = ERR_ARG); + lwIP_REQUIRE_ACTION(Threadmsg->pespconn,exit,ret = ERR_ARG); + + /*find the active connection*/ + for (ListMsg = plink_active; ListMsg != NULL; ListMsg = ListMsg->pnext){ + if (Threadmsg == ListMsg){ + active_flag = true; + break; + } + } + + if (active_flag){ + /*remove the node from the active connection list*/ + espconn_list_delete(&plink_active, Threadmsg); + if (TLSmsg->listen_fd.fd != -1){ + mbedtls_msg_server_step(TLSmsg); + espconn_copy_partial(Threadmsg->preverse, Threadmsg->pespconn); + mbedtls_espconn_free(&Threadmsg->pespconn); + } else{ + mbedtls_msg_free(&TLSmsg); + Threadmsg->pssl = NULL; + } + + switch (events->sig){ + case NETCONN_EVENT_ERROR: + espconn_close_internal(Threadmsg, NETCONN_EVENT_ERROR); + break; + case NETCONN_EVENT_CLOSE: + espconn_close_internal(Threadmsg, NETCONN_EVENT_CLOSE); + break; + default: + break; + } + } +exit: + return; +} + +static void mbedtls_threadinit(void) +{ + ets_task(mbedtls_thread, lwIPThreadPrio, lwIPThreadQueue, lwIPThreadQueueLen); + lwIPThreadFlag = true; +} + +sint8 espconn_ssl_client(struct espconn *espconn) +{ + int ret = ESPCONN_OK; + struct ip_addr ipaddr; + const char *server_name = NULL; + const char *server_port = NULL; + espconn_msg *pclient = NULL; + pmbedtls_msg mbedTLSMsg = NULL; + if (lwIPThreadFlag == false) + mbedtls_threadinit(); + + lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_ARG); + pclient = (espconn_msg *)os_zalloc( sizeof(espconn_msg)); + lwIP_REQUIRE_ACTION(pclient, exit, ret = ESPCONN_MEM); + mbedTLSMsg = mbedtls_msg_new(); + lwIP_REQUIRE_ACTION(mbedTLSMsg, exit, ret = ESPCONN_MEM); + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2],espconn->proto.tcp->remote_ip[3]); + server_name = ipaddr_ntoa(&ipaddr); + server_port = (const char *)sys_itoa(espconn->proto.tcp->remote_port); + + /*start the connection*/ + ret = mbedtls_net_connect(&mbedTLSMsg->fd, server_name, server_port, MBEDTLS_NET_PROTO_TCP); + lwIP_REQUIRE_NOERROR_ACTION(ret, exit, ret = ESPCONN_MEM); + espconn->state = ESPCONN_WAIT; + pclient->pespconn = espconn; + pclient->pssl = mbedTLSMsg; + pclient->preverse = NULL; + /*insert the node to the active connection list*/ + espconn_list_creat(&plink_active, pclient); +exit: + if (ret != ESPCONN_OK){ + if (mbedTLSMsg != NULL) + mbedtls_msg_free(&mbedTLSMsg); + if (pclient != NULL) + os_free(pclient); + } + return ret; +} + +/****************************************************************************** + * FunctionName : espconn_ssl_server + * Description : as + * Parameters : + * Returns : +*******************************************************************************/ +sint8 espconn_ssl_server(struct espconn *espconn) +{ + int ret = ESPCONN_OK; + struct ip_addr ipaddr; + + const char *server_port = NULL; + espconn_msg *pserver = NULL; + pmbedtls_msg mbedTLSMsg = NULL; + if (lwIPThreadFlag == false) + mbedtls_threadinit(); + + if (plink_server != NULL) + return ESPCONN_INPROGRESS; + + lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_ARG); + /*Creates a new server control message*/ + pserver = (espconn_msg *) os_zalloc( sizeof(espconn_msg)); + lwIP_REQUIRE_ACTION(espconn, exit, ret = ESPCONN_MEM); + mbedTLSMsg = mbedtls_msg_new(); + lwIP_REQUIRE_ACTION(mbedTLSMsg, exit, ret = ESPCONN_MEM); + + server_port = (const char *)sys_itoa(espconn->proto.tcp->local_port); + /*start the connection*/ + ret = mbedtls_net_bind(&mbedTLSMsg->listen_fd, NULL, server_port, MBEDTLS_NET_PROTO_TCP); + lwIP_REQUIRE_NOERROR_ACTION(ret, exit, ret = ESPCONN_MEM); + espconn->state = ESPCONN_LISTEN; + pserver->pespconn = NULL; + pserver->pssl = mbedTLSMsg; + pserver->preverse = espconn; + pserver->count_opt = MEMP_NUM_TCP_PCB; + pserver->pcommon.timeout = 0x0a; + espconn->state = ESPCONN_LISTEN; + plink_server = pserver; +exit: + if (ret != ESPCONN_OK) { + if (mbedTLSMsg != NULL) + mbedtls_msg_free(&mbedTLSMsg); + if (pserver != NULL) + os_free(pserver); + } + return ret; +} + +/****************************************************************************** + * FunctionName : espconn_ssl_delete + * Description : delete the server: delete a listening PCB and free it + * Parameters : pdeletecon -- the espconn used to delete a server + * Returns : none +*******************************************************************************/ +sint8 espconn_ssl_delete(struct espconn *pdeletecon) +{ + remot_info *pinfo = NULL; + espconn_msg *pdelete_msg = NULL; + pmbedtls_msg mbedTLSMsg = NULL; + + if (pdeletecon == NULL) + return ESPCONN_ARG; + + espconn_get_connection_info(pdeletecon, &pinfo, ESPCONN_SSL); + /*make sure all the active connection have been disconnect*/ + if (pdeletecon->link_cnt != 0) + return ESPCONN_INPROGRESS; + else { + pdelete_msg = plink_server; + if (pdelete_msg != NULL && pdelete_msg->preverse == pdeletecon) { + mbedTLSMsg = pdelete_msg->pssl; + espconn_kill_pcb(pdeletecon->proto.tcp->local_port); + mbedtls_net_free(&mbedTLSMsg->listen_fd); + mbedtls_msg_free(&mbedTLSMsg); + pdelete_msg->pssl = mbedTLSMsg; + os_free(pdelete_msg); + pdelete_msg = NULL; + plink_server = pdelete_msg; + mbedtls_parame_free(&def_private_key); + mbedtls_parame_free(&def_certificate); + return ESPCONN_OK; + } else { + return ESPCONN_ARG; + } + } +} + +/****************************************************************************** + * FunctionName : espconn_ssl_write + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ +void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length) +{ + espconn_msg *Threadmsg = arg; + uint16 out_msglen = length; + int ret = ESPCONN_OK; + lwIP_ASSERT(Threadmsg); + lwIP_ASSERT(psent); + lwIP_ASSERT(length); + pmbedtls_msg mbedTLSMsg = Threadmsg->pssl; + lwIP_ASSERT(mbedTLSMsg); + + if (length > MBEDTLS_SSL_PLAIN_ADD){ + out_msglen = MBEDTLS_SSL_PLAIN_ADD; + } + + Threadmsg->pcommon.write_flag = true; + ret = mbedtls_ssl_write(&mbedTLSMsg->ssl, psent, out_msglen); + if (ret > 0){ + Threadmsg->pcommon.ptrbuf = psent + ret; + Threadmsg->pcommon.cntr = length - ret; + } else{ + if (ret == MBEDTLS_ERR_SSL_WANT_WRITE || ret == 0) { + + } else{ + mbedtls_fail_info(Threadmsg, ret); + ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE,(uint32)Threadmsg); + } + } + +} + +/****************************************************************************** + * FunctionName : espconn_ssl_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ +void espconn_ssl_disconnect(espconn_msg *Threadmsg) +{ + lwIP_ASSERT(Threadmsg); + pmbedtls_msg mbedTLSMsg = Threadmsg->pssl; + lwIP_ASSERT(mbedTLSMsg); + mbedtls_net_free(&mbedTLSMsg->fd); + Threadmsg->pespconn->state = ESPCONN_CLOSE; + ets_post(lwIPThreadPrio, NETCONN_EVENT_CLOSE, (uint32)Threadmsg); +} + +/* + * Checkup routine + */ +int mbedtls_x509_test(int verbose, char *ca_crt, size_t ca_crt_len, char *cli_crt, size_t cli_crt_len) +{ +#if defined(MBEDTLS_SHA1_C) + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + os_printf( " X.509 certificate load: " ); + + mbedtls_x509_crt_init( &clicert ); + + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) cli_crt, + cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); + + return( ret ); + } + + mbedtls_x509_crt_init( &cacert ); + + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) ca_crt, + ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + os_printf( "passed\n X.509 signature verify: "); + + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + os_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + os_printf( "passed\n\n"); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); + + return( 0 ); +#else + ((void) verbose); + return( 0 ); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ +} + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_secure.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_secure.c new file mode 100644 index 0000000000..a7ebe15518 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/espconn_secure.c @@ -0,0 +1,397 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "ets_sys.h" +#include "os_type.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +#if !defined(ESPCONN_MBEDTLS) + +#include "sys/espconn_mbedtls.h" + +ssl_opt ssl_option = { + {NULL, ESPCONN_SECURE_DEFAULT_SIZE, 0, false, 0, false}, + {NULL, ESPCONN_SECURE_DEFAULT_SIZE, 0, false, 0, false}, + 0 +}; + +unsigned int max_content_len = ESPCONN_SECURE_DEFAULT_SIZE; +/****************************************************************************** + * FunctionName : espconn_encry_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_secure_connect(struct espconn *espconn) +{ + struct ip_addr ipaddr; + struct ip_info ipinfo; + uint8 connect_status = 0; + uint16 current_size = 0; + if (espconn == NULL || espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + if (wifi_get_opmode() == ESPCONN_STA){ + wifi_get_ip_info(STA_NETIF, &ipinfo); + if (ipinfo.ip.addr == 0) { + return ESPCONN_RTE; + } + } else if (wifi_get_opmode() == ESPCONN_AP) { + wifi_get_ip_info(AP_NETIF, &ipinfo); + if (ipinfo.ip.addr == 0) { + return ESPCONN_RTE; + } + } else if (wifi_get_opmode() == ESPCONN_AP_STA) { + IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0], + espconn->proto.tcp->remote_ip[1], + espconn->proto.tcp->remote_ip[2], + espconn->proto.tcp->remote_ip[3]); + ipaddr.addr <<= 8; + wifi_get_ip_info(AP_NETIF, &ipinfo); + ipinfo.ip.addr <<= 8; + espconn_printf("softap_addr = %x, remote_addr = %x\n", ipinfo.ip.addr, ipaddr.addr); + + if (ipaddr.addr != ipinfo.ip.addr) { + connect_status = wifi_station_get_connect_status(); + if (connect_status == STATION_GOT_IP) { + wifi_get_ip_info(STA_NETIF, &ipinfo); + if (ipinfo.ip.addr == 0) + return ESPCONN_RTE; + } else if (connect_status == STATION_IDLE) { + return ESPCONN_RTE; + } else { + return connect_status; + } + } + } + current_size = espconn_secure_get_size(ESPCONN_CLIENT); + current_size += ESPCONN_SECURE_DEFAULT_HEAP; +// ssl_printf("heap_size %d %d\n", system_get_free_heap_size(), current_size); + if (system_get_free_heap_size() <= current_size) + return ESPCONN_MEM; + + return espconn_ssl_client(espconn); +} + +/****************************************************************************** + * FunctionName : espconn_encry_disconnect + * Description : The function given as the disconnect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_secure_disconnect(struct espconn *espconn) +{ + espconn_msg *pnode = NULL; + bool value = false; + if (espconn == NULL) + return ESPCONN_ARG; + + value = espconn_find_connection(espconn, &pnode); + if (value){ + if (pnode->pespconn->state == ESPCONN_CLOSE) + return ESPCONN_INPROGRESS; + + espconn_ssl_disconnect(pnode); + return ESPCONN_OK; + } + else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_encry_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR +espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length) +{ + espconn_msg *pnode = NULL; + bool value = false; + if (espconn == NULL) + return ESPCONN_ARG; + + espconn ->state = ESPCONN_WRITE; + value = espconn_find_connection(espconn, &pnode); + if (value){ + pmbedtls_msg pssl = NULL; + pssl = pnode->pssl; + if (pssl->SentFnFlag){ + pssl->SentFnFlag = false; + espconn_ssl_sent(pnode, psent, length); + return ESPCONN_OK; + }else + return ESPCONN_INPROGRESS; + } + else + return ESPCONN_ARG; +} + +/****************************************************************************** + * FunctionName : espconn_secure_send + * Description : send data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_send(struct espconn *espconn, uint8 *psent, uint16 length) __attribute__((alias("espconn_secure_sent"))); + +sint8 ICACHE_FLASH_ATTR +espconn_secure_accept(struct espconn *espconn) +{ + if (espconn == NULL || espconn ->type != ESPCONN_TCP) + return ESPCONN_ARG; + + return espconn_ssl_server(espconn); +} + +/****************************************************************************** + * FunctionName : espconn_secure_set_size + * Description : set the buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * size -- buffer size + * Returns : true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_set_size(uint8 level, uint16 size) +{ + size = (size < 4096) ? 4096 : size; + + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE) + return false; + + if (size > ESPCONN_SECURE_MAX_SIZE || size < ESPCONN_SECURE_DEFAULT_SIZE) + return false; + + max_content_len = size; + return true; +} + +/****************************************************************************** + * FunctionName : espconn_secure_get_size + * Description : get buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : buffer size for client or server +*******************************************************************************/ +sint16 ICACHE_FLASH_ATTR espconn_secure_get_size(uint8 level) +{ + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE) + return ESPCONN_ARG; + + return max_content_len; +} + +/****************************************************************************** + * FunctionName : espconn_secure_ca_enable + * Description : enable the certificate authenticate and set the flash sector + * as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * flash_sector -- flash sector for save certificate + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_ca_enable(uint8 level, uint32 flash_sector ) +{ + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE || flash_sector <= 0) + return false; + + if (level == ESPCONN_CLIENT){ + ssl_option.client.cert_ca_sector.sector = flash_sector; + ssl_option.client.cert_ca_sector.flag = true; + } + + if (level == ESPCONN_SERVER){ + ssl_option.server.cert_ca_sector.sector = flash_sector; + ssl_option.server.cert_ca_sector.flag = true; + } + + if (level == ESPCONN_BOTH) { + ssl_option.client.cert_ca_sector.sector = flash_sector; + ssl_option.server.cert_ca_sector.sector = flash_sector; + ssl_option.client.cert_ca_sector.flag = true; + ssl_option.server.cert_ca_sector.flag = true; + } + return true; +} + +/****************************************************************************** + * FunctionName : espconn_secure_ca_disable + * Description : disable the certificate authenticate as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_ca_disable(uint8 level) +{ + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE) + return false; + + if (level == ESPCONN_CLIENT) + ssl_option.client.cert_ca_sector.flag = false; + + if (level == ESPCONN_SERVER) + ssl_option.server.cert_ca_sector.flag = false; + + if (level == ESPCONN_BOTH) { + ssl_option.client.cert_ca_sector.flag = false; + ssl_option.server.cert_ca_sector.flag = false; + } + + return true; +} + +/****************************************************************************** + * FunctionName : espconn_secure_cert_req_enable + * Description : enable the client certificate authenticate and set the flash sector + * as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * flash_sector -- flash sector for save certificate + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_cert_req_enable(uint8 level, uint32 flash_sector ) +{ + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE || flash_sector <= 0) + return false; + + if (level == ESPCONN_CLIENT){ + ssl_option.client.cert_req_sector.sector = flash_sector; + ssl_option.client.cert_req_sector.flag = true; + } + + if (level == ESPCONN_SERVER){ + ssl_option.server.cert_req_sector.sector = flash_sector; + ssl_option.server.cert_req_sector.flag = true; + } + + if (level == ESPCONN_BOTH) { + ssl_option.client.cert_req_sector.sector = flash_sector; + ssl_option.server.cert_req_sector.sector = flash_sector; + ssl_option.client.cert_req_sector.flag = true; + ssl_option.server.cert_req_sector.flag = true; + } + return true; +} + +/****************************************************************************** + * FunctionName : espconn_secure_ca_disable + * Description : disable the client certificate authenticate as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_cert_req_disable(uint8 level) +{ + if (level >= ESPCONN_MAX || level <= ESPCONN_IDLE) + return false; + + if (level == ESPCONN_CLIENT) + ssl_option.client.cert_req_sector.flag = false; + + if (level == ESPCONN_SERVER) + ssl_option.server.cert_req_sector.flag = false; + + if (level == ESPCONN_BOTH) { + ssl_option.client.cert_req_sector.flag = false; + ssl_option.server.cert_req_sector.flag = false; + } + + return true; +} + +/****************************************************************************** + * FunctionName : espconn_secure_set_default_certificate + * Description : Load the certificates in memory depending on compile-time + * and user options. + * Parameters : certificate -- Load the certificate + * length -- Load the certificate length + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_set_default_certificate(const uint8* certificate, uint16 length) +{ + if (certificate == NULL || length > ESPCONN_SECURE_MAX_SIZE) + return false; + + return mbedtls_load_default_obj(0, ESPCONN_CERT_OWN, certificate, length); +} + +/****************************************************************************** + * FunctionName : espconn_secure_set_default_private_key + * Description : Load the key in memory depending on compile-time + * and user options. + * Parameters : private_key -- Load the key + * length -- Load the key length + * Returns : result true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR espconn_secure_set_default_private_key(const uint8* private_key, uint16 length) +{ + if (private_key == NULL || length > ESPCONN_SECURE_MAX_SIZE) + return false; + + return mbedtls_load_default_obj(0, ESPCONN_PK, private_key, length); +} + +/****************************************************************************** + * FunctionName : espconn_secure_delete + * Description : delete the secure server host + * Parameters : espconn -- espconn to set for client or server + * Returns : result +*******************************************************************************/ +sint8 ICACHE_FLASH_ATTR espconn_secure_delete(struct espconn *espconn) +{ + sint8 error = ESPCONN_OK; + error = espconn_ssl_delete(espconn); + + return error; +} + +bool espconn_secure_obj_load(int obj_type, uint32 flash_sector, uint16 length) +{ + if (length > ESPCONN_SECURE_MAX_SIZE || length == 0) + return false; + + if (obj_type != ESPCONN_PK && obj_type != ESPCONN_CERT_OWN) + return false; + + return mbedtls_load_default_obj(flash_sector, obj_type, NULL, length); +} + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPFile.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPFile.c new file mode 100644 index 0000000000..bdae8fd147 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPFile.c @@ -0,0 +1,123 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "c_types.h" + +#include +//#include "os.h" +#include + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +int ICACHE_FLASH_ATTR __attribute__((weak)) +_open_r(struct _reent *r, const char *filename, int flags, int mode) +{ + return 0; +} + +_ssize_t ICACHE_FLASH_ATTR __attribute__((weak)) +_read_r(struct _reent *r, int fd, void *buf, size_t cnt) +{ + return -1; +} + +_ssize_t ICACHE_FLASH_ATTR __attribute__((weak)) +_write_r(struct _reent *r, int fd, void *buf, size_t cnt) +{ + return -1; +} + +_off_t ICACHE_FLASH_ATTR __attribute__((weak)) +_lseek_r(struct _reent *r, int fd, _off_t pos, int whence) +{ + return -1; +} + +int ICACHE_FLASH_ATTR __attribute__((weak)) +_close_r(struct _reent *r, int fd) +{ + return -1; +} + +int ICACHE_FLASH_ATTR __attribute__((weak)) +_rename_r(struct _reent *r, const char *from, const char *to) +{ + return 0; +} + +int ICACHE_FLASH_ATTR __attribute__((weak)) +_unlink_r(struct _reent *r, const char *filename) +{ + return 0; +} + +int ICACHE_FLASH_ATTR __attribute__((weak)) +_fstat_r(struct _reent *r, int fd, struct stat *s) +{ + return 0; +} + +void *ICACHE_FLASH_ATTR __attribute__((weak)) +_sbrk_r(void *ptr, int incr) +{ + return 0; +} + +char *sys_reverse(char *s) +{ + char temp = 0; + char *p = s; + char *q = s; + while(*q) + ++q; + q--; + while(q > p){ + temp = *p; + *p++ = *q; + *q-- = temp; + } + return s; +} + +char *sys_itoa(int n) +{ + int i = 0, Negative = 0; + static char s[32]; + Negative = n; + if (Negative < 0){ + n = -n; + } + do { + s[i++] = n%10 + '0'; + n = n / 10; + }while(n > 0); + + if (Negative < 0){ + s[i++] = '-'; + } + s[i] = '\0'; + return sys_reverse(s); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPSocket.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPSocket.c new file mode 100644 index 0000000000..87a09a2a39 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/app/lwIPSocket.c @@ -0,0 +1,1011 @@ + +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "netif/etharp.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/tcp_impl.h" +#include "lwip/memp.h" + +#include "ets_sys.h" +#include "os_type.h" + +#include "lwip/mem.h" +#include "sys/socket.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +/** The global array of available sockets */ +static lwIP_sock sockets[NUM_SOCKETS]; + +/** Table to quickly map an lwIP error (err_t) to a socket error + * by using -err as an index */ +static const int err_to_errno_table[] = +{ + 0, /* ERR_OK 0 No error, everything OK. */ +// ENOMEM, /* ERR_MEM -1 Out of memory error. */ +// ENOBUFS, /* ERR_BUF -2 Buffer error. */ +// EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ +// EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ +// EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ +// EINVAL, /* ERR_VAL -6 Illegal value. */ +// EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ +// ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ +// ECONNRESET, /* ERR_RST -9 Connection reset. */ +// ESHUTDOWN, /* ERR_CLSD -10 Connection closed. */ +// ENOTCONN, /* ERR_CONN -11 Not connected. */ +// EIO, /* ERR_ARG -12 Illegal argument. */ +// EADDRINUSE, /* ERR_USE -13 Address in use. */ + -1, /* ERR_IF -14 Low-level netif error */ + -1, /* ERR_ISCONN -15 Already connected. */ +}; + +#define ERR_TO_ERRNO_TABLE_SIZE \ + (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) + +#define err_to_errno(err) \ + ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ + err_to_errno_table[-(err)] : EIO) + +#ifdef ERRNO +#ifndef set_errno +#define set_errno(err) errno = (err) +#endif +#else /* ERRNO */ +#define set_errno(err) +#endif /* ERRNO */ + +#define sock_set_errno(sk, e) do { \ + sk->err = (e); \ + set_errno(sk->err); \ +} while (0) + +static lwIP_sock *get_socket(int s); + +static int find_socket(lwIP_netconn *newconn) +{ + int i = 0; + lwIP_ASSERT(newconn); + for (i = 0; i < NUM_SOCKETS; ++i) + { + if (sockets[i].conn && sockets[i].conn == newconn) + return i; + } + return -1; +} + +static void remove_tcp(lwIP_netconn *conn) +{ + struct tcp_pcb *pcb = NULL; + sint8 ret = ERR_OK; + lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG); + pcb = conn->tcp; + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_poll(pcb, NULL, 0); + tcp_err(pcb, NULL); +exit: + return; +} + +static void free_netconn(lwIP_netconn *netconn) +{ + lwIP_ASSERT(netconn); + if (netconn->readbuf) + { + ringbuf_free(&netconn->readbuf); + } + + os_free(netconn); + netconn = NULL; +} + +static lwIP_netconn * +netconn_alloc(netconn_type type, void *arg) +{ + sint8 ret = ERR_OK; + lwIP_netconn *netconn = NULL; + struct tcp_pcb *pcb = arg; + lwIP_REQUIRE_ACTION(pcb, exit, ret = ERR_ARG); + netconn = (lwIP_netconn *)os_zalloc(sizeof(lwIP_netconn)); + lwIP_REQUIRE_ACTION(netconn, exit, ret = ERR_MEM); + netconn->readbuf = ringbuf_new(TCP_SND_BUF); + lwIP_REQUIRE_ACTION(netconn->readbuf, exit, ret = ERR_MEM); + system_overclock(); + netconn->socket = -1; +exit: + if (ret != ERR_OK) + { + free_netconn(netconn); + } + return netconn; +} + +static err_t netconn_getaddr(lwIP_netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) +{ + sint8 ret = ERR_OK; + lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG); + lwIP_REQUIRE_ACTION(addr, exit, ret = ERR_ARG); + lwIP_REQUIRE_ACTION(port, exit, ret = ERR_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG); + *port = local==1 ? conn->tcp->local_port : conn->tcp->remote_port; + *addr = local==1 ? conn->tcp->local_ip : conn->tcp->remote_ip; +exit: + return ret; +} + +/** Free a socket. The socket's netconn must have been + * delete before! + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + */ +static void free_socket(lwIP_sock *sock) +{ + void *lastdata = NULL; + sock->conn = NULL; + sock->recv_data_len = 0; + sock->recv_index = 0; + sock->send_buffer = NULL; + sock->send_index = 0; +} + +static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + lwIP_netconn *newconn = arg; + err = ESP_OK; + lwIP_REQUIRE_ACTION(newconn, exit, err = ESP_ARG); + + if (p!= NULL) + { + struct pbuf *pthis = NULL; + + if (newconn->readbuf != NULL) + { + for (pthis = p; pthis != NULL; pthis = pthis->next) + { + newconn->state = NETCONN_STATE_READ; + ringbuf_memcpy_into(newconn->readbuf, pthis->payload, pthis->len); + tcp_recved(newconn->tcp, pthis->len); + newconn->state = NETCONN_STATE_ESTABLISHED; + lwIP_EVENT_PARSE(find_socket(newconn), ERR_OK); + } + pbuf_free(p); + } + else + { + tcp_recved(newconn->tcp, p->tot_len); + pbuf_free(p); + err = ERR_MEM; + } + } + else + { + lwIP_EVENT_PARSE(find_socket(newconn), NETCONN_EVENT_CLOSE); + } +exit: + return err; +} + +static err_t poll_tcp(void *arg, struct tcp_pcb *pcb) +{ + lwIP_netconn *conn = arg; + lwIP_ASSERT(conn); + + return ERR_OK; +} + +static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + lwIP_netconn *conn = arg; + lwIP_ASSERT(conn); + conn->state = NETCONN_STATE_ESTABLISHED; + lwIP_EVENT_THREAD(find_socket(conn), NETCONN_EVENT_SEND, len); + return ERR_OK; +} + +static void err_tcp(void *arg, err_t err) +{ + lwIP_netconn *conn = arg; + lwIP_ASSERT(conn); + conn->state = NETCONN_STATE_ERROR; + ESP_LOG("%s %d %p\n",__FILE__, __LINE__, conn->tcp); + switch (conn->tcp->state) + { + case SYN_SENT: + if (conn->tcp->nrtx == TCP_SYNMAXRTX) + { + err = ERR_CONN; + } + break; + case ESTABLISHED: + if (conn->tcp->nrtx == TCP_MAXRTX) + { + err = ERR_TIMEOUT; + } + break; + default: + break; + } + + lwIP_EVENT_PARSE(find_socket(conn), err); + return; +} + +/** + * TCP callback function if a connection (opened by tcp_connect/do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + lwIP_netconn *conn = arg; + err = ERR_OK; + lwIP_REQUIRE_ACTION(conn, exit, err = ESP_ARG); + conn->state = NETCONN_STATE_ESTABLISHED; + conn->readbuf = ringbuf_new(TCP_SND_BUF); + lwIP_REQUIRE_ACTION(conn->readbuf, exit, err = ESP_MEM); + lwIP_EVENT_PARSE(find_socket(conn), ERR_OK); +exit: + return err; +} + +static void setup_tcp(lwIP_netconn *conn) +{ + struct tcp_pcb *pcb = NULL; + sint8 ret = ERR_OK; + lwIP_REQUIRE_ACTION(conn, exit, ret = ERR_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, ret = ERR_ARG); + + pcb = conn->tcp; + tcp_arg(pcb, conn); + tcp_recv(pcb, recv_tcp); + tcp_sent(pcb, sent_tcp); + tcp_poll(pcb, poll_tcp, 4); + tcp_err(pcb, err_tcp); +exit: + return; +} + +static err_t do_accepted(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + lwIP_netconn *newconn = NULL; + lwIP_netconn *conn = arg; + err = ERR_OK; + lwIP_REQUIRE_ACTION(conn, exit, err = ESP_ARG); + /* We have to set the callback here even though + * the new socket is unknown. conn->socket is marked as -1. */ + newconn = netconn_alloc(conn->type, newpcb); + lwIP_REQUIRE_ACTION(conn, exit, err = ERR_MEM); + newconn->tcp = newpcb; + setup_tcp(newconn); + newconn->state = NETCONN_STATE_ESTABLISHED; + conn->acceptmbox = newconn; + lwIP_EVENT_PARSE(find_socket(conn), ERR_OK); +exit: + return err; +} + +sint8 netconn_delete(lwIP_netconn *conn) +{ + sint8 error = ESP_OK; + lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG); + tcp_recv(conn->tcp, NULL); + error = tcp_close(conn->tcp); + + if (error != ERR_OK) + { + /* closing failed, try again later */ + tcp_recv(conn->tcp, recv_tcp); + } + else + { + /* closing succeeded */ + remove_tcp(conn); + } + free_netconn(conn); +exit: + return error; +} + +sint8 netconn_bind(lwIP_netconn *conn, ip_addr_t *addr, u16_t port) +{ + sint8 error = ESP_OK; + lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(addr, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG); + + error = tcp_bind(conn->tcp, addr, port); +exit: + return error; +} + +sint8 netconn_connect(lwIP_netconn *conn, ip_addr_t *addr, u16_t port) +{ + sint8 error = ESP_OK; + lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(addr, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG); + + setup_tcp(conn); + error = tcp_connect(conn->tcp, addr, port, do_connected); +exit: + return error; +} + +err_t netconn_accept(lwIP_netconn *conn, lwIP_netconn **new_conn) +{ + err_t error = ESP_OK; + lwIP_netconn *newconn = NULL; + lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(new_conn, exit, error = ESP_ARG); + *new_conn = NULL; + newconn = (lwIP_netconn *)conn->acceptmbox; + conn->acceptmbox = NULL; + lwIP_REQUIRE_ACTION(newconn, exit, error = ERR_CLSD); + *new_conn = newconn; +exit: + return error; +} + +sint8 netconn_listen(lwIP_netconn *conn) +{ + sint8 error = ESP_OK; + struct tcp_pcb *lpcb = NULL; + + lwIP_REQUIRE_ACTION(conn, exit, error = ESP_ARG); + lwIP_REQUIRE_ACTION(conn->tcp, exit, error = ESP_ARG); + + setup_tcp(conn); + lpcb = conn->tcp; + conn->tcp = tcp_listen(conn->tcp); + if (conn->tcp != NULL) + { + tcp_accept(conn->tcp, do_accepted); + } + else + { + conn->tcp = lpcb; + } +exit: + return error; +} + +static int alloc_socket(lwIP_netconn *newconn, int accepted) +{ + int i = 0; + lwIP_ASSERT(newconn); + /* allocate a new socket identifier */ + for (i = 0; i < NUM_SOCKETS; ++i) + { + /* Protect socket array */ + if (!sockets[i].conn) + { + sockets[i].conn = newconn; + return i; + } + } + return -1; +} + +static lwIP_sock *get_socket(int s) +{ + lwIP_sock *sock = NULL; + + if ((s < 0) || (s >= NUM_SOCKETS)) + { + return NULL; + } + + sock = &sockets[s]; + + if (!sock->conn) + { + return NULL; + } + + return sock; +} + +int lwip_socket(int domain, int type, int protocol) +{ + lwIP_netconn *conn = NULL; + int i = 0; + switch (type) + { + case SOCK_STREAM: + conn = (lwIP_netconn *)os_zalloc(sizeof(lwIP_netconn)); + lwIP_REQUIRE_ACTION(conn, exit, i = ESP_MEM); + conn->tcp = tcp_new(); + lwIP_REQUIRE_ACTION(conn->tcp, exit, i = ESP_MEM); + conn->socket = -1; + break; + default: + return -1; + } + + i = alloc_socket(conn, 0); + if (i == -1) + { + goto exit; + } + conn->socket = i; +exit: + if (i == -1) + { + if (conn->tcp) + memp_free(MEMP_TCP_PCB,conn->tcp); + if (conn) + os_free(conn); + } + return i; +} + +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + lwIP_sock *sock = NULL; + ip_addr_t local_addr; + uint16 local_port = 0; + sint8 err = ERR_OK; + const struct sockaddr_in *name_in = NULL; + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + /* check size, familiy and alignment of 'name' */ + LWIP_ERROR("lwip_bind: invalid address", + ((namelen == sizeof(struct sockaddr_in)) && ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + return -1;); + name_in = (const struct sockaddr_in *) (void*) name; + + inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); + local_port = name_in->sin_port; + + err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); + + if (err != ESP_OK) + { + ESP_LOG("%s %d, err=%d\n", __FILE__, __LINE__, err); + return -1; + } + ESP_LOG("%s %d, %d succeeded\n", __FILE__, __LINE__, s); + return ERR_OK; +} + +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + lwIP_sock *sock = NULL; + err_t err = ERR_OK; + ip_addr_t remote_addr; + u16_t remote_port = 0; + const struct sockaddr_in *name_in = NULL; + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + /* check size, familiy and alignment of 'name' */ + LWIP_ERROR("lwip_connect: invalid address", + ((namelen == sizeof(struct sockaddr_in)) && ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + return -1;); + name_in = (const struct sockaddr_in *) (void*) name; + + inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); + remote_port = name_in->sin_port; + + err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); + if (err != ERR_OK) + { + ESP_LOG("lwip_connect(%d) failed, err=%d\n", s, err); + return -1; + } + + ESP_LOG("lwip_connect(%d) succeeded\n", s); + return ERR_OK; +} + +int lwip_fcntl(int s, int cmd, int val) +{ + lwIP_sock *sock = get_socket(s); + int ret = -1; + + if (!sock || !sock->conn) + { + return -1; + } + + switch (cmd) + { + case F_GETFL: + ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; + break; + case F_SETFL: + if ((val & ~O_NONBLOCK) == 0) + { + /* only O_NONBLOCK, all other bits are zero */ + netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); + ret = 0; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); + break; + } + return ret; +} + +uint32_t lwip_getul(char *str) +{ + uint32 ret = 0; + + while (isdigit(*str)) + { + ret = ret * 10 + *str++ - '0'; + } + + return ret; +} + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + lwIP_sock *sock = NULL; + err_t err = ERR_OK; + lwIP_netconn *newconn = NULL; + int newsock = -1; + sock = get_socket(s); + if (!sock) + { + return -1; + } + + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + lwIP_REQUIRE_NOERROR(err, exit); + newsock = alloc_socket(newconn, 0); + if (newsock == -1) + { + goto exit; + } + newconn->socket = newsock; +exit: + if (newsock == -1) + { + netconn_delete(newconn); + } + return newsock; +} + +int lwip_listen(int s, int backlog) +{ + lwIP_sock *sock = NULL; + err_t err = ERR_OK; + sock = get_socket(s); + if (!sock) + { + return -1; + } + err = netconn_listen(sock->conn); + if (err != ERR_OK) + { + ESP_LOG("lwip_connect(%d) failed, err=%d\n", s, err); + return -1; + } + + ESP_LOG("lwip_connect(%d) succeeded\n", s); + + return ERR_OK; +} + +int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) +{ + lwIP_sock *sock = NULL; + size_t bytes_used = 0; + int is_tcp = 0; + lwIP_ASSERT(mem); + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + if (sock->conn != NULL) + { + if (sock->conn->state == NETCONN_STATE_ESTABLISHED) + { + bytes_used = ringbuf_bytes_used(sock->conn->readbuf); + if (bytes_used != 0) + { + if (len > bytes_used) + { + len = bytes_used; + } + ringbuf_memcpy_from(mem, sock->conn->readbuf, len); + return len; + } + else + { + return 0; + } + } + else + { + return 0; + } + } + else + { + return -1; + } +} + +int lwip_read(int s, void *mem, size_t len) +{ + return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +int lwip_recv(int s, void *mem, size_t len, int flags) +{ + return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +int lwip_send(int s, const void *data, size_t size, int flags) +{ + lwIP_sock *sock = NULL; + size_t bytes_used = 0; + err_t Err = ERR_OK; + + lwIP_ASSERT(data); + sock = get_socket(s); + if (!sock) + { + return -1; + } + + if (tcp_sndbuf(sock->conn->tcp) < size) + { + bytes_used = tcp_sndbuf(sock->conn->tcp); + } else{ + bytes_used = size; + } + + if (bytes_used > 2 * sock->conn->tcp->mss) + { + bytes_used = 2 * sock->conn->tcp->mss; + } + + do + { + Err = tcp_write(sock->conn->tcp, data, bytes_used, 1); + if (Err == ERR_MEM) + size /= 2; + } + while (Err == ERR_MEM && size > 1); + + if (Err == ERR_OK) + { + Err = tcp_output(sock->conn->tcp); + } else{ + size = Err; + } + + return size; +} + +int lwip_close(int s) +{ + lwIP_sock *sock = NULL; + int err = 0; + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + if (sock->conn->state != NETCONN_STATE_ERROR){ + tcp_recv(sock->conn->tcp, NULL); + err = tcp_close(sock->conn->tcp); + + if (err != ERR_OK) + { + /* closing failed, try again later */ + tcp_recv(sock->conn->tcp, recv_tcp); + return -1; + } + } + + /* closing succeeded */ + remove_tcp(sock->conn); + free_netconn(sock->conn); + free_socket(sock); + return ERR_OK; +} + +int lwip_write(int s, const void *data, size_t size) +{ + lwIP_sock *sock = NULL; + int is_tcp = 0; + size_t bytes_free = 0; + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + if (sock->conn != NULL) + { + switch (sock->conn->state) + { + case NETCONN_STATE_ESTABLISHED: + return lwip_send(s, data, size, 0); + default: + return -1; + } + } + else + { + return -1; + } +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ + lwIP_sock *sock = NULL; + struct sockaddr_in sin; + ip_addr_t naddr; + lwIP_ASSERT(name); + lwIP_ASSERT(namelen); + + sock = get_socket(s); + if (!sock) + { + return -1; + } + + os_memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + + /* get the IP address and port */ + netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + sin.sin_port = htons(sin.sin_port); + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + + if (*namelen > sizeof(sin)) + { + *namelen = sizeof(sin); + } + + MEMCPY(name, &sin, *namelen); + + return 0; +} + +int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 0); +} + +int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 1); +} + +int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + lwIP_sock *sock = NULL; + err_t err = ERR_OK; + + lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG); + lwIP_REQUIRE_ACTION(optlen, exit, err = ESP_ARG); + + sock = get_socket(s); + lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM); + switch (level) + { + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) + { + /* The option flags */ + case SO_ACCEPTCONN: + case SO_BROADCAST: + case SO_KEEPALIVE: +#if SO_REUSE + case SO_REUSEADDR: + case SO_REUSEPORT: +#endif /* SO_REUSE */ + *(int*)optval = sock->conn->tcp->so_options & optname; + break; + case SO_TYPE: + switch (NETCONNTYPE_GROUP(sock->conn->type)) + { + case NETCONN_TCP: + *(int*)optval = SOCK_STREAM; + break; + case NETCONN_UDP: + *(int*)optval = SOCK_DGRAM; + break; + default: + *(int*)optval = sock->conn->type; + break; + } + break; + break; + } + break; + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + break; +#if LWIP_TCP + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if (*optlen < sizeof(int)) + { + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + } + + /* If this is no TCP socket, ignore any options. */ + if (sock->conn->type != NETCONN_TCP) + { + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + } + + switch (optname) + { + case TCP_NODELAY: + case TCP_KEEPALIVE: + *(int*)optval = (int)sock->conn->tcp->keep_idle; + break; +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + *(int*)optval = (int)(sock->conn->tcp->keep_idle/1000); + break; + case TCP_KEEPINTVL: + *(int*)optval = (int)(sock->conn->tcp->keep_intvl/1000); + break; + case TCP_KEEPCNT: + *(int*)optval = (int)sock->conn->tcp->keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + break; + + default: + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ + default: + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + break; + } + +exit: + return err; +} + +int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + lwIP_sock *sock = NULL; + err_t err = ERR_OK; + lwIP_REQUIRE_ACTION(optval, exit, err = ESP_ARG); + + sock = get_socket(s); + lwIP_REQUIRE_ACTION(sock, exit, err = ESP_MEM); + lwIP_REQUIRE_ACTION(sock->conn, exit, err = ESP_MEM); + lwIP_REQUIRE_ACTION(sock->conn->tcp, exit, err = ESP_MEM); + switch (level) + { + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) + { + case SO_KEEPALIVE: + if (optlen < sizeof(int)) + { + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + } + if (*(int*)optval) + { + sock->conn->tcp->so_options |= optname; + } + else + { + sock->conn->tcp->so_options &= ~optname; + } + break; + } + break; + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + break; + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if (optlen < sizeof(int)) + { + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + } + + /* If this is no TCP socket, ignore any options. */ + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) + { + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + } + switch (optname) + { + case TCP_KEEPALIVE: + sock->conn->tcp->keep_idle = (u32_t) (*(int*) optval); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + sock->conn->tcp->keep_idle = 1000 * (u32_t) (*(int*) optval); + break; + case TCP_KEEPINTVL: + sock->conn->tcp->keep_intvl = 1000 * (u32_t) (*(int*) optval); + break; + case TCP_KEEPCNT: + sock->conn->tcp->keep_cnt = (u32_t) (*(int*) optval); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + break; + } + break; + /* UNDEFINED LEVEL */ + default: + err = ESP_ARG; + lwIP_REQUIRE_NOERROR(err, exit); + break; + } + +exit: + return err; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/Makefile new file mode 100644 index 0000000000..10f4067c64 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblibrary.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aes.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aes.c new file mode 100644 index 0000000000..0630042679 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aes.c @@ -0,0 +1,1491 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#include "c_types.h" +#include + +#include "mbedtls/aes.h" +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_AES_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +#if defined(MBEDTLS_PADLOCK_C) && \ + ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) ) +static int aes_padlock_ace = -1; +#endif + +#if defined(MBEDTLS_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t FT0[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t FT1[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t FT2[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t FT3[256] ICACHE_RODATA_ATTR STORE_ATTR = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t RT0[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t RT1[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t RT2[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t RT3[256] ICACHE_RODATA_ATTR STORE_ATTR = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] ICACHE_RODATA_ATTR = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else /* MBEDTLS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (uint32_t) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (uint32_t) y ) ^ + ( (uint32_t) x << 8 ) ^ + ( (uint32_t) x << 16 ) ^ + ( (uint32_t) z << 24 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + x = RSb[i]; + + RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ + ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ + ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ + ( (uint32_t) MUL( 0x0B, x ) << 24 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * AES key schedule (encryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + uint32_t *RK; + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + + } +#endif + + switch( keybits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) ); +#endif + + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + GET_UINT32_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 8 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 16 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] >> 24 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb ,( RK[3] ) & 0xFF ) << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 8 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 16 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] >> 24 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[5] ) & 0xFF ) << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 8 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 16 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] >> 24 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[7] ) & 0xFF ) << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( RK[11] >> 24 ) & 0xFF ) << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + return( 0 ); +} +#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int i, j, ret; + mbedtls_aes_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_aes_init( &cty ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + { + mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk, + (const unsigned char *) cty.rk, ctx->nr ); + goto exit; + } +#endif + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = RT0[ system_get_data_of_array_8(FSb, ( *SK ) & 0xFF ) ] ^ + RT1[ system_get_data_of_array_8(FSb, ( *SK >> 8 ) & 0xFF ) ] ^ + RT2[ system_get_data_of_array_8(FSb, ( *SK >> 16 ) & 0xFF ) ] ^ + RT3[ system_get_data_of_array_8(FSb, ( *SK >> 24 ) & 0xFF ) ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_aes_free( &cty ); + + return( ret ); +} +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * AES-ECB block encryption + */ +#if !defined(MBEDTLS_AES_ENCRYPT_ALT) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 24 ) & 0xFF ) << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 24 ) & 0xFF ) << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 24 ) & 0xFF ) << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y3 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y0 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y1 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(FSb, ( Y2 >> 24 ) & 0xFF ) << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); +} +#endif /* !MBEDTLS_AES_ENCRYPT_ALT */ + +/* + * AES-ECB block decryption + */ +#if !defined(MBEDTLS_AES_DECRYPT_ALT) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 24 ) & 0xFF ) << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 24 ) & 0xFF ) << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 >> 24 ) & 0xFF ) << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y3 ) & 0xFF ) ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y2 >> 8 ) & 0xFF ) << 8 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y1 >> 16 ) & 0xFF ) << 16 ) ^ + ( (uint32_t) system_get_data_of_array_8(RSb, ( Y0 >> 24 ) & 0xFF ) << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); +} +#endif /* !MBEDTLS_AES_DECRYPT_ALT */ + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) ); +#endif + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_ENCRYPT ) + mbedtls_aes_encrypt( ctx, input, output ); + else + mbedtls_aes_decrypt( ctx, input, output ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* !MBEDTLS_AES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test( int verbose ) +{ + int ret = 0, i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char iv[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + int len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + mbedtls_aes_context ctx; + + memset( key, 0, 32 ); + mbedtls_aes_init( &ctx ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CTR-128 (%s): ", + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_aes_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_ct[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_pt[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + ret = 0; + +exit: + mbedtls_aes_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aesni.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aesni.c new file mode 100644 index 0000000000..83a5868bd7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/aesni.c @@ -0,0 +1,464 @@ +/* + * AES-NI support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set + * [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AESNI_C) + +#include "mbedtls/aesni.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +/* + * AES-NI support detection routine + */ +int mbedtls_aesni_has_support( unsigned int what ) +{ + static int done = 0; + static unsigned int c = 0; + + if( ! done ) + { + asm( "movl $1, %%eax \n\t" + "cpuid \n\t" + : "=c" (c) + : + : "eax", "ebx", "edx" ); + done = 1; + } + + return( ( c & what ) != 0 ); +} + +/* + * Binutils needs to be at least 2.19 to support AES-NI instructions. + * Unfortunately, a lot of users have a lower version now (2014-04). + * Emit bytecode directly in order to support "old" version of gas. + * + * Opcodes from the Intel architecture reference manual, vol. 3. + * We always use registers, so we don't need prefixes for memory operands. + * Operand macros are in gas order (src, dst) as opposed to Intel order + * (dst, src) in order to blend better into the surrounding assembly code. + */ +#define AESDEC ".byte 0x66,0x0F,0x38,0xDE," +#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF," +#define AESENC ".byte 0x66,0x0F,0x38,0xDC," +#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD," +#define AESIMC ".byte 0x66,0x0F,0x38,0xDB," +#define AESKEYGENA ".byte 0x66,0x0F,0x3A,0xDF," +#define PCLMULQDQ ".byte 0x66,0x0F,0x3A,0x44," + +#define xmm0_xmm0 "0xC0" +#define xmm0_xmm1 "0xC8" +#define xmm0_xmm2 "0xD0" +#define xmm0_xmm3 "0xD8" +#define xmm0_xmm4 "0xE0" +#define xmm1_xmm0 "0xC1" +#define xmm1_xmm2 "0xD1" + +/* + * AES-NI AES-ECB block en(de)cryption + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + asm( "movdqu (%3), %%xmm0 \n\t" // load input + "movdqu (%1), %%xmm1 \n\t" // load round key 0 + "pxor %%xmm1, %%xmm0 \n\t" // round 0 + "addq $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // normal rounds = nr - 1 + "test %2, %2 \n\t" // mode? + "jz 2f \n\t" // 0 = decrypt + + "1: \n\t" // encryption loop + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENC xmm1_xmm0 "\n\t" // do round + "addq $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // loop + "jnz 1b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENCLAST xmm1_xmm0 "\n\t" // last round + "jmp 3f \n\t" + + "2: \n\t" // decryption loop + "movdqu (%1), %%xmm1 \n\t" + AESDEC xmm1_xmm0 "\n\t" // do round + "addq $16, %1 \n\t" + "subl $1, %0 \n\t" + "jnz 2b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESDECLAST xmm1_xmm0 "\n\t" // last round + + "3: \n\t" + "movdqu %%xmm0, (%4) \n\t" // export output + : + : "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output) + : "memory", "cc", "xmm0", "xmm1" ); + + + return( 0 ); +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ) +{ + unsigned char aa[16], bb[16], cc[16]; + size_t i; + + /* The inputs are in big-endian order, so byte-reverse them */ + for( i = 0; i < 16; i++ ) + { + aa[i] = a[15 - i]; + bb[i] = b[15 - i]; + } + + asm( "movdqu (%0), %%xmm0 \n\t" // a1:a0 + "movdqu (%1), %%xmm1 \n\t" // b1:b0 + + /* + * Caryless multiplication xmm2:xmm1 = xmm0 * xmm1 + * using [CLMUL-WP] algorithm 1 (p. 13). + */ + "movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0 + "movdqa %%xmm1, %%xmm3 \n\t" // same + "movdqa %%xmm1, %%xmm4 \n\t" // same + PCLMULQDQ xmm0_xmm1 ",0x00 \n\t" // a0*b0 = c1:c0 + PCLMULQDQ xmm0_xmm2 ",0x11 \n\t" // a1*b1 = d1:d0 + PCLMULQDQ xmm0_xmm3 ",0x10 \n\t" // a0*b1 = e1:e0 + PCLMULQDQ xmm0_xmm4 ",0x01 \n\t" // a1*b0 = f1:f0 + "pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0 + "movdqa %%xmm4, %%xmm3 \n\t" // same + "psrldq $8, %%xmm4 \n\t" // 0:e1+f1 + "pslldq $8, %%xmm3 \n\t" // e0+f0:0 + "pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1 + "pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0 + + /* + * Now shift the result one bit to the left, + * taking advantage of [CLMUL-WP] eq 27 (p. 20) + */ + "movdqa %%xmm1, %%xmm3 \n\t" // r1:r0 + "movdqa %%xmm2, %%xmm4 \n\t" // r3:r2 + "psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1 + "psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1 + "psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63 + "psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63 + "movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63 + "pslldq $8, %%xmm3 \n\t" // r0>>63:0 + "pslldq $8, %%xmm4 \n\t" // r2>>63:0 + "psrldq $8, %%xmm5 \n\t" // 0:r1>>63 + "por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1 + "por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1 + "por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63 + + /* + * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1 + * using [CLMUL-WP] algorithm 5 (p. 20). + * Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted). + */ + /* Step 2 (1) */ + "movdqa %%xmm1, %%xmm3 \n\t" // x1:x0 + "movdqa %%xmm1, %%xmm4 \n\t" // same + "movdqa %%xmm1, %%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a + "psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b + "psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c + + /* Step 2 (2) */ + "pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b + "pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c + "pslldq $8, %%xmm3 \n\t" // a+b+c:0 + "pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0 + + /* Steps 3 and 4 */ + "movdqa %%xmm1,%%xmm0 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0' + "psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0' + "psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0' + "pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0' + "pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0' + // e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing + // bits carried from d. Now get those\t bits back in. + "movdqa %%xmm1,%%xmm3 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // d<<63:stuff + "psllq $62, %%xmm4 \n\t" // d<<62:stuff + "psllq $57, %%xmm5 \n\t" // d<<57:stuff + "pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff + "pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff + "psrldq $8, %%xmm3 \n\t" // 0:missing bits of d + "pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0 + "pxor %%xmm1, %%xmm0 \n\t" // h1:h0 + "pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0 + + "movdqu %%xmm0, (%2) \n\t" // done + : + : "r" (aa), "r" (bb), "r" (cc) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" ); + + /* Now byte-reverse the outputs */ + for( i = 0; i < 16; i++ ) + c[i] = cc[15 - i]; + + return; +} + +/* + * Compute decryption round keys from encryption round keys + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, int nr ) +{ + unsigned char *ik = invkey; + const unsigned char *fk = fwdkey + 16 * nr; + + memcpy( ik, fk, 16 ); + + for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 ) + asm( "movdqu (%0), %%xmm0 \n\t" + AESIMC xmm0_xmm0 "\n\t" + "movdqu %%xmm0, (%1) \n\t" + : + : "r" (fk), "r" (ik) + : "memory", "xmm0" ); + + memcpy( ik, fk, 16 ); +} + +/* + * Key expansion, 128-bit case + */ +static void aesni_setkey_enc_128( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy the original key + "movdqu %%xmm0, (%0) \n\t" // as round key 0 + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next round key. + * + * On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff + * with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r7:r6:r5:r4 + * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0 + "pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm1 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time! + "add $16, %0 \n\t" // point to next round key + "movdqu %%xmm0, (%0) \n\t" // write it + "ret \n\t" + + /* Main "loop" */ + "2: \n\t" + AESKEYGENA xmm0_xmm1 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x80 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x1B \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x36 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 192-bit case + */ +static void aesni_setkey_enc_192( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy original round key + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movq 16(%1), %%xmm1 \n\t" + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next 6 quarter-keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4 + * and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6 + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9 + "pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10 + "pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0 + "pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10 + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "ret \n\t" + + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x80 \n\tcall 1b \n\t" + + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 256-bit case + */ +static void aesni_setkey_enc_256( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movdqu 16(%1), %%xmm1 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next two round keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and + * xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON + * + * On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12 + * and those have been written to the output buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + + /* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 ) + * and proceed to generate next round key from there */ + AESKEYGENA xmm0_xmm2 ",0x00 \n\t" + "pshufd $0xaa, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm2, %%xmm1 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "ret \n\t" + + /* + * Main "loop" - Generating one more key than necessary, + * see definition of mbedtls_aes_context.buf + */ + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, wrapper + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ) +{ + switch( bits ) + { + case 128: aesni_setkey_enc_128( rk, key ); break; + case 192: aesni_setkey_enc_192( rk, key ); break; + case 256: aesni_setkey_enc_256( rk, key ); break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/arc4.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/arc4.c new file mode 100644 index 0000000000..ff0e993e7f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/arc4.c @@ -0,0 +1,205 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARC4_C) + +#include "mbedtls/arc4.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARC4_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_arc4_context ) ); +} + +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); +} + +/* + * ARC4 key schedule + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ) +{ + int i, j, a; + unsigned int k; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ) +{ + int x, y, a, b; + size_t i; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < length; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + output[i] = (unsigned char) + ( input[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; + + return( 0 ); +} + +#endif /* !MBEDTLS_ARC4_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int mbedtls_arc4_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char ibuf[8]; + unsigned char obuf[8]; + mbedtls_arc4_context ctx; + + mbedtls_arc4_init( &ctx ); + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( ibuf, arc4_test_pt[i], 8 ); + + mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 ); + mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf ); + + if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_arc4_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARC4_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1parse.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1parse.c new file mode 100644 index 0000000000..b37523def0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1parse.c @@ -0,0 +1,392 @@ +/* + * Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +#include "mbedtls/asn1.h" + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * ASN.1 DER decoding routines + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 16 ) | + ( (size_t)(*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | + ( (size_t)(*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( mbedtls_asn1_get_len( p, end, len ) ); +} + +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 ) + return( ret ); + + if( len != 1 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = ( **p != 0 ) ? 1 : 0; + (*p)++; + + return( 0 ); +} + +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + if( len > sizeof( int ) || ( **p & 0x80 ) != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = 0; + + while( len-- > 0 ) + { + *val = ( *val << 8 ) | **p; + (*p)++; + } + + return( 0 ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mbedtls_mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs) +{ + int ret; + + /* Certificate type is a single byte bitstring */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + /* Check length, subtract one for actual bit string length */ + if( bs->len < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + bs->len -= 1; + + /* Get number of unused bits, ensure unused bits <= 7 */ + bs->unused_bits = **p; + if( bs->unused_bits > 7 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + (*p)++; + + /* Get actual bitstring */ + bs->p = *p; + *p += bs->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Get a bit string without unused bits + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + if( (*len)-- < 2 || *(*p)++ != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + + + +/* + * Parses and splits an ASN.1 "SEQUENCE OF " + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag) +{ + int ret; + size_t len; + mbedtls_asn1_buf *buf; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + buf = &(cur->buf); + buf->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) + return( ret ); + + buf->p = *p; + *p += buf->len; + + /* Allocate and assign next pointer */ + if( *p < end ) + { + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + alg->tag = **p; + end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + { + mbedtls_zeroize( params, sizeof(mbedtls_asn1_buf) ); + return( 0 ); + } + + params->tag = **p; + (*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, ¶ms->len ) ) != 0 ) + return( ret ); + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ) +{ + int ret; + mbedtls_asn1_buf params; + + memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 ) + return( ret ); + + if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) +{ + if( cur == NULL ) + return; + + mbedtls_free( cur->oid.p ); + mbedtls_free( cur->val.p ); + + mbedtls_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); +} + +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) +{ + mbedtls_asn1_named_data *cur; + + while( ( cur = *head ) != NULL ) + { + *head = cur->next; + mbedtls_asn1_free_named_data( cur ); + mbedtls_free( cur ); + } +} + +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +#endif /* MBEDTLS_ASN1_PARSE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1write.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1write.c new file mode 100644 index 0000000000..00ed73c114 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/asn1write.c @@ -0,0 +1,361 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_WRITE_C) + +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + *--(*p) = 0x81; + return( 2 ); + } + + if( *p - start < 3 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + // We assume we never have lengths larger than 65535 bytes + // + *--(*p) = len % 256; + *--(*p) = ( len / 256 ) % 256; + *--(*p) = 0x82; + + return( 3 ); +} + +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mbedtls_mpi_size( X ); + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + ret = (int) len; + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) oid, oid_len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ) +{ + int ret; + size_t len = 0; + + if( par_len == 0 ) + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) ); + else + len += par_len; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (boolean) ? 255 : 0; + len++; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + // TODO negative values and values larger than 128 + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ) +{ + int ret; + size_t len = 0, size; + + size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 ); + + // Calculate byte length + // + if( *p < start || (size_t)( *p - start ) < size + 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size + 1; + (*p) -= size; + memcpy( *p, buf, size ); + + // Write unused bits + // + *--(*p) = (unsigned char) (size * 8 - bits); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + return( (int) len ); +} + +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + { + // Add new entry if not present yet based on OID + // + if( ( cur = mbedtls_calloc( 1, sizeof(mbedtls_asn1_named_data) ) ) == NULL ) + return( NULL ); + + cur->oid.len = oid_len; + cur->oid.p = mbedtls_calloc( 1, oid_len ); + if( cur->oid.p == NULL ) + { + mbedtls_free( cur ); + return( NULL ); + } + + memcpy( cur->oid.p, oid, oid_len ); + + cur->val.len = val_len; + cur->val.p = mbedtls_calloc( 1, val_len ); + if( cur->val.p == NULL ) + { + mbedtls_free( cur->oid.p ); + mbedtls_free( cur ); + return( NULL ); + } + + cur->next = *head; + *head = cur; + } + else if( cur->val.len < val_len ) + { + /* + * Enlarge existing value buffer if needed + * Preserve old data until the allocation succeeded, to leave list in + * a consistent state in case allocation fails. + */ + void *p = mbedtls_calloc( 1, val_len ); + if( p == NULL ) + return( NULL ); + + mbedtls_free( cur->val.p ); + cur->val.p = p; + cur->val.len = val_len; + } + + if( val != NULL ) + memcpy( cur->val.p, val, val_len ); + + return( cur ); +} +#endif /* MBEDTLS_ASN1_WRITE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/base64.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/base64.c new file mode 100644 index 0000000000..36be7aa019 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/base64.c @@ -0,0 +1,289 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BASE64_C) + +#include "mbedtls/base64.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +static const unsigned char base64_enc_map[64] ICACHE_RODATA_ATTR = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] ICACHE_RODATA_ATTR = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Encode a buffer into base64 format + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + { + *olen = 0; + return( 0 ); + } + + n = slen / 3 + ( slen % 3 != 0 ); + + if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) + { + *olen = BASE64_SIZE_T_MAX; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n *= 4; + + if( dlen < n + 1 ) + { + *olen = n + 1; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = ( slen / 3 ) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = system_get_data_of_array_8(base64_enc_map, (C1 >> 2) & 0x3F); + *p++ = system_get_data_of_array_8(base64_enc_map, (((C1 & 3) << 4) + (C2 >> 4)) & 0x3F); + *p++ = system_get_data_of_array_8(base64_enc_map, (((C2 & 15) << 2) + (C3 >> 6)) & 0x3F); + *p++ = system_get_data_of_array_8(base64_enc_map, C3 & 0x3F); + } + + if( i < slen ) + { + C1 = *src++; + C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; + + *p++ = system_get_data_of_array_8(base64_enc_map, (C1 >> 2) & 0x3F); + *p++ = system_get_data_of_array_8(base64_enc_map, (((C1 & 3) << 4) + (C2 >> 4)) & 0x3F); + + if( ( i + 1 ) < slen ) + *p++ = system_get_data_of_array_8(base64_enc_map, ((C2 & 15) << 2) & 0x3F); + else *p++ = '='; + + *p++ = '='; + } + + *olen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + /* First pass: check for validity and get output length */ + for( i = n = j = 0; i < slen; i++ ) + { + /* Skip spaces before checking for EOL */ + x = 0; + while( i < slen && src[i] == ' ' ) + { + ++i; + ++x; + } + + /* Spaces at end of buffer are OK */ + if( i == slen ) + break; + + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + /* Space inside a line is an error */ + if( x != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] == '=' && ++j > 2 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || system_get_data_of_array_8(base64_dec_map, src[i]) == 127 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( system_get_data_of_array_8(base64_dec_map, src[i]) < 64 && j != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + { + *olen = 0; + return( 0 ); + } + + n = ( ( n * 6 ) + 7 ) >> 3; + n -= j; + + if( dst == NULL || dlen < n ) + { + *olen = n; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' || *src == ' ' ) + continue; + + j -= ( system_get_data_of_array_8(base64_dec_map, *src) == 64 ); + x = ( x << 6 ) | ( system_get_data_of_array_8(base64_dec_map, *src) & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *olen = p - dst; + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int mbedtls_base64_self_test( int verbose ) +{ + size_t len; + const unsigned char *src; + unsigned char buffer[128]; + + if( verbose != 0 ) + mbedtls_printf( " Base64 encoding test: " ); + + src = base64_test_dec; + + if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n Base64 decoding test: " ); + + src = base64_test_enc; + + if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BASE64_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/bignum.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/bignum.c new file mode 100644 index 0000000000..c55fdb872c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/bignum.c @@ -0,0 +1,2433 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#include "c_types.h" +#include "mbedtls/bignum.h" +#include "mbedtls/bn_mul.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mbedtls_mpi_free( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + mbedtls_zeroize( X->p, X->n * ciL ); + mbedtls_free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = mbedtls_calloc( nblimbs, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + mbedtls_zeroize( X->p, X->n * ciL ); + mbedtls_free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + size_t i; + + /* Actually resize up in this case */ + if( X->n <= nblimbs ) + return( mbedtls_mpi_grow( X, nblimbs ) ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + i++; + + if( i < nblimbs ) + i = nblimbs; + + if( ( p = mbedtls_calloc( i, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, i * ciL ); + mbedtls_zeroize( X->p, X->n * ciL ); + mbedtls_free( X->p ); + } + + X->n = i; + X->p = p; + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + if( Y->p == NULL ) + { + mbedtls_mpi_free( X ); + return( 0 ); + } + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) +{ + mbedtls_mpi T; + + memcpy( &T, X, sizeof( mbedtls_mpi ) ); + memcpy( X, Y, sizeof( mbedtls_mpi ) ); + memcpy( Y, &T, sizeof( mbedtls_mpi ) ); +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + + X->s = X->s * ( 1 - assign ) + Y->s * assign; + + for( i = 0; i < Y->n; i++ ) + X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; + + for( ; i < X->n; i++ ) + X->p[i] *= ( 1 - assign ); + +cleanup: + return( ret ); +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + mbedtls_mpi_uint tmp; + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * ( 1 - swap ) + Y->s * swap; + Y->s = Y->s * ( 1 - swap ) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; + } + +cleanup: + return( ret ); +} + +/* + * Set value from integer + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return( 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) ); + } + + X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx ); + X->p[off] |= (mbedtls_mpi_uint) val << idx; + +cleanup: + + return( ret ); +} + +/* + * Return the number of less significant zero-bits + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Count leading zero bits in a given integer + */ +static size_t mbedtls_clz( const mbedtls_mpi_uint x ) +{ + size_t j; + mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); + + for( j = 0; j < biL; j++ ) + { + if( x & mask ) break; + + mask >>= 1; + } + + return j; +} + +/* + * Return the number of bits + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ) +{ + size_t i, j; + + if( X->n == 0 ) + return( 0 ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + j = biL - mbedtls_clz( X->p[i] ); + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ) +{ + return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (mbedtls_mpi_uint) radix ) + return( MBEDTLS_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + mbedtls_mpi_uint d; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = BITS_TO_LIMBS( slen << 2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p ) +{ + int ret; + mbedtls_mpi_uint r; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); + + if( mbedtls_mpi_cmp_int( X, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ) +{ + int ret = 0; + size_t n; + char *p; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = mbedtls_mpi_bitlen( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( buflen < n ) + { + *olen = n; + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mbedtls_mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j ) != 2 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *olen = p - buf; + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Read X from an opened file + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) +{ + mbedtls_mpi_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mbedtls_mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + } + else + mbedtls_printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mbedtls_mpi_size( X ); + + if( buflen < n ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mbedtls_mpi_bitlen( X ) + count; + + if( X->n * biL < i ) + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mbedtls_mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + mbedtls_mpi Y; + mbedtls_mpi_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mbedtls_mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi_uint *o, *p, c; + + if( X == B ) + { + const mbedtls_mpi *T = A; A = X; B = T; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mbedtls_mpi subtraction + */ +static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) +{ + size_t i; + mbedtls_mpi_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + mbedtls_mpi TB; + int ret; + size_t n; + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + mbedtls_mpi_init( &TB ); + + if( X == B ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned subtractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed subtraction: X = A - B + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed subtraction: X = A - b + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mbedtls_mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b ) +{ + mbedtls_mpi_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else /* MULADDC_HUIT */ + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif /* MULADDC_HUIT */ + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi TA, TB; + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mbedtls_mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and + * mbedtls_mpi_uint divisor, d + */ +static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, + mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r ) +{ +#if defined(MBEDTLS_HAVE_UDBL) + mbedtls_t_udbl dividend, quotient; +#else + const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; + const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1; + mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mbedtls_mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if( 0 == d || u1 >= d ) + { + if (r != NULL) *r = ~0; + + return ( ~0 ); + } + +#if defined(MBEDTLS_HAVE_UDBL) + dividend = (mbedtls_t_udbl) u1 << biL; + dividend |= (mbedtls_t_udbl) u0; + quotient = dividend / d; + if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 ) + quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1; + + if( r != NULL ) + *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) ); + + return (mbedtls_mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = mbedtls_clz( d ); + d = d << s; + + u1 = u1 << s; + u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) ); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) + { + q1 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) + { + q0 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + if (r != NULL) + *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, n, t, k; + mbedtls_mpi X, Y, Z, T1, T2; + + if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) ); + if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) ); + return( 0 ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) ); + + k = mbedtls_mpi_bitlen( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) ); + + while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { + Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) ); + T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) ); + T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; + T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) ); + X.s = A->s; + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) ); + + if( mbedtls_mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) ); + + while( mbedtls_mpi_cmp_int( R, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); + + while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + size_t i; + mbedtls_mpi_uint x, y, z; + + if( b == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) +{ + mbedtls_mpi_uint x, m0 = N->p[0]; + unsigned int i; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + + for( i = biL; i >= 8; i /= 2 ) + x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm, + const mbedtls_mpi *T ) +{ + size_t i, n, m; + mbedtls_mpi_uint u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, ( n + 1 ) * ciL ); + + if( mbedtls_mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T ) +{ + mbedtls_mpi_uint z = 1; + mbedtls_mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + mbedtls_mpi_uint ei, mm, state; + mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T ); + mbedtls_mpi_init( &Apos ); + memset( W, 0, sizeof( W ) ); + + i = mbedtls_mpi_bitlen( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) + wsize = MBEDTLS_MPI_WINDOW_SIZE; + + j = N->n + 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + if( neg ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mbedtls_mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mbedtls_mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << ( wsize - 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < ( one << wsize ); i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs == 0 ) + break; + + nblimbs--; + + bufsize = sizeof( mbedtls_mpi_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= ( ei << ( wsize - nbits ) ); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( ( wbits & ( one << wsize ) ) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + + if( neg ) + { + X->s = -1; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); + } + +cleanup: + + for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + mbedtls_mpi_free( &W[i] ); + + mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); + + if( _RR == NULL || _RR->p == NULL ) + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t lz, lzt; + mbedtls_mpi TG, TA, TB; + + mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + + lz = mbedtls_mpi_lsb( &TA ); + lzt = mbedtls_mpi_lsb( &TB ); + + if( lzt < lz ) + lz = lzt; + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) ); + + if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) ); + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) ); + +cleanup: + + mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Fill X with size bytes of random. + * + * Use a temporary bytes representation to make sure the result is the same + * regardless of the platform endianness (useful when f_rng is actually + * deterministic, eg for tests). + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( size > MBEDTLS_MPI_MAX_SIZE ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 ); + mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV ); + mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) ); + + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) ); + } + + if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) ); + + while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) ); + +cleanup: + + mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 ); + mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV ); + mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 ); + + return( ret ); +} + +#if defined(MBEDTLS_GENPRIME) + +static const int small_prime[] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors( const mbedtls_mpi *X ) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint r; + + if( ( X->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, n, s; + mbedtls_mpi W, R, T, A, RR; + + mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); + mbedtls_mpi_init( &RR ); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) ); + s = mbedtls_mpi_lsb( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); + + i = mbedtls_mpi_bitlen( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + count = 0; + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + j = mbedtls_mpi_bitlen( &A ); + k = mbedtls_mpi_bitlen( &W ); + if (j > k) { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) ); + } + + if (count++ > 30) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || + mbedtls_mpi_cmp_int( &A, 1 ) <= 0 ); + + /* + * A = A^R mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) ); + + if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi XX; + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 || + mbedtls_mpi_cmp_int( &XX, 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); +} + +/* + * Prime number generation + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mbedtls_mpi_bitlen( X ); + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) ); + + mbedtls_mpi_set_bit( X, nbits-1, 1 ); + + X->p[0] |= 1; + + if( dh_flag == 0 ) + { + while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) ); + } + } + else + { + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + { + break; + } + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + } + } + +cleanup: + + mbedtls_mpi_free( &Y ); + + return( ret ); +} + +#endif /* MBEDTLS_GENPRIME */ + +#if defined(MBEDTLS_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mbedtls_mpi_self_test( int verbose ) +{ + int ret, i; + mbedtls_mpi A, E, N, X, Y, U, V; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X ); + mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #1 (mul_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #2 (div_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 || + mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #3 (exp_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #4 (inv_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #5 (simple gcd): " ); + + for( i = 0; i < GCD_PAIR_COUNT; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) ); + + if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed at %d\n", i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X ); + mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/blowfish.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/blowfish.c new file mode 100644 index 0000000000..89be4d122a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/blowfish.c @@ -0,0 +1,656 @@ +/* + * Blowfish implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Blowfish block cipher was designed by Bruce Schneier in 1993. + * http://www.schneier.com/blowfish.html + * http://en.wikipedia.org/wiki/Blowfish_%28cipher%29 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + +#include "mbedtls/blowfish.h" + +#include + +#if !defined(MBEDTLS_BLOWFISH_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL +}; + +/* declarations of data at the end of this file */ +static const uint32_t S[4][256]; + +static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x ) +{ + unsigned short a, b, c, d; + uint32_t y; + + d = (unsigned short)(x & 0xFF); + x >>= 8; + c = (unsigned short)(x & 0xFF); + x >>= 8; + b = (unsigned short)(x & 0xFF); + x >>= 8; + a = (unsigned short)(x & 0xFF); + y = ctx->S[0][a] + ctx->S[1][b]; + y = y ^ ctx->S[2][c]; + y = y + ctx->S[3][d]; + + return( y ); +} + +static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS]; + Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1]; + + *xl = Xl; + *xr = Xr; +} + +static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[1]; + Xl = Xl ^ ctx->P[0]; + + *xl = Xl; + *xr = Xr; +} + +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); +} + +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); +} + +/* + * Blowfish key schedule + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i, j, k; + uint32_t data, datal, datar; + + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + ( keybits % 8 ) ) + { + return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH ); + } + + keybits >>= 3; + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j++ ) + ctx->S[i][j] = S[i][j]; + } + + j = 0; + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i ) + { + data = 0x00000000; + for( k = 0; k < 4; ++k ) + { + data = ( data << 8 ) | key[j++]; + if( j >= keybits ) + j = 0; + } + ctx->P[i] = P[i] ^ data; + } + + datal = 0x00000000; + datar = 0x00000000; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->P[i] = datal; + ctx->P[i + 1] = datar; + } + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->S[i][j] = datal; + ctx->S[i][j + 1] = datar; + } + } + return( 0 ); +} + +/* + * Blowfish-ECB block encryption/decryption + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ) +{ + uint32_t X0, X1; + + GET_UINT32_BE( X0, input, 0 ); + GET_UINT32_BE( X1, input, 4 ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + blowfish_dec( ctx, &X0, &X1 ); + } + else /* MBEDTLS_BLOWFISH_ENCRYPT */ + { + blowfish_enc( ctx, &X0, &X1 ); + } + + PUT_UINT32_BE( X0, output, 0 ); + PUT_UINT32_BE( X1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Blowfish-CBC buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE]; + + if( length % MBEDTLS_BLOWFISH_BLOCKSIZE ) + return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE ); + mbedtls_blowfish_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_blowfish_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Blowfish CFB buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Blowfish CTR buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter, + stream_block ); + + for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; + +#endif /* !MBEDTLS_BLOWFISH_ALT */ +#endif /* MBEDTLS_BLOWFISH_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/camellia.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/camellia.c new file mode 100644 index 0000000000..e015ca24bd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/camellia.c @@ -0,0 +1,1072 @@ +/* + * Camellia implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + +#include "mbedtls/camellia.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, + 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, + 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, + 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, + 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, + 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, + 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, + 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, + 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, + 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, + 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, + 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, + 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, + 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, + 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, + 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ +{ \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ +} + +#define FL(XL, XR, KL, KR) \ +{ \ + (XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ +} + +#define FLInv(YL, YR, KL, KR) \ +{ \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \ +} + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ +{ \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for( i = 1; i <= 4; i++ ) \ + if( shifts[(INDEX)][(OFFSET)][i -1] ) \ + ROTL(TK + i * 4, TK, ( 15 * i ) % 32); \ + \ + for( i = 0; i < 20; i++ ) \ + if( indexes[(INDEX)][(OFFSET)][i] != -1 ) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \ + } \ +} + +static void camellia_feistel( const uint32_t x[2], const uint32_t k[2], + uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = ((uint32_t) SBOX1((I0 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX2((I0 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX3((I0 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX4((I0 ) & 0xFF) ); + I1 = ((uint32_t) SBOX2((I1 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX3((I1 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX4((I1 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX1((I1 ) & 0xFF) ); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); +} + +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); +} + +/* + * Camellia key schedule (encryption) + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + RK = ctx->rk; + + memset( t, 0, 64 ); + memset( RK, 0, sizeof(ctx->rk) ); + + switch( keybits ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + } + + for( i = 0; i < keybits / 8; ++i ) + t[i] = key[i]; + + if( keybits == 192 ) { + for( i = 0; i < 8; i++ ) + t[24 + i] = ~t[16 + i]; + } + + /* + * Prepare SIGMA values + */ + for( i = 0; i < 6; i++ ) { + GET_UINT32_BE( SIGMA[i][0], SIGMA_CHARS[i], 0 ); + GET_UINT32_BE( SIGMA[i][1], SIGMA_CHARS[i], 4 ); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset( KC, 0, sizeof(KC) ); + + /* Store KL, KR */ + for( i = 0; i < 8; i++ ) + GET_UINT32_BE( KC[i], t, i * 4 ); + + /* Generate KA */ + for( i = 0; i < 4; ++i ) + KC[8 + i] = KC[i] ^ KC[4 + i]; + + camellia_feistel( KC + 8, SIGMA[0], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[1], KC + 8 ); + + for( i = 0; i < 4; ++i ) + KC[8 + i] ^= KC[i]; + + camellia_feistel( KC + 8, SIGMA[2], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[3], KC + 8 ); + + if( keybits > 128 ) { + /* Generate KB */ + for( i = 0; i < 4; ++i ) + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + + camellia_feistel( KC + 12, SIGMA[4], KC + 14 ); + camellia_feistel( KC + 14, SIGMA[5], KC + 12 ); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE( idx, 0 ); + + /* Manipulating KR */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 1 ); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE( idx, 2 ); + + /* Manipulating KB */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 3 ); + } + + /* Do transpositions */ + for( i = 0; i < 20; i++ ) { + if( transposes[idx][i] != -1 ) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return( 0 ); +} + +/* + * Camellia key schedule (decryption) + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx, ret; + size_t i; + mbedtls_camellia_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_camellia_init( &cty ); + + /* Also checks keybits */ + if( ( ret = mbedtls_camellia_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + idx = ( ctx->nr == 4 ); + + RK = ctx->rk; + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4 ) + { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_camellia_free( &cty ); + + return( ret ); +} + +/* + * Camellia-ECB block encryption/decryption + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int NR; + uint32_t *RK, X[4]; + + ( (void) mode ); + + NR = ctx->nr; + RK = ctx->rk; + + GET_UINT32_BE( X[0], input, 0 ); + GET_UINT32_BE( X[1], input, 4 ); + GET_UINT32_BE( X[2], input, 8 ); + GET_UINT32_BE( X[3], input, 12 ); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while( NR ) { + --NR; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + + if( NR ) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + PUT_UINT32_BE( X[2], output, 0 ); + PUT_UINT32_BE( X[3], output, 4 ); + PUT_UINT32_BE( X[0], output, 8 ); + PUT_UINT32_BE( X[1], output, 12 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Camellia-CBC buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_camellia_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_camellia_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter, + stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_CAMELLIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_camellia_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + + mbedtls_camellia_context ctx; + + memset( key, 0, 32 ); + + for( j = 0; j < 6; j++ ) { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + + for( i = 0; i < CAMELLIA_TESTS_ECB; i++ ) { + memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_cipher[u][i], 16 ); + memcpy( dst, camellia_test_ecb_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_plain[i], 16 ); + memcpy( dst, camellia_test_ecb_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_ecb( &ctx, v, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( j = 0; j < 6; j++ ) + { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( src, camellia_test_cbc_iv, 16 ); + memcpy( dst, camellia_test_cbc_iv, 16 ); + memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + } else { + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + } + + for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) { + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + memcpy( iv , src, 16 ); + memcpy( src, camellia_test_cbc_cipher[u][i], 16 ); + memcpy( dst, camellia_test_cbc_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + memcpy( iv , dst, 16 ); + memcpy( src, camellia_test_cbc_plain[i], 16 ); + memcpy( dst, camellia_test_cbc_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CTR-128 (%s): ", + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 ); + memcpy( key, camellia_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_camellia_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_ct[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_pt[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CAMELLIA_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ccm.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ccm.c new file mode 100644 index 0000000000..3463a0b320 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ccm.c @@ -0,0 +1,464 @@ +/* + * NIST SP800-38C compliant CCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CCM_C) + +#include "mbedtls/ccm.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define CCM_ENCRYPT 0 +#define CCM_DECRYPT 1 + +/* + * Initialize context + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); +} + +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Free context + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); +} + +/* + * Macros for common operations. + * Results in smaller compiled code than static inline functions. + */ + +/* + * Update the CBC-MAC state in y using a block in b + * (Always using b as the source helps the compiler optimise a bit better.) + */ +#define UPDATE_CBC_MAC \ + for( i = 0; i < 16; i++ ) \ + y[i] ^= b[i]; \ + \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ + return( ret ); + +/* + * Encrypt or decrypt a partial block with CTR + * Warning: using b for temporary storage! src and dst must not be b! + * This avoids allocating one more 16 bytes buffer while allowing src == dst. + */ +#define CTR_CRYPT( dst, src, len ) \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ + return( ret ); \ + \ + for( i = 0; i < len; i++ ) \ + dst[i] = src[i] ^ b[i]; + +/* + * Authenticated encryption or decryption + */ +static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char i; + unsigned char q; + size_t len_left, olen; + unsigned char b[16]; + unsigned char y[16]; + unsigned char ctr[16]; + const unsigned char *src; + unsigned char *dst; + + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + */ + if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + /* Also implies q is within bounds */ + if( iv_len < 7 || iv_len > 13 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( add_len > 0xFF00 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + q = 16 - 1 - (unsigned char) iv_len; + + /* + * First block B_0: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 length + * + * With flags as (bits): + * 7 0 + * 6 add present? + * 5 .. 3 (t - 2) / 2 + * 2 .. 0 q - 1 + */ + b[0] = 0; + b[0] |= ( add_len > 0 ) << 6; + b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; + b[0] |= q - 1; + + memcpy( b + 1, iv, iv_len ); + + for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) + b[15-i] = (unsigned char)( len_left & 0xFF ); + + if( len_left > 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + + /* Start CBC-MAC with first block */ + memset( y, 0, 16 ); + UPDATE_CBC_MAC; + + /* + * If there is additional data, update CBC-MAC with + * add_len, add, 0 (padding to a block boundary) + */ + if( add_len > 0 ) + { + size_t use_len; + len_left = add_len; + src = add; + + memset( b, 0, 16 ); + b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); + b[1] = (unsigned char)( ( add_len ) & 0xFF ); + + use_len = len_left < 16 - 2 ? len_left : 16 - 2; + memcpy( b + 2, src, use_len ); + len_left -= use_len; + src += use_len; + + UPDATE_CBC_MAC; + + while( len_left > 0 ) + { + use_len = len_left > 16 ? 16 : len_left; + + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + + len_left -= use_len; + src += use_len; + } + } + + /* + * Prepare counter block for encryption: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 counter (initially 1) + * + * With flags as (bits): + * 7 .. 3 0 + * 2 .. 0 q - 1 + */ + ctr[0] = q - 1; + memcpy( ctr + 1, iv, iv_len ); + memset( ctr + 1 + iv_len, 0, q ); + ctr[15] = 1; + + /* + * Authenticate and {en,de}crypt the message. + * + * The only difference between encryption and decryption is + * the respective order of authentication and {en,de}cryption. + */ + len_left = length; + src = input; + dst = output; + + while( len_left > 0 ) + { + size_t use_len = len_left > 16 ? 16 : len_left; + + if( mode == CCM_ENCRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + } + + CTR_CRYPT( dst, src, use_len ); + + if( mode == CCM_DECRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, dst, use_len ); + UPDATE_CBC_MAC; + } + + dst += use_len; + src += use_len; + len_left -= use_len; + + /* + * Increment counter. + * No need to check for overflow thanks to the length check above. + */ + for( i = 0; i < q; i++ ) + if( ++ctr[15-i] != 0 ) + break; + } + + /* + * Authentication: reset counter and crypt/mask internal tag + */ + for( i = 0; i < q; i++ ) + ctr[15-i] = 0; + + CTR_CRYPT( y, y, 16 ); + memcpy( tag, y, tag_len ); + + return( 0 ); +} + +/* + * Authenticated encryption + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len ) ); +} + +/* + * Authenticated decryption + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char check_tag[16]; + unsigned char i; + int diff; + + if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, check_tag, tag_len ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_zeroize( output, length ); + return( MBEDTLS_ERR_CCM_AUTH_FAILED ); + } + + return( 0 ); +} + + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 + +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char msg[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +}; + +static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res[NB_TESTS][32] = { + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, + { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } +}; + +int mbedtls_ccm_self_test( int verbose ) +{ + mbedtls_ccm_context ctx; + unsigned char out[32]; + size_t i; + int ret; + + mbedtls_ccm_init( &ctx ); + + if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM: setup failed" ); + + return( 1 ); + } + + for( i = 0; i < NB_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); + + ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + msg, out, + out + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + res[i], out, + res[i] + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, msg, msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + mbedtls_ccm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_CCM_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/certs.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/certs.c new file mode 100644 index 0000000000..ffa48abfdc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/certs.c @@ -0,0 +1,357 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/certs.h" + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_CERTS_C) + +#if defined(MBEDTLS_ECDSA_C) +#define TEST_CA_CRT_EC \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \ +"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \ +"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \ +"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \ +"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \ +"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \ +"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \ +"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \ +"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; + +const char mbedtls_test_ca_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" +"\r\n" +"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" +"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" +"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" +"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest"; + +const char mbedtls_test_srv_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" +"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" +"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" +"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" +"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" +"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" +"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" +"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" +"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_srv_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" +"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" +"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const char mbedtls_test_cli_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n" +"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n" +"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n" +"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n" +"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n" +"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n" +"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n" +"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_cli_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" +"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" +"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); +#else +#define TEST_CA_CRT_EC +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_RSA_C) +#define TEST_CA_CRT_RSA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \ +"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \ +"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \ +"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \ +"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \ +"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \ +"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \ +"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \ +"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA; + +const char mbedtls_test_ca_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" +"\r\n" +"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" +"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" +"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" +"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" +"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" +"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" +"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" +"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" +"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" +"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" +"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" +"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" +"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" +"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" +"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" +"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" +"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" +"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" +"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" +"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" +"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" +"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" +"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" +"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" +"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest"; + +const char mbedtls_test_srv_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" +"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" +"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" +"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" +"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" +"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" +"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" +"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" +"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n" +"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n" +"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n" +"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n" +"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n" +"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n" +"zhuYwjVuX6JHG0c=\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_srv_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" +"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" +"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" +"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" +"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" +"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" +"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" +"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" +"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" +"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" +"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" +"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" +"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" +"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" +"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" +"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" +"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" +"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" +"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" +"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" +"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" +"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" +"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" +"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" +"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char mbedtls_test_cli_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA3WhcNMjEwMjEyMTQ0NDA3WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" +"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" +"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" +"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" +"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" +"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" +"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n" +"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQUFAAOC\r\n" +"AQEAAn86isAM8X+mVwJqeItt6E9slhEQbAofyk+diH1Lh8Y9iLlWQSKbw/UXYjx5\r\n" +"LLPZcniovxIcARC/BjyZR9g3UwTHNGNm+rwrqa15viuNOFBchykX/Orsk02EH7NR\r\n" +"Alw5WLPorYjED6cdVQgBl9ot93HdJogRiXCxErM7NC8/eP511mjq+uLDjLKH8ZPQ\r\n" +"8I4ekHJnroLsDkIwXKGIsvIBHQy2ac/NwHLCQOK6mfum1pRx52V4Utu5dLLjD5bM\r\n" +"xOBC7KU4xZKuMXXZM6/93Yb51K/J4ahf1TxJlTWXtnzDr9saEYdNy2SKY/6ZiDNH\r\n" +"D+stpAKiQLAWaAusIWKYEyw9MQ==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_cli_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" +"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" +"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" +"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" +"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" +"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" +"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" +"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" +"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" +"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" +"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" +"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" +"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" +"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" +"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" +"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" +"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" +"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" +"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" +"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" +"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" +"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" +"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" +"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" +"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa ); +#else +#define TEST_CA_CRT_RSA +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all available CA certificates */ +const char mbedtls_test_cas_pem[] = TEST_CA_CRT_RSA TEST_CA_CRT_EC; +const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); +#endif + +/* List of all available CA certificates */ +const char * mbedtls_test_cas[] = { +#if defined(MBEDTLS_RSA_C) + mbedtls_test_ca_crt_rsa, +#endif +#if defined(MBEDTLS_ECDSA_C) + mbedtls_test_ca_crt_ec, +#endif + NULL +}; +const size_t mbedtls_test_cas_len[] = { +#if defined(MBEDTLS_RSA_C) + sizeof( mbedtls_test_ca_crt_rsa ), +#endif +#if defined(MBEDTLS_ECDSA_C) + sizeof( mbedtls_test_ca_crt_ec ), +#endif + 0 +}; + +#if defined(MBEDTLS_RSA_C) +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa ); +#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */ +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_RSA_C */ + +#endif /* MBEDTLS_CERTS_C */ + +#else + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher.c new file mode 100644 index 0000000000..ccc0685036 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher.c @@ -0,0 +1,886 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher.h" +#include "mbedtls/cipher_internal.h" + +#include +#include + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static int supported_init = 0; + +const int *mbedtls_cipher_list( void ) +{ + const mbedtls_cipher_definition_t *def; + int *type; + + if( ! supported_init ) + { + def = mbedtls_cipher_definitions; + type = mbedtls_cipher_supported; + + while( def->type != 0 ) + *type++ = (*def++).type; + + *type = 0; + + supported_init = 1; + } + + return( mbedtls_cipher_supported ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->type == cipher_type ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) +{ + const mbedtls_cipher_definition_t *def; + + if( NULL == cipher_name ) + return( NULL ); + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( ! strcmp( def->info->name, cipher_name ) ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->info->base->cipher == cipher_id && + def->info->key_bitlen == (unsigned) key_bitlen && + def->info->mode == mode ) + return( def->info ); + + return( NULL ); +} + +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); +} + +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) +{ + if( ctx == NULL ) + return; + + if( ctx->cipher_ctx ) + ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); +} + +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) +{ + if( NULL == cipher_info || NULL == ctx ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); + + if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cipher_info = cipher_info; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /* + * Ignore possible errors caused by a cipher mode that doesn't use padding + */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); +#else + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); +#endif +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + + return( 0 ); +} + +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && + (int) ctx->cipher_info->key_bitlen != key_bitlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + + /* + * For CFB and CTR mode always use the encryption key schedule + */ + if( MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) + { + return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + } + + if( MBEDTLS_DECRYPT == operation ) + return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +} + +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ) +{ + size_t actual_iv_size; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* avoid buffer overflow in ctx->iv */ + if( iv_len > MBEDTLS_MAX_IV_LENGTH ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) + actual_iv_size = iv_len; + else + { + actual_iv_size = ctx->cipher_info->iv_size; + + /* avoid reading past the end of input buffer */ + if( actual_iv_size > iv_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( ctx->iv, iv, actual_iv_size ); + ctx->iv_size = actual_iv_size; + + return( 0 ); +} + +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ctx->unprocessed_len = 0; + + return( 0 ); +} + +#if defined(MBEDTLS_GCM_C) +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, + ctx->iv, ctx->iv_size, ad, ad_len ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C */ + +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ) +{ + int ret; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = 0; + + if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) + { + if( ilen != mbedtls_cipher_get_block_size( ctx ) ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + *olen = ilen; + + if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, + ctx->operation, input, output ) ) ) + { + return( ret ); + } + + return( 0 ); + } + +#if defined(MBEDTLS_GCM_C) + if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) + { + *olen = ilen; + return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, + output ); + } +#endif + + if( input == output && + ( ctx->unprocessed_len != 0 || ilen % mbedtls_cipher_get_block_size( ctx ) ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) + { + size_t copy_len = 0; + + /* + * If there is not enough data for a full block, cache it. + */ + if( ( ctx->operation == MBEDTLS_DECRYPT && + ilen + ctx->unprocessed_len <= mbedtls_cipher_get_block_size( ctx ) ) || + ( ctx->operation == MBEDTLS_ENCRYPT && + ilen + ctx->unprocessed_len < mbedtls_cipher_get_block_size( ctx ) ) ) + { + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + ilen ); + + ctx->unprocessed_len += ilen; + return( 0 ); + } + + /* + * Process cached data first + */ + if( ctx->unprocessed_len != 0 ) + { + copy_len = mbedtls_cipher_get_block_size( ctx ) - ctx->unprocessed_len; + + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + copy_len ); + + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + *olen += mbedtls_cipher_get_block_size( ctx ); + output += mbedtls_cipher_get_block_size( ctx ); + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if( 0 != ilen ) + { + copy_len = ilen % mbedtls_cipher_get_block_size( ctx ); + if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT ) + copy_len = mbedtls_cipher_get_block_size( ctx ); + + memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), + copy_len ); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if( ilen ) + { + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen += ilen; + } + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, + ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, + input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) + { + if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, + ctx->unprocessed_data, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) + { + if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_STREAM */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) +/* + * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len + */ +static void add_pkcs_padding( unsigned char *output, size_t output_len, + size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i; + + for( i = 0; i < padding_len; i++ ) + output[data_len + i] = (unsigned char) padding_len; +} + +static int get_pkcs_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len, + * so pick input_len, which is usually 8 or 16 (one block) */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len; i++ ) + bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) +/* + * One and zeros padding: fill with 80 00 ... 00 + */ +static void add_one_and_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + output[data_len] = 0x80; + for( i = 1; i < padding_len; i++ ) + output[data_len + i] = 0x00; +} + +static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done, bad; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + bad = 0xFF; + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= ( i - 1 ) * ( done != prev_done ); + bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done ); + } + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); + +} +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) +/* + * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length + */ +static void add_zeros_and_len_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + for( i = 1; i < padding_len; i++ ) + output[data_len + i - 1] = 0x00; + output[output_len - 1] = (unsigned char) padding_len; +} + +static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len - 1; i++ ) + bad |= input[i] * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) +/* + * Zero padding: fill with 00 ... 00 + */ +static void add_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t i; + + for( i = data_len; i < output_len; i++ ) + output[i] = 0x00; +} + +static int get_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= i * ( done != prev_done ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ + +/* + * No padding: don't pad :) + * + * There is no add_padding function (check for NULL in mbedtls_cipher_finish) + * but a trivial get_padding function + */ +static int get_no_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = input_len; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *olen = 0; + + if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode || + MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) + { + return( 0 ); + } + + if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) + { + if( ctx->unprocessed_len != 0 ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) + { + int ret = 0; + + if( MBEDTLS_ENCRYPT == ctx->operation ) + { + /* check for 'no padding' mode */ + if( NULL == ctx->add_padding ) + { + if( 0 != ctx->unprocessed_len ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + + ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), + ctx->unprocessed_len ); + } + else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) + { + /* + * For decrypt operations, expect a full block, + * or an empty block if no padding + */ + if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) + return( 0 ); + + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + } + + /* cipher block */ + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + /* Set output size for decryption */ + if( MBEDTLS_DECRYPT == ctx->operation ) + return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), + olen ); + + /* Set output size for encryption */ + *olen = mbedtls_cipher_get_block_size( ctx ); + return( 0 ); + } +#else + ((void) output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ) +{ + if( NULL == ctx || + MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + switch( mode ) + { +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + case MBEDTLS_PADDING_PKCS7: + ctx->add_padding = add_pkcs_padding; + ctx->get_padding = get_pkcs_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + case MBEDTLS_PADDING_ONE_AND_ZEROS: + ctx->add_padding = add_one_and_zeros_padding; + ctx->get_padding = get_one_and_zeros_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + case MBEDTLS_PADDING_ZEROS_AND_LEN: + ctx->add_padding = add_zeros_and_len_padding; + ctx->get_padding = get_zeros_and_len_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + case MBEDTLS_PADDING_ZEROS: + ctx->add_padding = add_zeros_padding; + ctx->get_padding = get_zeros_padding; + break; +#endif + case MBEDTLS_PADDING_NONE: + ctx->add_padding = NULL; + ctx->get_padding = get_no_padding; + break; + + default: + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +#if defined(MBEDTLS_GCM_C) +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_ENCRYPT != ctx->operation ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); + + return( 0 ); +} + +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + + if( NULL == ctx || NULL == ctx->cipher_info || + MBEDTLS_DECRYPT != ctx->operation ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + unsigned char check_tag[16]; + size_t i; + int diff; + + if( tag_len > sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + check_tag, tag_len ) ) ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C */ + +/* + * Packet-oriented wrapper for non-AEAD modes + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + size_t finish_olen; + + if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) + return( ret ); + + *olen += finish_olen; + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD modes + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, + iv, iv_len, ad, ad_len, input, output, + tag_len, tag ) ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, input, output, + tag, tag_len ) ); + } +#endif /* MBEDTLS_CCM_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +/* + * Packet-oriented decryption for AEAD modes + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + tag, tag_len, input, output ); + + if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + input, output, tag, tag_len ); + + if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CCM_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher_wrap.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher_wrap.c new file mode 100644 index 0000000000..814376b7e6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/cipher_wrap.c @@ -0,0 +1,1451 @@ +/** + * \file cipher_wrap.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher_internal.h" + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_GCM_C) +/* shared by all GCM ciphers */ +static void *gcm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_gcm_context ) ); + + if( ctx != NULL ) + mbedtls_gcm_init( (mbedtls_gcm_context *) ctx ); + + return( ctx ); +} + +static void gcm_ctx_free( void *ctx ) +{ + mbedtls_gcm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +/* shared by all CCM ciphers */ +static void *ccm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ccm_context ) ); + + if( ctx != NULL ) + mbedtls_ccm_init( (mbedtls_ccm_context *) ctx ); + + return( ctx ); +} + +static void ccm_ctx_free( void *ctx ) +{ + mbedtls_ccm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_AES_C) + +static int aes_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ecb( (mbedtls_aes_context *) ctx, operation, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cfb128( (mbedtls_aes_context *) ctx, operation, length, iv_off, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr( (mbedtls_aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_dec( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_enc( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static void * aes_ctx_alloc( void ) +{ + mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); + + if( aes == NULL ) + return( NULL ); + + mbedtls_aes_init( aes ); + + return( aes ); +} + +static void aes_ctx_free( void *ctx ) +{ + mbedtls_aes_free( (mbedtls_aes_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aes_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_AES, + aes_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aes_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aes_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aes_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aes_setkey_enc_wrap, + aes_setkey_dec_wrap, + aes_ctx_alloc, + aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "AES-128-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "AES-192-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "AES-256-ECB", + 16, + 0, + 16, + &aes_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aes_128_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "AES-128-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "AES-192-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "AES-256-CBC", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aes_128_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "AES-128-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "AES-192-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "AES-256-CFB128", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aes_128_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "AES-128-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "AES-192-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "AES-256-CTR", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aes_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aes_setkey_wrap, + gcm_aes_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "AES-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "AES-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "AES-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aes_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aes_setkey_wrap, + ccm_aes_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "AES-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "AES-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "AES-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + +static int camellia_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ecb( (mbedtls_camellia_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int camellia_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cbc( (mbedtls_camellia_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int camellia_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cfb128( (mbedtls_camellia_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ctr( (mbedtls_camellia_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_dec( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_enc( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static void * camellia_ctx_alloc( void ) +{ + mbedtls_camellia_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_camellia_init( ctx ); + + return( ctx ); +} + +static void camellia_ctx_free( void *ctx ) +{ + mbedtls_camellia_free( (mbedtls_camellia_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t camellia_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_CAMELLIA, + camellia_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + camellia_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + camellia_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + camellia_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + camellia_setkey_enc_wrap, + camellia_setkey_dec_wrap, + camellia_ctx_alloc, + camellia_ctx_free +}; + +static const mbedtls_cipher_info_t camellia_128_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "CAMELLIA-128-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "CAMELLIA-192-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "CAMELLIA-256-ECB", + 16, + 0, + 16, + &camellia_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t camellia_128_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "CAMELLIA-128-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "CAMELLIA-192-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "CAMELLIA-256-CBC", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t camellia_128_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "CAMELLIA-128-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "CAMELLIA-192-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cfb128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "CAMELLIA-256-CFB128", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t camellia_128_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "CAMELLIA-128-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "CAMELLIA-192-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "CAMELLIA-256-CTR", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_camellia_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_camellia_setkey_wrap, + gcm_camellia_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "CAMELLIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "CAMELLIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_gcm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "CAMELLIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_camellia_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_camellia_setkey_wrap, + ccm_camellia_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "CAMELLIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "CAMELLIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "CAMELLIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) + +static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des_crypt_ecb( (mbedtls_des_context *) ctx, input, output ); +} + +static int des3_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des3_crypt_ecb( (mbedtls_des3_context *) ctx, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des_crypt_cbc( (mbedtls_des_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des3_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des3_crypt_cbc( (mbedtls_des3_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static int des_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_dec( (mbedtls_des_context *) ctx, key ); +} + +static int des_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_enc( (mbedtls_des_context *) ctx, key ); +} + +static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static void * des_ctx_alloc( void ) +{ + mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); + + if( des == NULL ) + return( NULL ); + + mbedtls_des_init( des ); + + return( des ); +} + +static void des_ctx_free( void *ctx ) +{ + mbedtls_des_free( (mbedtls_des_context *) ctx ); + mbedtls_free( ctx ); +} + +static void * des3_ctx_alloc( void ) +{ + mbedtls_des3_context *des3; + des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); + + if( des3 == NULL ) + return( NULL ); + + mbedtls_des3_init( des3 ); + + return( des3 ); +} + +static void des3_ctx_free( void *ctx ) +{ + mbedtls_des3_free( (mbedtls_des3_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t des_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_DES, + des_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des_setkey_enc_wrap, + des_setkey_dec_wrap, + des_ctx_alloc, + des_ctx_free +}; + +static const mbedtls_cipher_info_t des_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES, + "DES-ECB", + 8, + 0, + 8, + &des_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES, + "DES-CBC", + 8, + 0, + 8, + &des_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set2key_enc_wrap, + des3_set2key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-ECB", + 8, + 0, + 8, + &des_ede_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-CBC", + 8, + 0, + 8, + &des_ede_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede3_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_3DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set3key_enc_wrap, + des3_set3key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede3_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-ECB", + 8, + 0, + 8, + &des_ede3_info +}; +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede3_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-CBC", + 8, + 0, + 8, + &des_ede3_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + +static int blowfish_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ecb( (mbedtls_blowfish_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int blowfish_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cbc( (mbedtls_blowfish_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int blowfish_crypt_cfb64_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cfb64( (mbedtls_blowfish_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ctr( (mbedtls_blowfish_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_blowfish_setkey( (mbedtls_blowfish_context *) ctx, key, key_bitlen ); +} + +static void * blowfish_ctx_alloc( void ) +{ + mbedtls_blowfish_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_blowfish_init( ctx ); + + return( ctx ); +} + +static void blowfish_ctx_free( void *ctx ) +{ + mbedtls_blowfish_free( (mbedtls_blowfish_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t blowfish_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_BLOWFISH, + blowfish_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + blowfish_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + blowfish_crypt_cfb64_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + blowfish_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + blowfish_setkey_wrap, + blowfish_setkey_wrap, + blowfish_ctx_alloc, + blowfish_ctx_free +}; + +static const mbedtls_cipher_info_t blowfish_ecb_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_MODE_ECB, + 128, + "BLOWFISH-ECB", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t blowfish_cbc_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_MODE_CBC, + 128, + "BLOWFISH-CBC", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t blowfish_cfb64_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_MODE_CFB, + 128, + "BLOWFISH-CFB64", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t blowfish_ctr_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_MODE_CTR, + 128, + "BLOWFISH-CTR", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_ARC4_C) +static int arc4_crypt_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + return( mbedtls_arc4_crypt( (mbedtls_arc4_context *) ctx, length, input, output ) ); +} + +static int arc4_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + /* we get key_bitlen in bits, arc4 expects it in bytes */ + if( key_bitlen % 8 != 0 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_arc4_setup( (mbedtls_arc4_context *) ctx, key, key_bitlen / 8 ); + return( 0 ); +} + +static void * arc4_ctx_alloc( void ) +{ + mbedtls_arc4_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_arc4_init( ctx ); + + return( ctx ); +} + +static void arc4_ctx_free( void *ctx ) +{ + mbedtls_arc4_free( (mbedtls_arc4_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t arc4_base_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_ARC4, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + arc4_crypt_stream_wrap, +#endif + arc4_setkey_wrap, + arc4_setkey_wrap, + arc4_ctx_alloc, + arc4_ctx_free +}; + +static const mbedtls_cipher_info_t arc4_128_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_MODE_STREAM, + 128, + "ARC4-128", + 0, + 0, + 1, + &arc4_base_info +}; +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +static int null_crypt_stream( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + ((void) ctx); + memmove( output, input, length ); + return( 0 ); +} + +static int null_setkey( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) ctx); + ((void) key); + ((void) key_bitlen); + + return( 0 ); +} + +static void * null_ctx_alloc( void ) +{ + return( (void *) 1 ); +} + +static void null_ctx_free( void *ctx ) +{ + ((void) ctx); +} + +static const mbedtls_cipher_base_t null_base_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_ID_NULL, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + null_crypt_stream, +#endif + null_setkey, + null_setkey, + null_ctx_alloc, + null_ctx_free +}; + +static const mbedtls_cipher_info_t null_cipher_info ICACHE_RODATA_ATTR = { + MBEDTLS_CIPHER_NULL, + MBEDTLS_MODE_STREAM, + 0, + "NULL", + 0, + 0, + 1, + &null_base_info +}; +#endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */ + +const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] ICACHE_RODATA_ATTR = +{ +#if defined(MBEDTLS_AES_C) + { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info }, + { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info }, + { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info }, + { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info }, + { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info }, + { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, + { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, + { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, + { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, + { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, + { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info }, + { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info }, + { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info }, +#endif +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + { MBEDTLS_CIPHER_ARC4_128, &arc4_128_info }, +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + { MBEDTLS_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info }, +#endif +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info }, +#endif +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) + { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_DES_CBC, &des_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE_CBC, &des_ede_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info }, +#endif +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + { MBEDTLS_CIPHER_NULL, &null_cipher_info }, +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + + { MBEDTLS_CIPHER_NONE, NULL } +}; + +#define NUM_CIPHERS sizeof mbedtls_cipher_definitions / sizeof mbedtls_cipher_definitions[0] +int mbedtls_cipher_supported[NUM_CIPHERS]; + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ctr_drbg.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ctr_drbg.c new file mode 100644 index 0000000000..aefddfa1d9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ctr_drbg.c @@ -0,0 +1,593 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publucation. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "mbedtls/ctr_drbg.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * CTR_DRBG context initialization + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Non-public function wrapped by ctr_crbg_init(). Necessary to allow NIST + * tests to succeed (which require known length fixed entropy) + */ +int mbedtls_ctr_drbg_seed_entropy_len( + mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + + memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); + + mbedtls_aes_init( &ctx->aes_ctx ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len, + MBEDTLS_CTR_DRBG_ENTROPY_LEN ) ); +} + +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_aes_free( &ctx->aes_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); +} + +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + mbedtls_aes_context aes_ctx; + + int i, j; + size_t buf_len, use_len; + + if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 ); + mbedtls_aes_init( &aes_ctx ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = MBEDTLS_CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + /* + * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? + MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len; + + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ); + } + + memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + mbedtls_aes_free( &aes_ctx ); + + return( 0 ); +} + +static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, + const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + + memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ); + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + + if( ctx->entropy_len + len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather entropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + block_cipher_df( seed, seed, seedlen ); + + /* + * Update state + */ + ctr_drbg_update_internal( ctx, seed ); + ctx->reseed_counter = 1; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; + } + + if( add_len > 0 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ); + + use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : + output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + ctr_drbg_update_internal( ctx, add_input ); + + ctx->reseed_counter++; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) +{ + int ret; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + FILE *f; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_ctr_drbg_update( ctx, buf, n ); + + return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +static const unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +static const unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +static const unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +static const unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +static const unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +static size_t test_offset; +static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, + size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine + */ +int mbedtls_ctr_drbg_self_test( int verbose ) +{ + mbedtls_ctr_drbg_context ctx; + unsigned char buf[16]; + + mbedtls_ctr_drbg_init( &ctx ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); + mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = FALSE): " ); + + mbedtls_ctr_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( memcmp( buf, result_nopr, 16 ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CTR_DRBG_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/debug.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/debug.c new file mode 100644 index 0000000000..4752ab1a39 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/debug.c @@ -0,0 +1,367 @@ +/* + * Debugging routines + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#include "mbedtls/debug.h" + +#include +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#define mbedtls_snprintf snprintf +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define DEBUG_BUF_SIZE 512 + +static int debug_threshold = 0; + +void mbedtls_debug_set_threshold( int threshold ) +{ + debug_threshold = threshold; +} + +/* + * All calls to f_dbg must be made via this function + */ +static inline void debug_send_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *str ) +{ + /* + * If in a threaded environment, we need a thread identifier. + * Since there is no portable way to get one, use the address of the ssl + * context instead, as it shouldn't be shared between threads. + */ +#if defined(MBEDTLS_THREADING_C) + char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */ + mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", ssl, str ); + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, idstr ); +#else + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, str ); +#endif +} + +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ) +{ + va_list argp; + char str[DEBUG_BUF_SIZE]; + int ret; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + va_start( argp, format ); +#if defined(_WIN32) +#if defined(_TRUNCATE) + ret = _vsnprintf_s( str, DEBUG_BUF_SIZE, _TRUNCATE, format, argp ); +#else + ret = _vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); + if( ret < 0 || (size_t) ret == DEBUG_BUF_SIZE ) + { + str[DEBUG_BUF_SIZE-1] = '\0'; + ret = -1; + } +#endif +#else + ret = vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); +#endif + va_end( argp ); + + if( ret >= 0 && ret < DEBUG_BUF_SIZE - 1 ) + { + str[ret] = '\n'; + str[ret + 1] = '\0'; + } + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ) +{ + char str[DEBUG_BUF_SIZE]; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + /* + * With non-blocking I/O and examples that just retry immediately, + * the logs would be quickly flooded with WANT_READ, so ignore that. + * Don't ignore WANT_WRITE however, since is is usually rare. + */ + if( ret == MBEDTLS_ERR_SSL_WANT_READ ) + return; + + mbedtls_snprintf( str, sizeof( str ), "%s() returned %d (-0x%04x)\n", + text, ret, -ret ); + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ) +{ + char str[DEBUG_BUF_SIZE]; + char txt[17]; + size_t i, idx = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n", + text, (unsigned int) len ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + for( i = 0; i < len; i++ ) + { + if( i >= 4096 ) + break; + + if( i % 16 == 0 ) + { + if( i > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%04x: ", + (unsigned int) i ); + + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", + (unsigned int) buf[i] ); + txt[i % 16] = ( buf[i] > 31 && buf[i] < 127 ) ? buf[i] : '.' ; + } + + if( len > 0 ) + { + for( /* i = i */; i % 16 != 0; i++ ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " " ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + } +} + +#if defined(MBEDTLS_ECP_C) +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ) +{ + char str[DEBUG_BUF_SIZE]; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + mbedtls_snprintf( str, sizeof( str ), "%s(X)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X ); + + mbedtls_snprintf( str, sizeof( str ), "%s(Y)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->Y ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_BIGNUM_C) +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ) +{ + char str[DEBUG_BUF_SIZE]; + int j, k, zeros = 1; + size_t i, n, idx = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold ) + return; + + for( n = X->n - 1; n > 0; n-- ) + if( X->p[n] != 0 ) + break; + + for( j = ( sizeof(mbedtls_mpi_uint) << 3 ) - 1; j >= 0; j-- ) + if( ( ( X->p[n] >> j ) & 1 ) != 0 ) + break; + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "value of '%s' (%d bits) is:\n", + text, (int) ( ( n * ( sizeof(mbedtls_mpi_uint) << 3 ) ) + j + 1 ) ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + for( i = n + 1, j = 0; i > 0; i-- ) + { + if( zeros && X->p[i - 1] == 0 ) + continue; + + for( k = sizeof( mbedtls_mpi_uint ) - 1; k >= 0; k-- ) + { + if( zeros && ( ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ) == 0 ) + continue; + else + zeros = 0; + + if( j % 16 == 0 ) + { + if( j > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); + idx = 0; + } + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", (unsigned int) + ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ); + + j++; + } + + } + + if( zeros == 1 ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " 00" ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void debug_print_pk( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_pk_context *pk ) +{ + size_t i; + mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS]; + char name[16]; + + memset( items, 0, sizeof( items ) ); + + if( mbedtls_pk_debug( pk, items ) != 0 ) + { + debug_send_line( ssl, level, file, line, + "invalid PK context\n" ); + return; + } + + for( i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++ ) + { + if( items[i].type == MBEDTLS_PK_DEBUG_NONE ) + return; + + mbedtls_snprintf( name, sizeof( name ), "%s%s", text, items[i].name ); + name[sizeof( name ) - 1] = '\0'; + + if( items[i].type == MBEDTLS_PK_DEBUG_MPI ) + mbedtls_debug_print_mpi( ssl, level, file, line, name, items[i].value ); + else +#if defined(MBEDTLS_ECP_C) + if( items[i].type == MBEDTLS_PK_DEBUG_ECP ) + mbedtls_debug_print_ecp( ssl, level, file, line, name, items[i].value ); + else +#endif + debug_send_line( ssl, level, file, line, + "should not happen\n" ); + } +} + +static void debug_print_line_by_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text ) +{ + char str[DEBUG_BUF_SIZE]; + const char *start, *cur; + + start = text; + for( cur = text; *cur != '\0'; cur++ ) + { + if( *cur == '\n' ) + { + size_t len = cur - start + 1; + if( len > DEBUG_BUF_SIZE - 1 ) + len = DEBUG_BUF_SIZE - 1; + + memcpy( str, start, len ); + str[len] = '\0'; + + debug_send_line( ssl, level, file, line, str ); + + start = cur + 1; + } + } +} + +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ) +{ + char str[DEBUG_BUF_SIZE]; + int i = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold ) + return; + + while( crt != NULL ) + { + char buf[1024]; + + mbedtls_snprintf( str, sizeof( str ), "%s #%d:\n", text, ++i ); + debug_send_line( ssl, level, file, line, str ); + + mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt ); + debug_print_line_by_line( ssl, level, file, line, buf ); + + debug_print_pk( ssl, level, file, line, "crt->", &crt->pk ); + + crt = crt->next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#endif /* MBEDTLS_DEBUG_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/des.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/des.c new file mode 100644 index 0000000000..61f214af31 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/des.c @@ -0,0 +1,1061 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DES_C) + +#include "mbedtls/des.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_DES_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +void mbedtls_des_init( mbedtls_des_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des_free( mbedtls_des_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des3_init( mbedtls_des3_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des3_context ) ); +} + +void mbedtls_des3_free( mbedtls_des3_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_des3_context ) ); +} + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + if( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDTLS_DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, MBEDTLS_DES_KEY_SIZE) == 0 ) + return( 1 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DES_SETKEY_ALT) +void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} +#endif /* !MBEDTLS_DES_SETKEY_ALT */ + +/* + * DES key schedule (56-bit, encryption) + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + mbedtls_des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + mbedtls_des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[MBEDTLS_DES_KEY_SIZE*2] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + mbedtls_des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES_CRYPT_ECB_ALT) +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES3_CRYPT_ECB_ALT) +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES3_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#endif /* !MBEDTLS_DES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int mbedtls_des_self_test( int verbose ) +{ + int i, j, u, v, ret = 0; + mbedtls_des_context ctx; + mbedtls_des3_context ctx3; + unsigned char buf[8]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + mbedtls_des_init( &ctx ); + mbedtls_des3_init( &ctx3 ); + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_ecb( &ctx, buf, buf ); + else + mbedtls_des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == MBEDTLS_DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_des_free( &ctx ); + mbedtls_des3_free( &ctx3 ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DES_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/dhm.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/dhm.c new file mode 100644 index 0000000000..0f4d316432 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/dhm.c @@ -0,0 +1,624 @@ +/* + * Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Reference: + * + * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DHM_C) + +#include "mbedtls/dhm.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * helper to validate the mbedtls_mpi size and import it + */ +static int dhm_read_bignum( mbedtls_mpi *X, + unsigned char **p, + const unsigned char *end ) +{ + int ret, n; + + if( end - *p < 2 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( (int)( end - *p ) < n ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret ); + + (*p) += n; + + return( 0 ); +} + +/* + * Verify sanity of parameter with regards to P + * + * Parameter should be: 2 <= public_param <= P - 2 + * + * For more information on the attack, see: + * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf + * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 + */ +static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) +{ + mbedtls_mpi L, U; + int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; + + mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); + + if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 && + mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) + { + ret = 0; + } + +cleanup: + mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); + return( ret ); +} + +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); +} + +/* + * Parse the ServerKeyExchange parameters + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ) +{ + int ret; + + if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) + return( ret ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + ctx->len = mbedtls_mpi_size( &ctx->P ); + + return( 0 ); +} + +/* + * Setup and write the ServerKeyExchange parameters + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + size_t n1, n2, n3; + unsigned char *p; + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * Generate X as large as possible ( < P ) + */ + do + { + mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + /* + * Calculate GX = G^X mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + /* + * export P, G, GX + */ +#define DHM_MPI_EXPORT(X,n) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \ + *p++ = (unsigned char)( n >> 8 ); \ + *p++ = (unsigned char)( n ); p += n; + + n1 = mbedtls_mpi_size( &ctx->P ); + n2 = mbedtls_mpi_size( &ctx->G ); + n3 = mbedtls_mpi_size( &ctx->GX ); + + p = output; + DHM_MPI_EXPORT( &ctx->P , n1 ); + DHM_MPI_EXPORT( &ctx->G , n2 ); + DHM_MPI_EXPORT( &ctx->GX, n3 ); + + *olen = p - output; + + ctx->len = n1; + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); + + return( 0 ); +} + +/* + * Import the peer's public value G^Y + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ) +{ + int ret; + + if( ctx == NULL || ilen < 1 || ilen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Create own private value X and export G^X + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + + if( ctx == NULL || olen < 1 || olen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * generate X and calculate GX = G^X mod P + */ + do + { + mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Use the blinding method and optimisation suggested in section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int dhm_update_blinding( mbedtls_dhm_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count; + + /* + * Don't use any blinding the first time a particular X is used, + * but remember it to use blinding next time. + */ + if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); + + return( 0 ); + } + + /* + * Ok, we need blinding. Can we re-use existing values? + * If yes, just update them by squaring them. + */ + if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); + + return( 0 ); + } + + /* + * We need to generate blinding values from scratch + */ + + /* Vi = random( 2, P-1 ) */ + count = 0; + do + { + mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); + + /* Vf = Vi^-X mod P */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); + +cleanup: + return( ret ); +} + +/* + * Derive and export the shared secret (G^Y)^X mod P + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi GYb; + + if( ctx == NULL || output_size < ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + mbedtls_mpi_init( &GYb ); + + /* Blind peer's value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); + } + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); + + /* Do modular exponentiation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, + &ctx->P, &ctx->RP ) ); + + /* Unblind secret value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); + } + + *olen = mbedtls_mpi_size( &ctx->K ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); + +cleanup: + mbedtls_mpi_free( &GYb ); + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); + + return( 0 ); +} + +/* + * Free the components of a DHM key + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) +{ + mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY ); + mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G ); + mbedtls_mpi_free( &ctx->P ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); +} + +#if defined(MBEDTLS_ASN1_PARSE_C) +/* + * Parse DHM parameters + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ) +{ + int ret; + size_t len; + unsigned char *p, *end; +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN DH PARAMETERS-----", + "-----END DH PARAMETERS-----", + dhmin, NULL, 0, &dhminlen ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + dhminlen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + goto exit; + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; +#else + p = (unsigned char *) dhmin; +#endif /* MBEDTLS_PEM_PARSE_C */ + end = p + dhminlen; + + /* + * DHParams ::= SEQUENCE { + * prime INTEGER, -- P + * generator INTEGER, -- g + * privateValueLength INTEGER OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + if( p != end ) + { + /* This might be the optional privateValueLength. + * If so, we can cleanly discard it */ + mbedtls_mpi rec; + mbedtls_mpi_init( &rec ); + ret = mbedtls_asn1_get_mpi( &p, end, &rec ); + mbedtls_mpi_free( &rec ); + if ( ret != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + if ( p != end ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto exit; + } + } + + ret = 0; + + dhm->len = mbedtls_mpi_size( &dhm->P ); + +exit: +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + if( ret != 0 ) + mbedtls_dhm_free( dhm ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +static int load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + mbedtls_free( *buf ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse DHM parameters + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_SELF_TEST) + +static const char mbedtls_test_dhm_params[] = +"-----BEGIN DH PARAMETERS-----\r\n" +"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" +"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" +"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" +"-----END DH PARAMETERS-----\r\n"; + +static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); + +/* + * Checkup routine + */ +int mbedtls_dhm_self_test( int verbose ) +{ + int ret; + mbedtls_dhm_context dhm; + + mbedtls_dhm_init( &dhm ); + + if( verbose != 0 ) + mbedtls_printf( " DHM parameter load: " ); + + if( ( ret = mbedtls_dhm_parse_dhm( &dhm, + (const unsigned char *) mbedtls_test_dhm_params, + mbedtls_test_dhm_params_len ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + +exit: + mbedtls_dhm_free( &dhm ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DHM_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdh.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdh.c new file mode 100644 index 0000000000..c0a8147312 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdh.c @@ -0,0 +1,264 @@ +/* + * Elliptic curve Diffie-Hellman + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * RFC 4492 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/ecdh.h" + +#include + +/* + * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); +} + +/* + * Compute shared secret (SEC1 3.3.1) + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point P; + + mbedtls_ecp_point_init( &P ); + + /* + * Make sure Q is a valid pubkey before using it + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); + + if( mbedtls_ecp_is_zero( &P ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); + +cleanup: + mbedtls_ecp_point_free( &P ); + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); +} + +/* + * Free context + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_group_free( &ctx->grp ); + mbedtls_ecp_point_free( &ctx->Q ); + mbedtls_ecp_point_free( &ctx->Qp ); + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->d ); + mbedtls_mpi_free( &ctx->z ); + mbedtls_mpi_free( &ctx->_d ); +} + +/* + * Setup and write the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t grp_len, pt_len; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) + != 0 ) + return( ret ); + + buf += grp_len; + blen -= grp_len; + + if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +/* + * Read the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, const unsigned char *end ) +{ + int ret; + + if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) + != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Get parameters from a keypair + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) + return( ret ); + + /* If it's not our key, just import the public part as Qp */ + if( side == MBEDTLS_ECDH_THEIRS ) + return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); + + /* Our key: import public (as Q) and private parts */ + if( side != MBEDTLS_ECDH_OURS ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Setup and export the client public value + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + olen, buf, blen ); +} + +/* + * Parse and import the client's public value + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret; + const unsigned char *p = buf; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) + return( ret ); + + if( (size_t)( p - buf ) != blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Derive and export the shared secret + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + if( mbedtls_mpi_size( &ctx->z ) > blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); + return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); +} + +#endif /* MBEDTLS_ECDH_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdsa.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdsa.c new file mode 100644 index 0000000000..4156f3c3c4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecdsa.c @@ -0,0 +1,448 @@ +/* + * Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDSA_C) + +#include "mbedtls/ecdsa.h" +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#include "mbedtls/hmac_drbg.h" +#endif + +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, + const unsigned char *buf, size_t blen ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + size_t use_size = blen > n_size ? n_size : blen; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); + if( use_size * 8 > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); + + /* While at it, reduce modulo N */ + if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); + +cleanup: + return( ret ); +} + +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, key_tries, sign_tries, blind_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e, t; + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); + + sign_tries = 0; + do + { + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + key_tries = 0; + do + { + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); + + if( key_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); + + /* + * Step 5: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Generate a random value to blind inv_mod in next step, + * avoiding a potential timing leak. + */ + blind_tries = 0; + do + { + size_t n_size = ( grp->nbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); + + /* See mbedtls_ecp_gen_keypair() */ + if( ++blind_tries > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); + + /* + * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); + + if( sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + + return( ret ); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Deterministic signature wrapper + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + int ret; + mbedtls_hmac_drbg_context rng_ctx; + unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; + size_t grp_len = ( grp->nbits + 7 ) / 8; + const mbedtls_md_info_t *md_info; + mbedtls_mpi h; + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &h ); + mbedtls_hmac_drbg_init( &rng_ctx ); + + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); + MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); + mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); + + ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, &rng_ctx ); + +cleanup: + mbedtls_hmac_drbg_free( &rng_ctx ); + mbedtls_mpi_free( &h ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) +{ + int ret; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || + mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Additional precaution: make sure Q is valid + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + /* + * Step 3: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); + + /* + * Step 5: R = u1 G + u2 Q + * + * Since we're not using any secret data, no need to pass a RNG to + * mbedtls_ecp_mul() for countermesures. + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); + + if( mbedtls_ecp_is_zero( &R ) ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 6: convert xR to an integer (no-op) + * Step 7: reduce xR mod n (gives v) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); + + /* + * Step 8: check if v (that is, R.X) is equal to r + */ + if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + + return( ret ); +} + +/* + * Convert a signature (given by context) to ASN.1 + */ +static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen ) +{ + int ret; + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; + unsigned char *p = buf + sizeof( buf ); + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memcpy( sig, p, len ); + *slen = len; + + return( 0 ); +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + (void) f_rng; + (void) p_rng; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg ) ); +#else + (void) md_alg; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng ) ); +#endif + + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \ + defined(MBEDTLS_ECDSA_DETERMINISTIC) +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) +{ + return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, + NULL, NULL ) ); +} +#endif + +/* + * Read and check signature + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ) +{ + int ret; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( p + len != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto cleanup; + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s ) ) != 0 ) + goto cleanup; + + if( p != end ) + ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +/* + * Generate key pair + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecp_group_load( &ctx->grp, gid ) || + mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); +} + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || + ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ) + { + mbedtls_ecdsa_free( ctx ); + } + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_init( ctx ); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_free( ctx ); +} + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecjpake.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecjpake.c new file mode 100644 index 0000000000..1fa1c2d801 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecjpake.c @@ -0,0 +1,1103 @@ +/* + * Elliptic curve J-PAKE + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References in the code are to the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECJPAKE_C) + +#include "mbedtls/ecjpake.h" + +#include + +/* + * Convert a mbedtls_ecjpake_role to identifier string + */ +static const char * const ecjpake_id[] = { + "client", + "server" +}; + +#define ID_MINE ( ecjpake_id[ ctx->role ] ) +#define ID_PEER ( ecjpake_id[ 1 - ctx->role ] ) + +/* + * Initialize context + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->md_info = NULL; + mbedtls_ecp_group_init( &ctx->grp ); + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + + mbedtls_ecp_point_init( &ctx->Xm1 ); + mbedtls_ecp_point_init( &ctx->Xm2 ); + mbedtls_ecp_point_init( &ctx->Xp1 ); + mbedtls_ecp_point_init( &ctx->Xp2 ); + mbedtls_ecp_point_init( &ctx->Xp ); + + mbedtls_mpi_init( &ctx->xm1 ); + mbedtls_mpi_init( &ctx->xm2 ); + mbedtls_mpi_init( &ctx->s ); +} + +/* + * Free context + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->md_info = NULL; + mbedtls_ecp_group_free( &ctx->grp ); + + mbedtls_ecp_point_free( &ctx->Xm1 ); + mbedtls_ecp_point_free( &ctx->Xm2 ); + mbedtls_ecp_point_free( &ctx->Xp1 ); + mbedtls_ecp_point_free( &ctx->Xp2 ); + mbedtls_ecp_point_free( &ctx->Xp ); + + mbedtls_mpi_free( &ctx->xm1 ); + mbedtls_mpi_free( &ctx->xm2 ); + mbedtls_mpi_free( &ctx->s ); +} + +/* + * Setup context + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ) +{ + int ret; + + ctx->role = role; + + if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL ) + return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) ); + +cleanup: + if( ret != 0 ) + mbedtls_ecjpake_free( ctx ); + + return( ret ); +} + +/* + * Check if context is ready for use + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ) +{ + if( ctx->md_info == NULL || + ctx->grp.id == MBEDTLS_ECP_DP_NONE || + ctx->s.p == NULL ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +/* + * Write a point plus its length to a buffer + */ +static int ecjpake_write_len_point( unsigned char **p, + const unsigned char *end, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *P ) +{ + int ret; + size_t len; + + /* Need at least 4 for length plus 1 for point */ + if( end < *p || end - *p < 5 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + ret = mbedtls_ecp_point_write_binary( grp, P, pf, + &len, *p + 4, end - ( *p + 4 ) ); + if( ret != 0 ) + return( ret ); + + (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF ); + (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF ); + (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF ); + (*p)[3] = (unsigned char)( ( len ) & 0xFF ); + + *p += 4 + len; + + return( 0 ); +} + +/* + * Size of the temporary buffer for ecjpake_hash: + * 3 EC points plus their length, plus ID and its length (4 + 6 bytes) + */ +#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 4 + 6 ) + +/* + * Compute hash for ZKP (7.4.2.2.2.1) + */ +static int ecjpake_hash( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *V, + const mbedtls_ecp_point *X, + const char *id, + mbedtls_mpi *h ) +{ + int ret; + unsigned char buf[ECJPAKE_HASH_BUF_LEN]; + unsigned char *p = buf; + const unsigned char *end = buf + sizeof( buf ); + const size_t id_len = strlen( id ); + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + /* Write things to temporary buffer */ + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, G ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, V ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, X ) ); + + if( end - p < 4 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len ) & 0xFF ); + + if( end < p || (size_t)( end - p ) < id_len ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + memcpy( p, id, id_len ); + p += id_len; + + /* Compute hash */ + mbedtls_md( md_info, buf, p - buf, hash ); + + /* Turn it into an integer mod n */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash, + mbedtls_md_get_size( md_info ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) ); + +cleanup: + return( ret ); +} + +/* + * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3) + */ +static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + mbedtls_ecp_point V, VV; + mbedtls_mpi r, h; + size_t r_len; + + mbedtls_ecp_point_init( &V ); + mbedtls_ecp_point_init( &VV ); + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &h ); + + /* + * struct { + * ECPoint V; + * opaque r<1..2^8-1>; + * } ECSchnorrZKP; + */ + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) ); + + if( end < *p || (size_t)( end - *p ) < 1 ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + r_len = *(*p)++; + + if( end < *p || (size_t)( end - *p ) < r_len ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) ); + *p += r_len; + + /* + * Verification + */ + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp, + &VV, &h, X, &r, G ) ); + + if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_ecp_point_free( &VV ); + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2) + */ +static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_mpi *x, + const mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point V; + mbedtls_mpi v; + mbedtls_mpi h; /* later recycled to hold r */ + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &V ); + mbedtls_mpi_init( &v ); + mbedtls_mpi_init( &h ); + + /* Compute signature */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, + G, &v, &V, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */ + + /* Write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V, + pf, &len, *p, end - *p ) ); + *p += len; + + len = mbedtls_mpi_size( &h ); /* actually r */ + if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + + *(*p)++ = (unsigned char)( len & 0xFF ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */ + *p += len; + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_mpi_free( &v ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof + * Output: verified public key X + */ +static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * struct { + * ECPoint X; + * ECSchnorrZKP zkp; + * } ECJPAKEKeyKP; + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) ); + if( mbedtls_ecp_is_zero( X ) ) + { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, pf, G, X, id, p, end ) ); + +cleanup: + return( ret ); +} + +/* + * Generate an ECJPAKEKeyKP + * Output: the serialized structure, plus private/public key pair + */ +static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *x, + mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* Generate key (7.4.2.3.1) and write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X, + pf, &len, *p, end - *p ) ); + *p += len; + + /* Generate and write proof */ + MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, pf, G, x, X, id, + p, end, f_rng, p_rng ) ); + +cleanup: + return( ret ); +} + +/* + * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs + * Ouputs: verified peer public keys Xa, Xb + */ +static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *Xa, + mbedtls_ecp_point *Xb, + const char *id, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + + /* + * struct { + * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2]; + * } ECJPAKEKeyKPPairList; + */ + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xa, id, &p, end ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xb, id, &p, end ) ); + + if( p != end ) + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + +cleanup: + return( ret ); +} + +/* + * Generate a ECJPAKEKeyKPPairList + * Outputs: the serialized structure, plus two private/public key pairs + */ +static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *xm1, + mbedtls_ecp_point *Xa, + mbedtls_mpi *xm2, + mbedtls_ecp_point *Xb, + const char *id, + unsigned char *buf, + size_t len, + size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = buf + len; + + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm1, Xa, id, + &p, end, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm2, Xb, id, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + return( ret ); +} + +/* + * Read and process the first round message + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->Xp1, &ctx->Xp2, ID_PEER, + buf, len ) ); +} + +/* + * Generate and write the first round message + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, + ID_MINE, buf, len, olen, f_rng, p_rng ) ); +} + +/* + * Compute the sum of three points R = A + B + C + */ +static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *A, + const mbedtls_ecp_point *B, + const mbedtls_ecp_point *C ) +{ + int ret; + mbedtls_mpi one; + + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) ); + +cleanup: + mbedtls_mpi_free( &one ); + + return( ret ); +} + +/* + * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6) + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + mbedtls_ecp_group grp; + mbedtls_ecp_point G; /* C: GB, S: GA */ + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &G ); + + /* + * Server: GA = X3 + X4 + X1 (7.4.2.6.1) + * Client: GB = X1 + X2 + X3 (7.4.2.5.1) + * Unified: G = Xm1 + Xm2 + Xp1 + * We need that before parsing in order to check Xp as we read it + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) ); + + /* + * struct { + * ECParameters curve_params; // only client reading server msg + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_CLIENT ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) ); + if( grp.id != ctx->grp.id ) + { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &ctx->Xp, ID_PEER, &p, end ) ); + + if( p != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &G ); + + return( ret ); +} + +/* + * Compute R = +/- X * S mod N, taking care not to leak S + */ +static int ecjpake_mul_secret( mbedtls_mpi *R, int sign, + const mbedtls_mpi *X, + const mbedtls_mpi *S, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi b; /* Blinding value, then s + N * blinding */ + + mbedtls_mpi_init( &b ); + + /* b = s + rnd-128-bit * N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) ); + + /* R = sign * X * b mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) ); + R->s *= sign; + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) ); + +cleanup: + mbedtls_mpi_free( &b ); + + return( ret ); +} + +/* + * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6) + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point G; /* C: GA, S: GB */ + mbedtls_ecp_point Xm; /* C: Xc, S: Xs */ + mbedtls_mpi xm; /* C: xc, S: xs */ + unsigned char *p = buf; + const unsigned char *end = buf + len; + size_t ec_len; + + mbedtls_ecp_point_init( &G ); + mbedtls_ecp_point_init( &Xm ); + mbedtls_mpi_init( &xm ); + + /* + * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1) + * + * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA + * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB + * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) ); + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) ); + + /* + * Now write things out + * + * struct { + * ECParameters curve_params; // only server writing its message + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_SERVER ) + { + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len, + p, end - p ) ); + p += ec_len; + } + + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm, + ctx->point_format, &ec_len, p, end - p ) ); + p += ec_len; + + MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &xm, &Xm, ID_MINE, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + mbedtls_ecp_point_free( &G ); + mbedtls_ecp_point_free( &Xm ); + mbedtls_mpi_free( &xm ); + + return( ret ); +} + +/* + * Derive PMS (7.4.2.7 / 7.4.2.8) + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point K; + mbedtls_mpi m_xm2_s, one; + unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; + size_t x_bytes; + + *olen = mbedtls_md_get_size( ctx->md_info ); + if( len < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &K ); + mbedtls_mpi_init( &m_xm2_s ); + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + + /* + * Client: K = ( Xs - X4 * x2 * s ) * x2 + * Server: K = ( Xc - X2 * x4 * s ) * x4 + * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2 + */ + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K, + &one, &ctx->Xp, + &m_xm2_s, &ctx->Xp2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K, + f_rng, p_rng ) ); + + /* PMS = SHA-256( K.X ) */ + x_bytes = ( ctx->grp.pbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) ); + MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) ); + +cleanup: + mbedtls_ecp_point_free( &K ); + mbedtls_mpi_free( &m_xm2_s ); + mbedtls_mpi_free( &one ); + + return( ret ); +} + +#undef ID_MINE +#undef ID_PEER + + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + !defined(MBEDTLS_SHA256_C) +int mbedtls_ecjpake_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +static const unsigned char ecjpake_test_password[] = { + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74, + 0x65, 0x73, 0x74 +}; + +static const unsigned char ecjpake_test_x1[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21 +}; + +static const unsigned char ecjpake_test_x2[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x3[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x4[] = { + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, + 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1 +}; + +static const unsigned char ecjpake_test_cli_one[] = { + 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19, + 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44, + 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad, + 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62, + 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9, + 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d, + 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e, + 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e, + 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73, + 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22, + 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce, + 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00, + 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b, + 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e, + 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62, + 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5, + 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb, + 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35, + 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0, + 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb, + 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47, + 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39, + 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97, + 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40, + 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d, + 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa, + 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d, + 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0 +}; + +static const unsigned char ecjpake_test_srv_one[] = { + 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, + 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, + 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, + 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, + 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, + 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d, + 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64, + 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36, + 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2, + 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec, + 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16, + 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96, + 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3, + 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19, + 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f, + 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8, + 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7, + 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea, + 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5, + 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6, + 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31, + 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d, + 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8, + 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee, + 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84, + 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f, + 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80, + 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12 +}; + +static const unsigned char ecjpake_test_srv_two[] = { + 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23, + 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c, + 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f, + 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca, + 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26, + 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55, + 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38, + 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6, + 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9, + 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4, + 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2, + 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8, + 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd, + 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c +}; + +static const unsigned char ecjpake_test_cli_two[] = { + 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46, + 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb, + 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72, + 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce, + 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98, + 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31, + 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15, + 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36, + 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8, + 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45, + 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d, + 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58, + 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82, + 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c +}; + +static const unsigned char ecjpake_test_pms[] = { + 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7, + 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9, + 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 +}; + +/* Load my private keys and generate the correponding public keys */ +static int ecjpake_test_load( mbedtls_ecjpake_context *ctx, + const unsigned char *xm1, size_t len1, + const unsigned char *xm2, size_t len2 ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1, + &ctx->grp.G, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2, + &ctx->grp.G, NULL, NULL ) ); + +cleanup: + return( ret ); +} + +/* For tests we don't need a secure RNG; + * use the LGC from Numerical Recipes for simplicity */ +static int ecjpake_lgc( void *p, unsigned char *out, size_t len ) +{ + static uint32_t x = 42; + (void) p; + + while( len > 0 ) + { + size_t use_len = len > 4 ? 4 : len; + x = 1664525 * x + 1013904223; + memcpy( out, &x, use_len ); + out += use_len; + len -= use_len; + } + + return( 0 ); +} + +#define TEST_ASSERT( x ) \ + do { \ + if( x ) \ + ret = 0; \ + else \ + { \ + ret = 1; \ + goto cleanup; \ + } \ + } while( 0 ) + +/* + * Checkup routine + */ +int mbedtls_ecjpake_self_test( int verbose ) +{ + int ret; + mbedtls_ecjpake_context cli; + mbedtls_ecjpake_context srv; + unsigned char buf[512], pms[32]; + size_t len, pmslen; + + mbedtls_ecjpake_init( &cli ); + mbedtls_ecjpake_init( &srv ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #0 (setup): " ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #1 (random handshake): " ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == pmslen ); + TEST_ASSERT( memcmp( buf, pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #2 (reference handshake): " ); + + /* Simulate generation of round one */ + MBEDTLS_MPI_CHK( ecjpake_test_load( &cli, + ecjpake_test_x1, sizeof( ecjpake_test_x1 ), + ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) ); + + MBEDTLS_MPI_CHK( ecjpake_test_load( &srv, + ecjpake_test_x3, sizeof( ecjpake_test_x3 ), + ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) ); + + /* Read round one */ + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, + ecjpake_test_cli_one, + sizeof( ecjpake_test_cli_one ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, + ecjpake_test_srv_one, + sizeof( ecjpake_test_srv_one ) ) == 0 ); + + /* Skip generation of round two, read round two */ + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, + ecjpake_test_srv_two, + sizeof( ecjpake_test_srv_two ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, + ecjpake_test_cli_two, + sizeof( ecjpake_test_cli_two ) ) == 0 ); + + /* Server derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + memset( buf, 0, len ); /* Avoid interferences with next step */ + + /* Client derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_ecjpake_free( &cli ); + mbedtls_ecjpake_free( &srv ); + + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#undef TEST_ASSERT + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECJPAKE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp.c new file mode 100644 index 0000000000..19bb4882e7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp.c @@ -0,0 +1,2090 @@ +/* + * Elliptic curves over GF(p): generic functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * Counts of point addition and doubling, and field multiplications. + * Used to test resistance of point multiplication to simple timing attacks. + */ +static unsigned long add_count, dbl_count, mul_count; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define ECP_SHORTWEIERSTRASS +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#define ECP_MONTGOMERY +#endif + +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + ECP_TYPE_NONE = 0, + ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; + +/* + * List of supported curves: + * - internal ID + * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2) + * - size in bits + * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. This provides the default order for the SSL module. + * + * Reminder: update profiles in x509_crt.c when adding a new curves! + */ +static const mbedtls_ecp_curve_info ecp_supported_curves[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +}; + +#define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \ + sizeof( ecp_supported_curves[0] ) + +static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; + +/* + * List of supported curves and associated info + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ) +{ + return( ecp_supported_curves ); +} + +/* + * List of supported curves, group ID only + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ) +{ + static int init_done = 0; + + if( ! init_done ) + { + size_t i = 0; + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; + + init_done = 1; + } + + return( ecp_supported_grp_id ); +} + +/* + * Get the curve info for the internal identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->grp_id == grp_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the TLS identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->tls_id == tls_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the name + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( strcmp( curve_info->name, name ) == 0 ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the type of a curve + */ +static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( ECP_TYPE_MONTGOMERY ); + else + return( ECP_TYPE_SHORT_WEIERSTRASS ); +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_init( &pt->X ); + mbedtls_mpi_init( &pt->Y ); + mbedtls_mpi_init( &pt->Z ); +} + +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) +{ + if( grp == NULL ) + return; + + memset( grp, 0, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_init( &key->grp ); + mbedtls_mpi_init( &key->d ); + mbedtls_ecp_point_init( &key->Q ); +} + +/* + * Unallocate (the components of) a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_free( &( pt->X ) ); + mbedtls_mpi_free( &( pt->Y ) ); + mbedtls_mpi_free( &( pt->Z ) ); +} + +/* + * Unallocate (the components of) a group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) +{ + size_t i; + + if( grp == NULL ) + return; + + if( grp->h != 1 ) + { + mbedtls_mpi_free( &grp->P ); + mbedtls_mpi_free( &grp->A ); + mbedtls_mpi_free( &grp->B ); + mbedtls_ecp_point_free( &grp->G ); + mbedtls_mpi_free( &grp->N ); + } + + if( grp->T != NULL ) + { + for( i = 0; i < grp->T_size; i++ ) + mbedtls_ecp_point_free( &grp->T[i] ); + mbedtls_free( grp->T ); + } + + mbedtls_zeroize( grp, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Unallocate (the components of) a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_free( &key->grp ); + mbedtls_mpi_free( &key->d ); + mbedtls_ecp_point_free( &key->Q ); +} + +/* + * Copy the contents of a point + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Z, &Q->Z ) ); + +cleanup: + return( ret ); +} + +/* + * Copy the contents of a group object + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) +{ + return mbedtls_ecp_group_load( dst, src->id ); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z , 0 ) ); + +cleanup: + return( ret ); +} + +/* + * Tell if a point is zero + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) +{ + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); +} + +/* + * Compare two points lazyly + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) + { + return( 0 ); + } + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Import a non-zero point from ASCII strings + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Export a point into unsigned binary data (SEC1 2.3.3) + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ) +{ + int ret = 0; + size_t plen; + + if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Common case: P == 0 + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + { + if( buflen < 1 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x00; + *olen = 1; + + return( 0 ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( format == MBEDTLS_ECP_PF_UNCOMPRESSED ) + { + *olen = 2 * plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x04; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) ); + } + else if( format == MBEDTLS_ECP_PF_COMPRESSED ) + { + *olen = plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + } + +cleanup: + return( ret ); +} + +/* + * Import a point from unsigned binary data (SEC1 2.3.4) + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) +{ + int ret; + size_t plen; + + if( ilen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( buf[0] == 0x00 ) + { + if( ilen == 1 ) + return( mbedtls_ecp_set_zero( pt ) ); + else + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( buf[0] != 0x04 ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + if( ilen != 2 * plen + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Import a point from a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + + /* + * We must have at least two bytes (1 for length, at least one for data) + */ + if( buf_len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = *(*buf)++; + if( data_len < 1 || data_len > buf_len - 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ); +} + +/* + * Export a point as a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret; + + /* + * buffer length must be at least one, for our length byte + */ + if( blen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 1, blen - 1) ) != 0 ) + return( ret ); + + /* + * write length to the first byte and update total length + */ + buf[0] = (unsigned char) *olen; + ++*olen; + + return( 0 ); +} + +/* + * Set a group from an ECParameters record (RFC 4492) + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + + /* + * We expect at least three bytes (see below) + */ + if( len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * First byte is curve_type; only named_curve is handled + */ + if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + return mbedtls_ecp_group_load( grp, curve_info->grp_id ); +} + +/* + * Write the ECParameters record corresponding to a group (RFC 4492) + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * We are going to write 3 bytes (see below) + */ + *olen = 3; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* + * First byte is curve_type, always named_curve + */ + *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; + + /* + * Next two bytes are the namedcurve value + */ + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +/* + * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. + * See the documentation of struct mbedtls_ecp_group. + * + * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. + */ +static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp ) +{ + int ret; + + if( grp->modp == NULL ) + return( mbedtls_mpi_mod_mpi( N, N, &grp->P ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + if( ( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) || + mbedtls_mpi_bitlen( N ) > 2 * grp->pbits ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + MBEDTLS_MPI_CHK( grp->modp( N ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + while( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &grp->P ) ); + + while( mbedtls_mpi_cmp_mpi( N, &grp->P ) >= 0 ) + /* we known P, N and the result are positive */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, N, &grp->P ) ); + +cleanup: + return( ret ); +} + +/* + * Fast mod-p functions expect their argument to be in the 0..p^2 range. + * + * In order to guarantee that, we need to ensure that operands of + * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will + * bring the result back to this range. + * + * The following macros are shortcuts for doing that. + */ + +/* + * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi + */ +#if defined(MBEDTLS_SELF_TEST) +#define INC_MUL_COUNT mul_count++; +#else +#define INC_MUL_COUNT +#endif + +#define MOD_MUL( N ) do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \ + while( 0 ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi + * N->s < 0 is a very fast test, which fails only if N is 0 + */ +#define MOD_SUB( N ) \ + while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. + * We known P, N and the result are positive, so sub_abs is correct, and + * a bit faster. + */ +#define MOD_ADD( N ) \ + while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) ) + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with coutermeasueres against + * SPA, hence timing attacks. + */ + +/* + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + * Cost: 1N := 1I + 3M + 1S + */ +static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi Zi, ZZi; + + if( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ) + return( 0 ); + + mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * X = X / Z^2 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Zi, &pt->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X ); + + /* + * Y = Y / Z^3 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y ); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + + mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + + return( ret ); +} + +/* + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * Warning: fails (returning an error) if one of the points is zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * Cost: 1N(t) := 1I + (6t - 3)M + 1S + */ +static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ) +{ + int ret; + size_t i; + mbedtls_mpi *c, u, Zi, ZZi; + + if( t_len < 2 ) + return( ecp_normalize_jac( grp, *T ) ); + + if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); + for( i = 1; i < t_len; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); + MOD_MUL( c[i] ); + } + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Zi, &u ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u, &u, &T[i]->Z ) ); MOD_MUL( u ); + } + + /* + * proceed as in normalize() + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi ) ); MOD_MUL( T[i]->Y ); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + +cleanup: + + mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + for( i = 0; i < t_len; i++ ) + mbedtls_mpi_free( &c[i] ); + mbedtls_free( c ); + + return( ret ); +} + +/* + * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. + * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid + */ +static int ecp_safe_invert_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *Q, + unsigned char inv ) +{ + int ret; + unsigned char nonzero; + mbedtls_mpi mQY; + + mbedtls_mpi_init( &mQY ); + + /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) ); + nonzero = mbedtls_mpi_cmp_int( &Q->Y, 0 ) != 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) ); + +cleanup: + mbedtls_mpi_free( &mQY ); + + return( ret ); +} + +/* + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . + * + * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR + * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. + * + * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + */ +static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + mbedtls_mpi M, S, T, U; + +#if defined(MBEDTLS_SELF_TEST) + dbl_count++; +#endif + + mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + /* M = 3(X + Z^2)(X - Z^2) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &P->X, &S ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U, &P->X, &S ) ); MOD_SUB( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &U ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + } + else + { + /* M = 3.X^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &P->X ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + + /* Optimize away for "koblitz" curves with A = 0 */ + if( mbedtls_mpi_cmp_int( &grp->A, 0 ) != 0 ) + { + /* M += A.Z^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &S, &S ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &grp->A ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &S ) ); MOD_ADD( M ); + } + } + + /* S = 4.X.Y^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &P->Y, &P->Y ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T, 1 ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &T ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &S, 1 ) ); MOD_ADD( S ); + + /* U = 8.Y^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &T, &T ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + /* T = M^2 - 2.S */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &M, &M ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + + /* S = M(S - T) - U */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &T ) ); MOD_SUB( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &S, &M ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &U ) ); MOD_SUB( S ); + + /* U = 2.Y.Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &P->Y, &P->Z ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &T ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &S ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &U ) ); + +cleanup: + mbedtls_mpi_free( &M ); mbedtls_mpi_free( &S ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &U ); + + return( ret ); +} + +/* + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. + * None of these cases can happen as intermediate step in ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base point, the factor + * being less than its order, so none of them is zero; + * - Q is an odd multiple of the base point, P an even multiple, + * due to the choice of precomputed points in the modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_mpi T1, T2, T3, T4, X, Y, Z; + +#if defined(MBEDTLS_SELF_TEST) + add_count++; +#endif + + /* + * Trivial cases: P == 0 or Q == 0 (case 1) + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, Q ) ); + + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, P ) ); + + /* + * Make sure Q coordinates are normalized + */ + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); mbedtls_mpi_init( &T3 ); mbedtls_mpi_init( &T4 ); + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 ); + + /* Special cases (2) and (3) */ + if( mbedtls_mpi_cmp_int( &T1, 0 ) == 0 ) + { + if( mbedtls_mpi_cmp_int( &T2, 0 ) == 0 ) + { + ret = ecp_double_jac( grp, R, P ); + goto cleanup; + } + else + { + ret = mbedtls_ecp_set_zero( R ); + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &Z ) ); + +cleanup: + + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); mbedtls_mpi_free( &T3 ); mbedtls_mpi_free( &T4 ); + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + + return( ret ); +} + +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * This countermeasure was first suggested in [2]. + */ +static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l, ll; + size_t p_size = ( grp->pbits + 7 ) / 8; + int count = 0; + + mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z ); + + /* X = l^2 * X */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X ); + + /* Y = l^3 * Y */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y ); + +cleanup: + mbedtls_mpi_free( &l ); mbedtls_mpi_free( &ll ); + + return( ret ); +} + +/* + * Check and define parameters used by the comb method (see below for details) + */ +#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 +#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" +#endif + +/* d = ceil( n / w ) */ +#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2 + +/* number of precomputed points */ +#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + +/* + * Compute the representation of m that will be used with our comb method. + * + * The basic comb method is described in GECC 3.44 for example. We use a + * modified version that provides resistance to SPA by avoiding zero + * digits in the representation as in [3]. We modify the method further by + * requiring that all K_i be odd, which has the small cost that our + * representation uses one more K_i, due to carries. + * + * Also, for the sake of compactness, only the seven low-order bits of x[i] + * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in + * the paper): it is set if and only if if s_i == -1; + * + * Calling conventions: + * - x is an array of size d + 1 + * - w is the size, ie number of teeth, of the comb, and must be between + * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) + * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d + * (the result will be incorrect if these assumptions are not satisfied) + */ +static void ecp_comb_fixed( unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m ) +{ + size_t i, j; + unsigned char c, cc, adjust; + + memset( x, 0, d+1 ); + + /* First get the classical comb values (except for x_d = 0) */ + for( i = 0; i < d; i++ ) + for( j = 0; j < w; j++ ) + x[i] |= mbedtls_mpi_get_bit( m, i + d * j ) << j; + + /* Now make sure x_1 .. x_d are odd */ + c = 0; + for( i = 1; i <= d; i++ ) + { + /* Add carry and update it */ + cc = x[i] & c; + x[i] = x[i] ^ c; + c = cc; + + /* Adjust if needed, avoiding branches */ + adjust = 1 - ( x[i] & 0x01 ); + c |= x[i] & ( x[i-1] * adjust ); + x[i] = x[i] ^ ( x[i-1] * adjust ); + x[i-1] |= adjust << 7; + } +} + +/* + * Precompute points for the comb method + * + * If i = i_{w-1} ... i_1 is the binary representation of i, then + * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P + * + * T must be able to hold 2^{w - 1} elements + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + */ +static int ecp_precompute_comb( const mbedtls_ecp_group *grp, + mbedtls_ecp_point T[], const mbedtls_ecp_point *P, + unsigned char w, size_t d ) +{ + int ret; + unsigned char i, k; + size_t j; + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; + + /* + * Set T[0] = P and + * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); + + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + cur = T + i; + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + for( j = 0; j < d; j++ ) + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); + + TT[k++] = cur; + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + j = i; + while( j-- ) + { + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); + TT[k++] = &T[i + j]; + } + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + +cleanup: + return( ret ); +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + */ +static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + unsigned char i ) +{ + int ret; + unsigned char ii, j; + + /* Ignore the "sign" bit and scale down */ + ii = ( i & 0x7Fu ) >> 1; + + /* Read the whole table to thwart cache-based timing attacks */ + for( j = 0; j < t_len; j++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); + } + + /* Safely invert result if i is "negative" */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) ); + +cleanup: + return( ret ); +} + +/* + * Core multiplication algorithm for the (modified) comb method. + * This part is actually common with the basic comb method (GECC 3.44) + * + * Cost: d A + d D + 1 R + */ +static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point Txi; + size_t i; + + mbedtls_ecp_point_init( &Txi ); + + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + if( f_rng != 0 ) + MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); + + while( i-- != 0 ) + { + MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); + } + +cleanup: + mbedtls_ecp_point_free( &Txi ); + + return( ret ); +} + +/* + * Multiplication using the comb method, + * for curves in short Weierstrass form + */ +static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char w, m_is_odd, p_eq_g, pre_len, i; + size_t d; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *T; + mbedtls_mpi M, mm; + + mbedtls_mpi_init( &M ); + mbedtls_mpi_init( &mm ); + + /* we need N to be odd to trnaform m in an odd number, check now */ + if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Minimize the number of multiplications, that is minimize + * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) + * (see costs of the various parts, with 1S = 1M) + */ + w = grp->nbits >= 384 ? 5 : 4; + + /* + * If P == G, pre-compute a bit more, since this may be re-used later. + * Just adding one avoids upping the cost of the first mul too much, + * and the memory cost too. + */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); + if( p_eq_g ) + w++; +#else + p_eq_g = 0; +#endif + + /* + * Make sure w is within bounds. + * (The last test is useful only for very small curves in the test suite.) + */ + if( w > MBEDTLS_ECP_WINDOW_SIZE ) + w = MBEDTLS_ECP_WINDOW_SIZE; + if( w >= grp->nbits ) + w = 2; + + /* Other sizes that depend on w */ + pre_len = 1U << ( w - 1 ); + d = ( grp->nbits + w - 1 ) / w; + + /* + * Prepare precomputed points: if P == G we want to + * use grp->T if already initialized, or initialize it. + */ + T = p_eq_g ? grp->T : NULL; + + if( T == NULL ) + { + T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); + if( T == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); + + if( p_eq_g ) + { + grp->T = T; + grp->T_size = pre_len; + } + } + + /* + * Make sure M is odd (M = m or M = N - m, since N is odd) + * using the fact that m * P = - (N - m) * P + */ + m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) ); + + /* + * Go for comb multiplication, R = M * P + */ + ecp_comb_fixed( k, d, w, &M ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); + + /* + * Now get m * P from M * P and normalize it + */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + + if( T != NULL && ! p_eq_g ) + { + for( i = 0; i < pre_len; i++ ) + mbedtls_ecp_point_free( &T[i] ); + mbedtls_free( T ); + } + + mbedtls_mpi_free( &M ); + mbedtls_mpi_free( &mm ); + + if( ret != 0 ) + mbedtls_ecp_point_free( R ); + + return( ret ); +} + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) +/* + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internaly represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. + */ + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l; + size_t p_size = ( grp->pbits + 7 ) / 8; + int count = 0; + + mbedtls_mpi_init( &l ); + + /* Generate l such that 1 < l < p */ + do + { + mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z ); + +cleanup: + mbedtls_mpi_free( &l ); + + return( ret ); +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + const mbedtls_mpi *d ) +{ + int ret; + mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); + mbedtls_mpi_init( &BB ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &C ); + mbedtls_mpi_init( &D ); mbedtls_mpi_init( &DA ); mbedtls_mpi_init( &CB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z ); + +cleanup: + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &AA ); mbedtls_mpi_free( &B ); + mbedtls_mpi_free( &BB ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &D ); mbedtls_mpi_free( &DA ); mbedtls_mpi_free( &CB ); + + return( ret ); +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i; + unsigned char b; + mbedtls_ecp_point RP; + mbedtls_mpi PX; + + mbedtls_ecp_point_init( &RP ); mbedtls_mpi_init( &PX ); + + /* Save PX and read from P before writing to R, in case P == R */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &PX, &P->X ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &RP, P ) ); + + /* Set R to zero in modified x/z coordinates */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->X, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 0 ) ); + mbedtls_mpi_free( &R->Y ); + + /* RP.X might be sligtly larger than P, so reduce it */ + MOD_ADD( RP.X ); + + /* Randomize coordinates of the starting point */ + if( f_rng != NULL ) + MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); + + /* Loop invariant: R = result so far, RP = R + P */ + i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */ + while( i-- > 0 ) + { + b = mbedtls_mpi_get_bit( m, i ); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + MBEDTLS_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + } + + MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &RP ); mbedtls_mpi_free( &PX ); + + return( ret ); +} + +#endif /* ECP_MONTGOMERY */ + +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + /* Common sanity checks */ + if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || + ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) + return( ret ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_mul_comb( grp, R, m, P, f_rng, p_rng ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi YY, RHS; + + /* pt coordinates must be normalized for our checks */ + if( mbedtls_mpi_cmp_int( &pt->X, 0 ) < 0 || + mbedtls_mpi_cmp_int( &pt->Y, 0 ) < 0 || + mbedtls_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || + mbedtls_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_mpi_init( &YY ); mbedtls_mpi_init( &RHS ); + + /* + * YY = Y^2 + * RHS = X (X^2 + A) + B = X^3 + A X + B + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->A ) ); MOD_ADD( RHS ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS ); + + if( mbedtls_mpi_cmp_mpi( &YY, &RHS ) != 0 ) + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + +cleanup: + + mbedtls_mpi_free( &YY ); mbedtls_mpi_free( &RHS ); + + return( ret ); +} +#endif /* ECP_SHORTWEIERSTRASS */ + +/* + * R = m * P with shortcuts for m == 1 and m == -1 + * NOT constant-time - ONLY for short Weierstrass! + */ +static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + } + else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) ); + } + +cleanup: + return( ret ); +} + +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_ecp_point mP; + + if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + mbedtls_ecp_point_init( &mP ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) ); + + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &mP ); + + return( ret ); +} + + +#if defined(ECP_MONTGOMERY) +/* + * Check validity of a public key for Montgomery curves with x-only schemes + */ +static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); +} +#endif /* ECP_MONTGOMERY */ + +/* + * Check that a point is valid as a public key + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* Must use affine coordinates */ + if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_check_pubkey_sw( grp, pt ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Check that an mbedtls_mpi is valid as a private key + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ) +{ +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* see [Curve25519] page 5 */ + if( mbedtls_mpi_get_bit( d, 0 ) != 0 || + mbedtls_mpi_get_bit( d, 1 ) != 0 || + mbedtls_mpi_get_bit( d, 2 ) != 0 || + mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* see SEC1 3.2 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_SHORTWEIERSTRASS */ + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* [M225] page 5 */ + size_t b; + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + + /* Make sure the most significant bit is nbits */ + b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */ + if( b > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); + + /* Make sure the last three bits are unset */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + else +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + unsigned char rnd[MBEDTLS_ECP_MAX_BYTES]; + + /* + * Match the procedure given in RFC 6979 (deterministic ECDSA): + * - use the same byte ordering; + * - keep the leftmost nbits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any biais, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( f_rng( p_rng, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); + + /* + * Each try has at worst a probability 1/2 of failing (the msb has + * a probability 1/2 of being 0, and then the result will be < N), + * so after 30 tries failure probability is a most 2**(-30). + * + * For most curves, 1 try is enough with overwhelming probability, + * since N starts with a lot of 1s in binary, but some curves + * such as secp224k1 are actually very close to the worst case. + */ + if( ++count > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); + } + else +#endif /* ECP_SHORTWEIERSTRASS */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +} + +/* + * Generate key pair, wrapper for conventional base point + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); +} + +/* + * Generate a keypair, prettier wrapper + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) ); +} + +/* + * Check a public-private key pair + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ) +{ + int ret; + mbedtls_ecp_point Q; + mbedtls_ecp_group grp; + + if( pub->grp.id == MBEDTLS_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mbedtls_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + mbedtls_ecp_point_init( &Q ); + mbedtls_ecp_group_init( &grp ); + + /* mbedtls_ecp_mul() needs a non-const group... */ + mbedtls_ecp_group_copy( &grp, &prv->grp ); + + /* Also checks d is valid */ + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) ); + + if( mbedtls_mpi_cmp_mpi( &Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &Q ); + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Checkup routine + */ +int mbedtls_ecp_self_test( int verbose ) +{ + int ret; + size_t i; + mbedtls_ecp_group grp; + mbedtls_ecp_point R, P; + mbedtls_mpi m; + unsigned long add_c_prev, dbl_c_prev, mul_c_prev; + /* exponents especially adapted for secp192r1 */ + const char *exponents[] = + { + "000000000000000000000000000000000000000000000001", /* one */ + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */ + "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ + "400000000000000000000000000000000000000000000000", /* one and zeros */ + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ + "555555555555555555555555555555555555555555555555", /* 101010... */ + }; + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &R ); + mbedtls_ecp_point_init( &P ); + mbedtls_mpi_init( &m ); + + /* Use secp192r1 if available, or any available curve */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP192R1 ) ); +#else + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, mbedtls_ecp_curve_list()->grp_id ) ); +#endif + + if( verbose != 0 ) + mbedtls_printf( " ECP test #1 (constant op_count, base point G): " ); + + /* Do a dummy multiplication first to trigger precomputation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &m, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) ); + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECP test #2 (constant op_count, other point): " ); + /* We computed P = 2G last time, use it */ + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret < 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &R ); + mbedtls_ecp_point_free( &P ); + mbedtls_mpi_free( &m ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp_curves.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp_curves.c new file mode 100644 index 0000000000..9a6e8eb187 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ecp_curves.c @@ -0,0 +1,1325 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_4( a, b, 0, 0 ) + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + BYTES_TO_T_UINT_4( a, b, c, d ), \ + BYTES_TO_T_UINT_4( e, f, g, h ) + +#else /* 64-bits */ + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) | \ + ( (mbedtls_mpi_uint) e << 32 ) | \ + ( (mbedtls_mpi_uint) f << 40 ) | \ + ( (mbedtls_mpi_uint) g << 48 ) | \ + ( (mbedtls_mpi_uint) h << 56 ) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 ) + +#endif /* bits in mbedtls_mpi_uint */ + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp192r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static const mbedtls_mpi_uint secp192r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192r1_b[] = { + BYTES_TO_T_UINT_8( 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE ), + BYTES_TO_T_UINT_8( 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F ), + BYTES_TO_T_UINT_8( 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 ), +}; +static const mbedtls_mpi_uint secp192r1_gx[] = { + BYTES_TO_T_UINT_8( 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4 ), + BYTES_TO_T_UINT_8( 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C ), + BYTES_TO_T_UINT_8( 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 ), +}; +static const mbedtls_mpi_uint secp192r1_gy[] = { + BYTES_TO_T_UINT_8( 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73 ), + BYTES_TO_T_UINT_8( 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63 ), + BYTES_TO_T_UINT_8( 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 ), +}; +static const mbedtls_mpi_uint secp192r1_n[] = { + BYTES_TO_T_UINT_8( 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14 ), + BYTES_TO_T_UINT_8( 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +/* + * Domain parameters for secp224r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static const mbedtls_mpi_uint secp224r1_p[] = { + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224r1_b[] = { + BYTES_TO_T_UINT_8( 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27 ), + BYTES_TO_T_UINT_8( 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50 ), + BYTES_TO_T_UINT_8( 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C ), + BYTES_TO_T_UINT_4( 0x85, 0x0A, 0x05, 0xB4 ), +}; +static const mbedtls_mpi_uint secp224r1_gx[] = { + BYTES_TO_T_UINT_8( 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34 ), + BYTES_TO_T_UINT_8( 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A ), + BYTES_TO_T_UINT_8( 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B ), + BYTES_TO_T_UINT_4( 0xBD, 0x0C, 0x0E, 0xB7 ), +}; +static const mbedtls_mpi_uint secp224r1_gy[] = { + BYTES_TO_T_UINT_8( 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44 ), + BYTES_TO_T_UINT_8( 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD ), + BYTES_TO_T_UINT_8( 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5 ), + BYTES_TO_T_UINT_4( 0x88, 0x63, 0x37, 0xBD ), +}; +static const mbedtls_mpi_uint secp224r1_n[] = { + BYTES_TO_T_UINT_8( 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13 ), + BYTES_TO_T_UINT_8( 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + BYTES_TO_T_UINT_8( 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B ), + BYTES_TO_T_UINT_8( 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65 ), + BYTES_TO_T_UINT_8( 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3 ), + BYTES_TO_T_UINT_8( 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A ), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), + BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), + BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), + BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), + BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), + BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), + BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + BYTES_TO_T_UINT_8( 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3 ), + BYTES_TO_T_UINT_8( 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + BYTES_TO_T_UINT_8( 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A ), + BYTES_TO_T_UINT_8( 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6 ), + BYTES_TO_T_UINT_8( 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03 ), + BYTES_TO_T_UINT_8( 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18 ), + BYTES_TO_T_UINT_8( 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98 ), + BYTES_TO_T_UINT_8( 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 ), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + BYTES_TO_T_UINT_8( 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A ), + BYTES_TO_T_UINT_8( 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55 ), + BYTES_TO_T_UINT_8( 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59 ), + BYTES_TO_T_UINT_8( 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E ), + BYTES_TO_T_UINT_8( 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E ), + BYTES_TO_T_UINT_8( 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA ), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A ), + BYTES_TO_T_UINT_8( 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A ), + BYTES_TO_T_UINT_8( 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9 ), + BYTES_TO_T_UINT_8( 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8 ), + BYTES_TO_T_UINT_8( 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D ), + BYTES_TO_T_UINT_8( 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 ), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + BYTES_TO_T_UINT_8( 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC ), + BYTES_TO_T_UINT_8( 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58 ), + BYTES_TO_T_UINT_8( 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7 ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + BYTES_TO_T_UINT_8( 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF ), + BYTES_TO_T_UINT_8( 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35 ), + BYTES_TO_T_UINT_8( 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16 ), + BYTES_TO_T_UINT_8( 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56 ), + BYTES_TO_T_UINT_8( 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8 ), + BYTES_TO_T_UINT_8( 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2 ), + BYTES_TO_T_UINT_8( 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92 ), + BYTES_TO_T_UINT_8( 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95 ), + BYTES_TO_T_UINT_2( 0x51, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + BYTES_TO_T_UINT_8( 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9 ), + BYTES_TO_T_UINT_8( 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33 ), + BYTES_TO_T_UINT_8( 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE ), + BYTES_TO_T_UINT_8( 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1 ), + BYTES_TO_T_UINT_8( 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8 ), + BYTES_TO_T_UINT_8( 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C ), + BYTES_TO_T_UINT_8( 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E ), + BYTES_TO_T_UINT_8( 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85 ), + BYTES_TO_T_UINT_2( 0xC6, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + BYTES_TO_T_UINT_8( 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88 ), + BYTES_TO_T_UINT_8( 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35 ), + BYTES_TO_T_UINT_8( 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5 ), + BYTES_TO_T_UINT_8( 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97 ), + BYTES_TO_T_UINT_8( 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17 ), + BYTES_TO_T_UINT_8( 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98 ), + BYTES_TO_T_UINT_8( 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C ), + BYTES_TO_T_UINT_8( 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39 ), + BYTES_TO_T_UINT_2( 0x18, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + BYTES_TO_T_UINT_8( 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB ), + BYTES_TO_T_UINT_8( 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B ), + BYTES_TO_T_UINT_8( 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F ), + BYTES_TO_T_UINT_8( 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51 ), + BYTES_TO_T_UINT_8( 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static const mbedtls_mpi_uint secp192k1_p[] = { + BYTES_TO_T_UINT_8( 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_b[] = { + BYTES_TO_T_UINT_2( 0x03, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_gx[] = { + BYTES_TO_T_UINT_8( 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D ), + BYTES_TO_T_UINT_8( 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26 ), + BYTES_TO_T_UINT_8( 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB ), +}; +static const mbedtls_mpi_uint secp192k1_gy[] = { + BYTES_TO_T_UINT_8( 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40 ), + BYTES_TO_T_UINT_8( 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84 ), + BYTES_TO_T_UINT_8( 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B ), +}; +static const mbedtls_mpi_uint secp192k1_n[] = { + BYTES_TO_T_UINT_8( 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F ), + BYTES_TO_T_UINT_8( 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static const mbedtls_mpi_uint secp224k1_p[] = { + BYTES_TO_T_UINT_8( 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp224k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_b[] = { + BYTES_TO_T_UINT_2( 0x05, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_gx[] = { + BYTES_TO_T_UINT_8( 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F ), + BYTES_TO_T_UINT_8( 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69 ), + BYTES_TO_T_UINT_8( 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D ), + BYTES_TO_T_UINT_4( 0x33, 0x5B, 0x45, 0xA1 ), +}; +static const mbedtls_mpi_uint secp224k1_gy[] = { + BYTES_TO_T_UINT_8( 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2 ), + BYTES_TO_T_UINT_8( 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7 ), + BYTES_TO_T_UINT_8( 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F ), + BYTES_TO_T_UINT_4( 0xED, 0x9F, 0x08, 0x7E ), +}; +static const mbedtls_mpi_uint secp224k1_n[] = { + BYTES_TO_T_UINT_8( 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA ), + BYTES_TO_T_UINT_8( 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + BYTES_TO_T_UINT_8( 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + BYTES_TO_T_UINT_2( 0x07, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + BYTES_TO_T_UINT_8( 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59 ), + BYTES_TO_T_UINT_8( 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02 ), + BYTES_TO_T_UINT_8( 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55 ), + BYTES_TO_T_UINT_8( 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 ), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + BYTES_TO_T_UINT_8( 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C ), + BYTES_TO_T_UINT_8( 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD ), + BYTES_TO_T_UINT_8( 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D ), + BYTES_TO_T_UINT_8( 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 ), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + BYTES_TO_T_UINT_8( 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF ), + BYTES_TO_T_UINT_8( 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + BYTES_TO_T_UINT_8( 0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20 ), + BYTES_TO_T_UINT_8( 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E ), + BYTES_TO_T_UINT_8( 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + BYTES_TO_T_UINT_8( 0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9 ), + BYTES_TO_T_UINT_8( 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB ), + BYTES_TO_T_UINT_8( 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE ), + BYTES_TO_T_UINT_8( 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + BYTES_TO_T_UINT_8( 0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B ), + BYTES_TO_T_UINT_8( 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95 ), + BYTES_TO_T_UINT_8( 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3 ), + BYTES_TO_T_UINT_8( 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A ), + BYTES_TO_T_UINT_8( 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9 ), + BYTES_TO_T_UINT_8( 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C ), + BYTES_TO_T_UINT_8( 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + BYTES_TO_T_UINT_8( 0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C ), + BYTES_TO_T_UINT_8( 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2 ), + BYTES_TO_T_UINT_8( 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97 ), + BYTES_TO_T_UINT_8( 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + BYTES_TO_T_UINT_8( 0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90 ), + BYTES_TO_T_UINT_8( 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C ), + BYTES_TO_T_UINT_8( 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + BYTES_TO_T_UINT_8( 0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87 ), + BYTES_TO_T_UINT_8( 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC ), + BYTES_TO_T_UINT_8( 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12 ), + BYTES_TO_T_UINT_8( 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), + BYTES_TO_T_UINT_8( 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A ), + BYTES_TO_T_UINT_8( 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13 ), + BYTES_TO_T_UINT_8( 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2 ), + BYTES_TO_T_UINT_8( 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C ), + BYTES_TO_T_UINT_8( 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + BYTES_TO_T_UINT_8( 0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A ), + BYTES_TO_T_UINT_8( 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C ), + BYTES_TO_T_UINT_8( 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E ), + BYTES_TO_T_UINT_8( 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F ), + BYTES_TO_T_UINT_8( 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B ), + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + BYTES_TO_T_UINT_8( 0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF ), + BYTES_TO_T_UINT_8( 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8 ), + BYTES_TO_T_UINT_8( 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB ), + BYTES_TO_T_UINT_8( 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88 ), + BYTES_TO_T_UINT_8( 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2 ), + BYTES_TO_T_UINT_8( 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E ), + BYTES_TO_T_UINT_8( 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1 ), + BYTES_TO_T_UINT_8( 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62 ), + BYTES_TO_T_UINT_8( 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C ), + BYTES_TO_T_UINT_8( 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + BYTES_TO_T_UINT_8( 0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B ), + BYTES_TO_T_UINT_8( 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF ), + BYTES_TO_T_UINT_8( 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F ), + BYTES_TO_T_UINT_8( 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + BYTES_TO_T_UINT_8( 0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28 ), + BYTES_TO_T_UINT_8( 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28 ), + BYTES_TO_T_UINT_8( 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE ), + BYTES_TO_T_UINT_8( 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D ), + BYTES_TO_T_UINT_8( 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + BYTES_TO_T_UINT_8( 0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7 ), + BYTES_TO_T_UINT_8( 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F ), + BYTES_TO_T_UINT_8( 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A ), + BYTES_TO_T_UINT_8( 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D ), + BYTES_TO_T_UINT_8( 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8 ), + BYTES_TO_T_UINT_8( 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94 ), + BYTES_TO_T_UINT_8( 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2 ), + BYTES_TO_T_UINT_8( 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + BYTES_TO_T_UINT_8( 0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28 ), + BYTES_TO_T_UINT_8( 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98 ), + BYTES_TO_T_UINT_8( 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77 ), + BYTES_TO_T_UINT_8( 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B ), + BYTES_TO_T_UINT_8( 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B ), + BYTES_TO_T_UINT_8( 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8 ), + BYTES_TO_T_UINT_8( 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA ), + BYTES_TO_T_UINT_8( 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + BYTES_TO_T_UINT_8( 0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B ), + BYTES_TO_T_UINT_8( 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C ), + BYTES_TO_T_UINT_8( 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50 ), + BYTES_TO_T_UINT_8( 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF ), + BYTES_TO_T_UINT_8( 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4 ), + BYTES_TO_T_UINT_8( 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85 ), + BYTES_TO_T_UINT_8( 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A ), + BYTES_TO_T_UINT_8( 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + BYTES_TO_T_UINT_8( 0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78 ), + BYTES_TO_T_UINT_8( 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1 ), + BYTES_TO_T_UINT_8( 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B ), + BYTES_TO_T_UINT_8( 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0 ), + BYTES_TO_T_UINT_8( 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2 ), + BYTES_TO_T_UINT_8( 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0 ), + BYTES_TO_T_UINT_8( 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + BYTES_TO_T_UINT_8( 0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5 ), + BYTES_TO_T_UINT_8( 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D ), + BYTES_TO_T_UINT_8( 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41 ), + BYTES_TO_T_UINT_8( 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55 ), + BYTES_TO_T_UINT_8( 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) + */ +static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +{ + X->s = 1; + X->n = len / sizeof( mbedtls_mpi_uint ); + X->p = (mbedtls_mpi_uint *) p; +} + +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1( mbedtls_mpi *X ) +{ + static mbedtls_mpi_uint one[] = { 1 }; + X->s = 1; + X->n = 1; + X->p = one; +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load( mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen) +{ + ecp_mpi_load( &grp->P, p, plen ); + if( a != NULL ) + ecp_mpi_load( &grp->A, a, alen ); + ecp_mpi_load( &grp->B, b, blen ); + ecp_mpi_load( &grp->N, n, nlen ); + + ecp_mpi_load( &grp->G.X, gx, gxlen ); + ecp_mpi_load( &grp->G.Y, gy, gylen ); + ecp_mpi_set1( &grp->G.Z ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + grp->h = 1; + + return( 0 ); +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static int ecp_mod_p192( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static int ecp_mod_p224( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521( mbedtls_mpi * ); +#endif + +#define NIST_MODP( P ) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP( P ) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static int ecp_mod_p192k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static int ecp_mod_p224k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1( mbedtls_mpi * ); +#endif + +#define LOAD_GROUP_A( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + G ## _a, sizeof( G ## _a ), \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#define LOAD_GROUP( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + NULL, 0, \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519( mbedtls_ecp_group *grp ) +{ + int ret; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "01DB42" ) ); + + /* P = 2^255 - 19 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 255 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* Y intentionaly not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + mbedtls_ecp_group_free( grp ); + + grp->id = id; + + switch( id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + NIST_MODP( p192 ); + return( LOAD_GROUP( secp192r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + NIST_MODP( p224 ); + return( LOAD_GROUP( secp224r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP( p256 ); + return( LOAD_GROUP( secp256r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP( p384 ); + return( LOAD_GROUP( secp384r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP( p521 ); + return( LOAD_GROUP( secp521r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case MBEDTLS_ECP_DP_SECP192K1: + grp->modp = ecp_mod_p192k1; + return( LOAD_GROUP_A( secp192k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case MBEDTLS_ECP_DP_SECP224K1: + grp->modp = ecp_mod_p224k1; + return( LOAD_GROUP_A( secp224k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return( LOAD_GROUP_A( secp256k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return( LOAD_GROUP_A( brainpoolP256r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return( LOAD_GROUP_A( brainpoolP384r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return( LOAD_GROUP_A( brainpoolP512r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return( ecp_use_curve25519( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + + default: + mbedtls_ecp_group_free( grp ); + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +/* + * Compared to the way things are presented in FIPS 186-3 D.2, + * we proceed in columns, from right (least significant chunk) to left, + * adding chunks to N in place, and keeping a carry for the next chunk. + * This avoids moving things around in memory, and uselessly adding zeros, + * compared to the more straightforward, line-oriented approach. + * + * For this prime we need to handle data in chunks of 64 bits. + * Since this is always a multiple of our basic mbedtls_mpi_uint, we can + * use a mbedtls_mpi_uint * to designate such a chunk, and small loops to handle it. + */ + +/* Add 64-bit chunks (dst += src) and update carry */ +static inline void add64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *src, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + mbedtls_mpi_uint c = 0; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++, src++ ) + { + *dst += c; c = ( *dst < c ); + *dst += *src; c += ( *dst < *src ); + } + *carry += c; +} + +/* Add carry to a 64-bit chunk and update carry */ +static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++ ) + { + *dst += *carry; + *carry = ( *dst < *carry ); + } +} + +#define WIDTH 8 / sizeof( mbedtls_mpi_uint ) +#define A( i ) N->p + i * WIDTH +#define ADD( i ) add64( p, A( i ), &c ) +#define NEXT p += WIDTH; carry64( p, &c ) +#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 + +/* + * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) + */ +static int ecp_mod_p192( mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi_uint c = 0; + mbedtls_mpi_uint *p, *end; + + /* Make sure we have enough blocks so that A(5) is legal */ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, 6 * WIDTH ) ); + + p = N->p; + end = p + N->n; + + ADD( 3 ); ADD( 5 ); NEXT; // A0 += A3 + A5 + ADD( 3 ); ADD( 4 ); ADD( 5 ); NEXT; // A1 += A3 + A4 + A5 + ADD( 4 ); ADD( 5 ); LAST; // A2 += A4 + A5 + +cleanup: + return( ret ); +} + +#undef WIDTH +#undef A +#undef ADD +#undef NEXT +#undef LAST +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A( i ); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 N->n +#define A( j ) N->p[j] +#define STORE32 N->p[i] = cur; + +#else /* 64-bit */ + +#define MAX32 N->n * 2 +#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] ) +#define STORE32 \ + if( i % 2 ) { \ + N->p[i/2] &= 0x00000000FFFFFFFF; \ + N->p[i/2] |= ((mbedtls_mpi_uint) cur) << 32; \ + } else { \ + N->p[i/2] &= 0xFFFFFFFF00000000; \ + N->p[i/2] |= (mbedtls_mpi_uint) cur; \ + } + +#endif /* sizeof( mbedtls_mpi_uint ) */ + +/* + * Helpers for addition and subtraction of chunks, with signed carry. + */ +static inline void add32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *dst += src; + *carry += ( *dst < src ); +} + +static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *carry -= ( *dst < src ); + *dst -= src; +} + +#define ADD( j ) add32( &cur, A( j ), &c ); +#define SUB( j ) sub32( &cur, A( j ), &c ); + +/* + * Helpers for the main 'loop' + * (see fix_negative for the motivation of C) + */ +#define INIT( b ) \ + int ret; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = b; \ + mbedtls_mpi C; \ + mbedtls_mpi_uint Cp[ b / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ + \ + C.s = 1; \ + C.n = b / 8 / sizeof( mbedtls_mpi_uint) + 1; \ + C.p = Cp; \ + memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ + \ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, b * 2 / 8 / sizeof( mbedtls_mpi_uint ) ) ); \ + LOAD32; + +#define NEXT \ + STORE32; i++; LOAD32; \ + cc = c; c = 0; \ + if( cc < 0 ) \ + sub32( &cur, -cc, &c ); \ + else \ + add32( &cur, cc, &c ); \ + +#define LAST \ + STORE32; i++; \ + cur = c > 0 ? c : 0; STORE32; \ + cur = 0; while( ++i < MAX32 ) { STORE32; } \ + if( c < 0 ) fix_negative( N, c, &C, bits ); + +/* + * If the result is negative, we get it in the form + * c * 2^(bits + 32) + N, with c negative and N positive shorter than 'bits' + */ +static inline int fix_negative( mbedtls_mpi *N, signed char c, mbedtls_mpi *C, size_t bits ) +{ + int ret; + + /* C = - c * 2^(bits + 32) */ +#if !defined(MBEDTLS_HAVE_INT64) + ((void) bits); +#else + if( bits == 224 ) + C->p[ C->n - 1 ] = ((mbedtls_mpi_uint) -c) << 32; + else +#endif + C->p[ C->n - 1 ] = (mbedtls_mpi_uint) -c; + + /* N = - ( C - N ) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, C, N ) ); + N->s = -1; + +cleanup: + + return( ret ); +} + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +/* + * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) + */ +static int ecp_mod_p224( mbedtls_mpi *N ) +{ + INIT( 224 ); + + SUB( 7 ); SUB( 11 ); NEXT; // A0 += -A7 - A11 + SUB( 8 ); SUB( 12 ); NEXT; // A1 += -A8 - A12 + SUB( 9 ); SUB( 13 ); NEXT; // A2 += -A9 - A13 + SUB( 10 ); ADD( 7 ); ADD( 11 ); NEXT; // A3 += -A10 + A7 + A11 + SUB( 11 ); ADD( 8 ); ADD( 12 ); NEXT; // A4 += -A11 + A8 + A12 + SUB( 12 ); ADD( 9 ); ADD( 13 ); NEXT; // A5 += -A12 + A9 + A13 + SUB( 13 ); ADD( 10 ); LAST; // A6 += -A13 + A10 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256( mbedtls_mpi *N ) +{ + INIT( 256 ); + + ADD( 8 ); ADD( 9 ); + SUB( 11 ); SUB( 12 ); SUB( 13 ); SUB( 14 ); NEXT; // A0 + + ADD( 9 ); ADD( 10 ); + SUB( 12 ); SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A1 + + ADD( 10 ); ADD( 11 ); + SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A2 + + ADD( 11 ); ADD( 11 ); ADD( 12 ); ADD( 12 ); ADD( 13 ); + SUB( 15 ); SUB( 8 ); SUB( 9 ); NEXT; // A3 + + ADD( 12 ); ADD( 12 ); ADD( 13 ); ADD( 13 ); ADD( 14 ); + SUB( 9 ); SUB( 10 ); NEXT; // A4 + + ADD( 13 ); ADD( 13 ); ADD( 14 ); ADD( 14 ); ADD( 15 ); + SUB( 10 ); SUB( 11 ); NEXT; // A5 + + ADD( 14 ); ADD( 14 ); ADD( 15 ); ADD( 15 ); ADD( 14 ); ADD( 13 ); + SUB( 8 ); SUB( 9 ); NEXT; // A6 + + ADD( 15 ); ADD( 15 ); ADD( 15 ); ADD( 8 ); + SUB( 10 ); SUB( 11 ); SUB( 12 ); SUB( 13 ); LAST; // A7 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384( mbedtls_mpi *N ) +{ + INIT( 384 ); + + ADD( 12 ); ADD( 21 ); ADD( 20 ); + SUB( 23 ); NEXT; // A0 + + ADD( 13 ); ADD( 22 ); ADD( 23 ); + SUB( 12 ); SUB( 20 ); NEXT; // A2 + + ADD( 14 ); ADD( 23 ); + SUB( 13 ); SUB( 21 ); NEXT; // A2 + + ADD( 15 ); ADD( 12 ); ADD( 20 ); ADD( 21 ); + SUB( 14 ); SUB( 22 ); SUB( 23 ); NEXT; // A3 + + ADD( 21 ); ADD( 21 ); ADD( 16 ); ADD( 13 ); ADD( 12 ); ADD( 20 ); ADD( 22 ); + SUB( 15 ); SUB( 23 ); SUB( 23 ); NEXT; // A4 + + ADD( 22 ); ADD( 22 ); ADD( 17 ); ADD( 14 ); ADD( 13 ); ADD( 21 ); ADD( 23 ); + SUB( 16 ); NEXT; // A5 + + ADD( 23 ); ADD( 23 ); ADD( 18 ); ADD( 15 ); ADD( 14 ); ADD( 22 ); + SUB( 17 ); NEXT; // A6 + + ADD( 19 ); ADD( 16 ); ADD( 15 ); ADD( 23 ); + SUB( 18 ); NEXT; // A7 + + ADD( 20 ); ADD( 17 ); ADD( 16 ); + SUB( 19 ); NEXT; // A8 + + ADD( 21 ); ADD( 18 ); ADD( 17 ); + SUB( 20 ); NEXT; // A9 + + ADD( 22 ); ADD( 19 ); ADD( 18 ); + SUB( 21 ); NEXT; // A10 + + ADD( 23 ); ADD( 20 ); ADD( 19 ); + SUB( 22 ); LAST; // A11 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef A +#undef LOAD32 +#undef STORE32 +#undef MAX32 +#undef INIT +#undef NEXT +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED || + MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* + * Here we have an actual Mersenne prime, so things are more straightforward. + * However, chunks are aligned on a 'weird' boundary (521 bits). + */ + +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH ( 521 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5) + * Write N as A1 + 2^521 A0, return A0 + A1 + */ +static int ecp_mod_p521( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P521_WIDTH + 1]; + /* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits: + * we need to hold bits 513 to 1056, which is 34 limbs, that is + * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */ + + if( N->n < P521_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P521_WIDTH - 1 ); + if( M.n > P521_WIDTH + 1 ) + M.n = P521_WIDTH + 1; + M.p = Mp; + memcpy( Mp, N->p + P521_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 521 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + + /* N = A0 */ + N->p[P521_WIDTH - 1] &= P521_MASK; + for( i = P521_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} + +#undef P521_WIDTH +#undef P521_MASK +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH ( 255 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^255 A1, return A0 + 19 * A1 + */ +static int ecp_mod_p255( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P255_WIDTH + 2]; + + if( N->n < P255_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P255_WIDTH - 1 ); + if( M.n > P255_WIDTH + 1 ) + M.n = P255_WIDTH + 1; + M.p = Mp; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 255 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + M.n++; /* Make room for multiplication by 19 */ + + /* N = A0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( N, 255, 0 ) ); + for( i = P255_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + 19 * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &M, 19 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write N as A0 + 2^224 A1, return A0 + R * A1. + * Actually do two passes, since R is big. + */ +#define P_KOBLITZ_MAX ( 256 / 8 / sizeof( mbedtls_mpi_uint ) ) // Max limbs in P +#define P_KOBLITZ_R ( 8 / sizeof( mbedtls_mpi_uint ) ) // Limbs in R +static inline int ecp_mod_koblitz( mbedtls_mpi *N, mbedtls_mpi_uint *Rp, size_t p_limbs, + size_t adjust, size_t shift, mbedtls_mpi_uint mask ) +{ + int ret; + size_t i; + mbedtls_mpi M, R; + mbedtls_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R]; + + if( N->n < p_limbs ) + return( 0 ); + + /* Init R */ + R.s = 1; + R.p = Rp; + R.n = P_KOBLITZ_R; + + /* Common setup for M */ + M.s = 1; + M.p = Mp; + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n - adjust; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + + /* Second pass */ + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n - adjust; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED) || + MBEDTLS_ECP_DP_SECP224K1_ENABLED) || + MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +/* + * Fast quasi-reduction modulo p192k1 = 2^192 - R, + * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x0100001119 + */ +static int ecp_mod_p192k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xC9, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + + return( ecp_mod_koblitz( N, Rp, 192 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +/* + * Fast quasi-reduction modulo p224k1 = 2^224 - R, + * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 + */ +static int ecp_mod_p224k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0x93, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + +#if defined(MBEDTLS_HAVE_INT64) + return( ecp_mod_koblitz( N, Rp, 4, 1, 32, 0xFFFFFFFF ) ); +#else + return( ecp_mod_koblitz( N, Rp, 224 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +#endif +} + +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + return( ecp_mod_koblitz( N, Rp, 256 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy.c new file mode 100644 index 0000000000..cdbd35c34e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy.c @@ -0,0 +1,493 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_entropy_context) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_starts( &ctx->accumulator, 0 ); +#else + mbedtls_sha256_starts( &ctx->accumulator, 0 ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + +#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_TIMING_C) + mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDCLOCK, + MBEDTLS_ENTROPY_SOURCE_WEAK ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, + MBEDTLS_ENTROPY_MIN_HAVEGE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDWARE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +} + +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) +{ +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_free( &ctx->havege_data ); +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_zeroize( ctx, sizeof( mbedtls_entropy_context ) ); +} + +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ) +{ + int index, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + index = ctx->source_count; + if( index >= MBEDTLS_ENTROPY_MAX_SOURCES ) + { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[index].f_source = f_source; + ctx->source[index].p_source = p_source; + ctx->source[index].threshold = threshold; + ctx->source[index].strong = strong; + + ctx->source_count++; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Entropy accumulator update + */ +static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + + if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + { +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512( data, len, tmp, 0 ); +#else + mbedtls_sha256( data, len, tmp, 0 ); +#endif + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_update( &ctx->accumulator, header, 2 ); + mbedtls_sha512_update( &ctx->accumulator, p, use_len ); +#else + mbedtls_sha256_update( &ctx->accumulator, header, 2 ); + mbedtls_sha256_update( &ctx->accumulator, p, use_len ); +#endif + + return( 0 ); +} + +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +static int entropy_gather_internal( mbedtls_entropy_context *ctx ) +{ + int ret, i, have_one_strong = 0; + unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) + have_one_strong = 1; + + olen = 0; + if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + return( ret ); + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + entropy_update( ctx, (unsigned char) i, buf, olen ); + ctx->source[i].size += olen; + } + } + + if( have_one_strong == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE ); + + return( 0 ); +} + +/* + * Thread-safe wrapper for entropy_gather_internal() + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_gather_internal( ctx ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, done; + mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) + goto exit; + + done = 1; + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size < ctx->source[i].threshold ) + done = 0; + } + while( ! done ); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha512_context ) ); + mbedtls_sha512_starts( &ctx->accumulator, 0 ); + mbedtls_sha512_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-512 on entropy + */ + mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + mbedtls_sha256_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha256_context ) ); + mbedtls_sha256_starts( &ctx->accumulator, 0 ); + mbedtls_sha256_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-256 on entropy + */ + mbedtls_sha256( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + ret = 0; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + FILE *f; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE ) + { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE ) + n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_entropy_update_manual( ctx, buf, n ); + + return( mbedtls_entropy_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * Dummy source function + */ +static int entropy_dummy_source( void *data, unsigned char *output, + size_t len, size_t *olen ) +{ + ((void) data); + + memset( output, 0x2a, len ); + *olen = len; + + return( 0 ); +} + +/* + * The actual entropy quality is hard to test, but we can at least + * test that the functions don't cause errors and write the correct + * amount of data to buffers. + */ +int mbedtls_entropy_self_test( int verbose ) +{ + int ret = 0; + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + size_t i, j; + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY test: " ); + + mbedtls_entropy_init( &ctx ); + + /* First do a gather to make sure we have default sources */ + if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 ) + goto cleanup; + + ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16, + MBEDTLS_ENTROPY_SOURCE_WEAK ); + if( ret != 0 ) + goto cleanup; + + if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 ) + goto cleanup; + + /* + * To test that mbedtls_entropy_func writes correct number of bytes: + * - use the whole buffer and rely on ASan to detect overruns + * - collect entropy 8 times and OR the result in an accumulator: + * any byte should then be 0 with probably 2^(-64), so requiring + * each of the 32 or 64 bytes to be non-zero has a false failure rate + * of at most 2^(-58) which is acceptable. + */ + for( i = 0; i < 8; i++ ) + { + if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 ) + goto cleanup; + + for( j = 0; j < sizeof( buf ); j++ ) + acc[j] |= buf[j]; + } + + for( j = 0; j < sizeof( buf ); j++ ) + { + if( acc[j] == 0 ) + { + ret = 1; + goto cleanup; + } + } + +cleanup: + mbedtls_entropy_free( &ctx ); + + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy_poll.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy_poll.c new file mode 100644 index 0000000000..25a27bef3e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/entropy_poll.c @@ -0,0 +1,216 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#if defined(MBEDTLS_TIMING_C) +#include +#include "mbedtls/timing.h" +#endif +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Test for Linux getrandom() support. + * Since there is no wrapper in the libc yet, use the generic syscall wrapper + * available in GNU libc and compatible libc's (eg uClibc). + */ +#if defined(__linux__) && defined(__GLIBC__) +#include +#include +#if defined(SYS_getrandom) +#define HAVE_GETRANDOM + +static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) +{ + /* MemSan cannot understand that the syscall writes to the buffer */ +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset( buf, 0, buflen ); +#endif +#endif + + return( syscall( SYS_getrandom, buf, buflen, flags ) ); +} + +#include +/* Check if version is at least 3.17.0 */ +static int check_version_3_17_plus( void ) +{ + int minor; + struct utsname un; + const char *ver; + + /* Get version information */ + uname(&un); + ver = un.release; + + /* Check major version; assume a single digit */ + if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) + return( -1 ); + + if( ver[0] - '0' > 3 ) + return( 0 ); + + /* Ok, so now we know major == 3, check minor. + * Assume 1 or 2 digits. */ + if( ver[2] < '0' || ver[2] > '9' ) + return( -1 ); + + minor = ver[2] - '0'; + + if( ver[3] >= '0' && ver[3] <= '9' ) + minor = 10 * minor + ver[3] - '0'; + else if( ver [3] != '.' ) + return( -1 ); + + if( minor < 17 ) + return( -1 ); + + return( 0 ); +} +static int has_getrandom = -1; +#endif /* SYS_getrandom */ +#endif /* __linux__ */ + +#include + +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t read_len; + ((void) data); + +#if defined(HAVE_GETRANDOM) + if( has_getrandom == -1 ) + has_getrandom = ( check_version_3_17_plus() == 0 ); + + if( has_getrandom ) + { + int ret; + + if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = ret; + return( 0 ); + } +#endif /* HAVE_GETRANDOM */ + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + read_len = fread( output, 1, len, file ); + if( read_len != len ) + { + fclose( file ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ + +#if defined(MBEDTLS_TIMING_C) +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = mbedtls_timing_hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif /* MBEDTLS_TIMING_C */ + +#if defined(MBEDTLS_HAVEGE_C) +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + mbedtls_havege_state *hs = (mbedtls_havege_state *) data; + *olen = 0; + + if( mbedtls_havege_random( hs, output, len ) != 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = len; + + return( 0 ); +} +#endif /* MBEDTLS_HAVEGE_C */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/error.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/error.c new file mode 100644 index 0000000000..debda1d786 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/error.c @@ -0,0 +1,700 @@ +/* + * Error message information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY) +#include "mbedtls/error.h" +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_ERROR_C) + +#include + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_BASE64_C) +#include "mbedtls/base64.h" +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CIPHER_C) +#include "mbedtls/cipher.h" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "mbedtls/dhm.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ENTROPY_C) +#include "mbedtls/entropy.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net.h" +#endif + +#if defined(MBEDTLS_OID_C) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#endif + +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +#if defined(MBEDTLS_XTEA_C) +#include "mbedtls/xtea.h" +#endif + + +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + size_t len; + int use_ret; + + if( buflen == 0 ) + return; + + memset( buf, 0x00, buflen ); + + if( ret < 0 ) + ret = -ret; + + if( ret & 0xFF80 ) + { + use_ret = ret & 0xFF80; + + // High level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_CIPHER_C) + if( use_ret == -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Authentication failed (for AEAD modes)" ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_DHM_C) + if( use_ret == -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "DHM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the public values failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the public value failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "DHM - The ASN.1 data is not formatted correctly" ); + if( use_ret == -(MBEDTLS_ERR_DHM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "DHM - Read/write of file failed" ); +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_ECP_C) + if( use_ret == -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ECP - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ECP - Requested curve not available" ); + if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); + if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as (ephemeral) key, failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) + mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); + if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ECP - Signature is valid but shorter than the user-supplied length" ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) + if( use_ret == -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "MD - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_MD_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "MD - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MD_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_MD_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "MD - Opening or reading of file failed" ); +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + if( use_ret == -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) ) + mbedtls_snprintf( buf, buflen, "PEM - No PEM header or footer found" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - PEM string is not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PEM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PEM - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_ENC_IV) ) + mbedtls_snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" ); + if( use_ret == -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG) ) + mbedtls_snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PEM - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - Bad input parameters to function" ); +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ + +#if defined(MBEDTLS_PK_C) + if( use_ret == -(MBEDTLS_ERR_PK_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Type mismatch, eg attempt to encrypt with an ECDSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PK - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PK_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "PK - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "PK - Unsupported key version" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid key tag or value" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - Key algorithm is unsupported (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PK - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_PUBKEY) ) + mbedtls_snprintf( buf, buflen, "PK - The pubkey tag or value is invalid (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE) ) + mbedtls_snprintf( buf, buflen, "PK - Elliptic curve is unsupported (only NIST curves are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" ); +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_PKCS12_C) + if( use_ret == -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS12_C */ + +#if defined(MBEDTLS_PKCS5_C) + if( use_ret == -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS5_C */ + +#if defined(MBEDTLS_RSA_C) + if( use_ret == -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "RSA - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_RSA_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Something failed during generation of a key" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Key failed to pass the library's validity check" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The public key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PRIVATE_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The private key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" ); + if( use_ret == -(MBEDTLS_ERR_RSA_RNG_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_SSL_TLS_C) + if( use_ret == -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "SSL - The requested feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SSL - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_MAC) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of the message MAC failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - An invalid SSL record was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONN_EOF) ) + mbedtls_snprintf( buf, buflen, "SSL - The connection indicated an EOF" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) ) + mbedtls_snprintf( buf, buflen, "SSL - An unknown cipher was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) ) + mbedtls_snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_RNG) ) + mbedtls_snprintf( buf, buflen, "SSL - No RNG was provided to the SSL module" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Our own certificate(s) is/are too large to send in an SSL message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own private key or pre-shared key is not set, but needed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" ); + if( use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) ) + { + mbedtls_snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" ); + return; + } + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of our peer failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) + mbedtls_snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - Session ticket has expired" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "SSL - Public key type mismatch (eg, asked for RSA key exchange and presented EC key)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) ) + mbedtls_snprintf( buf, buflen, "SSL - Unknown identity received (eg, PSK identity)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INTERNAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal error (eg, unexpected failure in lower-level module)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING) ) + mbedtls_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) ) + mbedtls_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) + mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a read call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) + mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT) ) + mbedtls_snprintf( buf, buflen, "SSL - The client initiated a reconnect from the same port" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - Record header looks valid but is not expected" ); +#endif /* MBEDTLS_SSL_TLS_C */ + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) + if( use_ret == -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_OID) ) + mbedtls_snprintf( buf, buflen, "X509 - Requested OID is unknown" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR version element is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SERIAL) ) + mbedtls_snprintf( buf, buflen, "X509 - The serial tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_NAME) ) + mbedtls_snprintf( buf, buflen, "X509 - The name tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_DATE) ) + mbedtls_snprintf( buf, buflen, "X509 - The date tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "X509 - The signature tag or value invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_EXTENSIONS) ) + mbedtls_snprintf( buf, buflen, "X509 - The extension tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - CRT/CRL/CSR has an unsupported version number" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" ); + if( use_ret == -(MBEDTLS_ERR_X509_SIG_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithms do not match. (see \\c ::mbedtls_x509_crt sig_oid)" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" ); + if( use_ret == -(MBEDTLS_ERR_X509_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "X509 - Input invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + // END generated code + + if( strlen( buf ) == 0 ) + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); + } + + use_ret = ret & ~0xFF80; + + if( use_ret == 0 ) + return; + + // If high level code is present, make a concatenation between both + // error strings. + // + len = strlen( buf ); + + if( len > 0 ) + { + if( buflen - len < 5 ) + return; + + mbedtls_snprintf( buf + len, buflen - len, " : " ); + + buf += len + 3; + buflen -= len + 3; + } + + // Low level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_AES_C) + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ASN1_PARSE_C) + if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) ) + mbedtls_snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_BASE64_C) + if( use_ret == -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Invalid character in input" ); +#endif /* MBEDTLS_BASE64_C */ + +#if defined(MBEDTLS_BIGNUM_C) + if( use_ret == -(MBEDTLS_ERR_MPI_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MPI_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" ); + if( use_ret == -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" ); + if( use_ret == -(MBEDTLS_ERR_MPI_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Memory allocation failed" ); +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_CCM_C) + if( use_ret == -(MBEDTLS_ERR_CCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "CCM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_CCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - Authenticated decryption failed" ); +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_CTR_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Read/write error in file" ); +#endif /* MBEDTLS_CTR_DRBG_C */ + +#if defined(MBEDTLS_DES_C) + if( use_ret == -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "DES - The data input has an invalid length" ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ENTROPY_C) + if( use_ret == -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No more sources can be added" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No strong sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Read/write error in file" ); +#endif /* MBEDTLS_ENTROPY_C */ + +#if defined(MBEDTLS_GCM_C) + if( use_ret == -(MBEDTLS_ERR_GCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_HMAC_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Read/write error in file" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - The entropy source failed" ); +#endif /* MBEDTLS_HMAC_DRBG_C */ + +#if defined(MBEDTLS_NET_C) + if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" ); + if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) ) + mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" ); + if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" ); + if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); + if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); +#endif /* MBEDTLS_NET_C */ + +#if defined(MBEDTLS_OID_C) + if( use_ret == -(MBEDTLS_ERR_OID_NOT_FOUND) ) + mbedtls_snprintf( buf, buflen, "OID - OID is not found" ); + if( use_ret == -(MBEDTLS_ERR_OID_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "OID - output buffer is too small" ); +#endif /* MBEDTLS_OID_C */ + +#if defined(MBEDTLS_PADLOCK_C) + if( use_ret == -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED) ) + mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); +#endif /* MBEDTLS_PADLOCK_C */ + +#if defined(MBEDTLS_THREADING_C) + if( use_ret == -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "THREADING - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "THREADING - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_MUTEX_ERROR) ) + mbedtls_snprintf( buf, buflen, "THREADING - Locking / unlocking / free failed with error code" ); +#endif /* MBEDTLS_THREADING_C */ + +#if defined(MBEDTLS_XTEA_C) + if( use_ret == -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "XTEA - The data input has an invalid length" ); +#endif /* MBEDTLS_XTEA_C */ + // END generated code + + if( strlen( buf ) != 0 ) + return; + + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); +} + +#else /* MBEDTLS_ERROR_C */ + +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + +/* + * Provide an non-function in case MBEDTLS_ERROR_C is not defined + */ +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + ((void) ret); + + if( buflen > 0 ) + buf[0] = '\0'; +} + +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ + +#endif /* MBEDTLS_ERROR_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/gcm.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/gcm.c new file mode 100644 index 0000000000..aaacf97d61 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/gcm.c @@ -0,0 +1,953 @@ +/* + * NIST SP800-38D compliant GCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + * See also: + * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf + * + * We use the algorithm described as Shoup's method with 4-bit tables in + * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_GCM_C) + +#include "mbedtls/gcm.h" + +#include + +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize a context + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_gcm_context ) ); +} + +/* + * Precompute small multiples of H, that is set + * HH[i] || HL[i] = H times i, + * where i is seen as a field element as in [MGV], ie high-order bits + * correspond to low powers of P. The result is stored in the same way, that + * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL + * corresponds to P^127. + */ +static int gcm_gen_table( mbedtls_gcm_context *ctx ) +{ + int ret, i, j; + uint64_t hi, lo; + uint64_t vl, vh; + unsigned char h[16]; + size_t olen = 0; + + memset( h, 0, 16 ); + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, h, 16, h, &olen ) ) != 0 ) + return( ret ); + + /* pack h as two 64-bits ints, big-endian */ + GET_UINT32_BE( hi, h, 0 ); + GET_UINT32_BE( lo, h, 4 ); + vh = (uint64_t) hi << 32 | lo; + + GET_UINT32_BE( hi, h, 8 ); + GET_UINT32_BE( lo, h, 12 ); + vl = (uint64_t) hi << 32 | lo; + + /* 8 = 1000 corresponds to 1 in GF(2^128) */ + ctx->HL[8] = vl; + ctx->HH[8] = vh; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + /* With CLMUL support, we need only h, not the rest of the table */ + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) + return( 0 ); +#endif + + /* 0 corresponds to 0 in GF(2^128) */ + ctx->HH[0] = 0; + ctx->HL[0] = 0; + + for( i = 4; i > 0; i >>= 1 ) + { + uint32_t T = ( vl & 1 ) * 0xe1000000U; + vl = ( vh << 63 ) | ( vl >> 1 ); + vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); + + ctx->HL[i] = vl; + ctx->HH[i] = vh; + } + + for( i = 2; i <= 8; i *= 2 ) + { + uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; + vh = *HiH; + vl = *HiL; + for( j = 1; j < i; j++ ) + { + HiH[j] = vh ^ ctx->HH[j]; + HiL[j] = vl ^ ctx->HL[j]; + } + } + + return( 0 ); +} + +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = gcm_gen_table( ctx ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Shoup's method for multiplication use this table with + * last4[x] = x times P^128 + * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] + */ +static const uint64_t last4[16] = +{ + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; + +/* + * Sets output to x times H using the precomputed tables. + * x and output are seen as elements of GF(2^128) as in [MGV]. + */ +static void gcm_mult( mbedtls_gcm_context *ctx, const unsigned char x[16], + unsigned char output[16] ) +{ + int i = 0; + unsigned char lo, hi, rem; + uint64_t zh, zl; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) { + unsigned char h[16]; + + PUT_UINT32_BE( ctx->HH[8] >> 32, h, 0 ); + PUT_UINT32_BE( ctx->HH[8], h, 4 ); + PUT_UINT32_BE( ctx->HL[8] >> 32, h, 8 ); + PUT_UINT32_BE( ctx->HL[8], h, 12 ); + + mbedtls_aesni_gcm_mult( output, x, h ); + return; + } +#endif /* MBEDTLS_AESNI_C && MBEDTLS_HAVE_X86_64 */ + + lo = x[15] & 0xf; + + zh = ctx->HH[lo]; + zl = ctx->HL[lo]; + + for( i = 15; i >= 0; i-- ) + { + lo = x[i] & 0xf; + hi = x[i] >> 4; + + if( i != 15 ) + { + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[lo]; + zl ^= ctx->HL[lo]; + + } + + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[hi]; + zl ^= ctx->HL[hi]; + } + + PUT_UINT32_BE( zh >> 32, output, 0 ); + PUT_UINT32_BE( zh, output, 4 ); + PUT_UINT32_BE( zl >> 32, output, 8 ); + PUT_UINT32_BE( zl, output, 12 ); +} + +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ) +{ + int ret; + unsigned char work_buf[16]; + size_t i; + const unsigned char *p; + size_t use_len, olen = 0; + + /* IV and AD are limited to 2^64 bits, so 2^61 bytes */ + if( ( (uint64_t) iv_len ) >> 61 != 0 || + ( (uint64_t) add_len ) >> 61 != 0 ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + memset( ctx->y, 0x00, sizeof(ctx->y) ); + memset( ctx->buf, 0x00, sizeof(ctx->buf) ); + + ctx->mode = mode; + ctx->len = 0; + ctx->add_len = 0; + + if( iv_len == 12 ) + { + memcpy( ctx->y, iv, iv_len ); + ctx->y[15] = 1; + } + else + { + memset( work_buf, 0x00, 16 ); + PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); + + p = iv; + while( iv_len > 0 ) + { + use_len = ( iv_len < 16 ) ? iv_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->y[i] ^= p[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + + iv_len -= use_len; + p += use_len; + } + + for( i = 0; i < 16; i++ ) + ctx->y[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + } + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr, + &olen ) ) != 0 ) + { + return( ret ); + } + + ctx->add_len = add_len; + p = add; + while( add_len > 0 ) + { + use_len = ( add_len < 16 ) ? add_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->buf[i] ^= p[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + add_len -= use_len; + p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char ectr[16]; + size_t i; + const unsigned char *p; + unsigned char *out_p = output; + size_t use_len, olen = 0; + + if( output > input && (size_t) ( output - input ) < length ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes + * Also check for possible overflow */ + if( ctx->len + length < ctx->len || + (uint64_t) ctx->len + length > 0xFFFFFFFE0ull ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + ctx->len += length; + + p = input; + while( length > 0 ) + { + use_len = ( length < 16 ) ? length : 16; + + for( i = 16; i > 12; i-- ) + if( ++ctx->y[i - 1] != 0 ) + break; + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr, + &olen ) ) != 0 ) + { + return( ret ); + } + + for( i = 0; i < use_len; i++ ) + { + if( ctx->mode == MBEDTLS_GCM_DECRYPT ) + ctx->buf[i] ^= p[i]; + out_p[i] = ectr[i] ^ p[i]; + if( ctx->mode == MBEDTLS_GCM_ENCRYPT ) + ctx->buf[i] ^= out_p[i]; + } + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + length -= use_len; + p += use_len; + out_p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ) +{ + unsigned char work_buf[16]; + size_t i; + uint64_t orig_len = ctx->len * 8; + uint64_t orig_add_len = ctx->add_len * 8; + + if( tag_len > 16 || tag_len < 4 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + if( tag_len != 0 ) + memcpy( tag, ctx->base_ectr, tag_len ); + + if( orig_len || orig_add_len ) + { + memset( work_buf, 0x00, 16 ); + + PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 ); + PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 ); + PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 ); + PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); + + for( i = 0; i < 16; i++ ) + ctx->buf[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + for( i = 0; i < tag_len; i++ ) + tag[i] ^= ctx->buf[i]; + } + + return( 0 ); +} + +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret; + + if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_update( ctx, length, input, output ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_finish( ctx, tag, tag_len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + + if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag_len, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_zeroize( output, length ); + return( MBEDTLS_ERR_GCM_AUTH_FAILED ); + } + + return( 0 ); +} + +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * AES-GCM test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + */ +#define MAX_TESTS 6 + +static const int key_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char key[MAX_TESTS][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, +}; + +static const size_t iv_len[MAX_TESTS] = + { 12, 12, 12, 12, 8, 60 }; + +static const int iv_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 2 }; + +static const unsigned char iv[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, + 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, + 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, + 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, + 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, + 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, + 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, + 0xa6, 0x37, 0xb3, 0x9b }, +}; + +static const size_t add_len[MAX_TESTS] = + { 0, 0, 0, 20, 20, 20 }; + +static const int add_index[MAX_TESTS] = + { 0, 0, 0, 1, 1, 1 }; + +static const unsigned char additional[MAX_TESTS][64] = +{ + { 0x00 }, + { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, +}; + +static const size_t pt_len[MAX_TESTS] = + { 0, 16, 64, 60, 60, 60 }; + +static const int pt_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char pt[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, +}; + +static const unsigned char ct[MAX_TESTS * 3][64] = +{ + { 0x00 }, + { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 }, + { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, + 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, + 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, + 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, + 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, + 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, + 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, + 0xc2, 0x3f, 0x45, 0x98 }, + { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, + 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, + 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, + 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, + 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, + 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, + 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, + 0x4c, 0x34, 0xae, 0xe5 }, + { 0x00 }, + { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10 }, + { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, + 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, + 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, + 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, + 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, + 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, + 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, + 0xa0, 0xf0, 0x62, 0xf7 }, + { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, + 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, + 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, + 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, + 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, + 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, + 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, + 0xe9, 0xb7, 0x37, 0x3b }, + { 0x00 }, + { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 }, + { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, + 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, + 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, + 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, + 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, + 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, + 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, + 0xf4, 0x7c, 0x9b, 0x1f }, + { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, + 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, + 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, + 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, + 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, + 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, + 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, + 0x44, 0xae, 0x7e, 0x3f }, +}; + +static const unsigned char tag[MAX_TESTS * 3][16] = +{ + { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, + 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }, + { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, + 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }, + { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, + 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 }, + { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, + 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 }, + { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, + 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 }, + { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, + 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a }, +}; + +int mbedtls_gcm_self_test( int verbose ) +{ + mbedtls_gcm_context ctx; + unsigned char buf[64]; + unsigned char tag_buf[16]; + int i, j, ret; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + + mbedtls_gcm_init( &ctx ); + + for( j = 0; j < 3; j++ ) + { + int key_len = 128 + 64 * j; + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + pt[pt_index[i]], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + ct[j * 6 + i], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + } + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_GCM_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/havege.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/havege.c new file mode 100644 index 0000000000..7623bc0676 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/havege.c @@ -0,0 +1,243 @@ +/** + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The HAVEGE RNG was designed by Andre Seznec in 2002. + * + * http://www.irisa.fr/caps/projects/hipsor/publi.php + * + * Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVEGE_C) + +#include "mbedtls/havege.h" +#include "mbedtls/timing.h" + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* ------------------------------------------------------------------------ + * On average, one iteration accesses two 8-word blocks in the havege WALK + * table, and generates 16 words in the RES array. + * + * The data read in the WALK table is updated and permuted after each use. + * The result of the hardware clock counter read is used for this update. + * + * 25 conditional tests are present. The conditional tests are grouped in + * two nested groups of 12 conditional tests and 1 test that controls the + * permutation; on average, there should be 6 tests executed and 3 of them + * should be mispredicted. + * ------------------------------------------------------------------------ + */ + +#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } + +#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; +#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; + +#define TST1_LEAVE U1++; } +#define TST2_LEAVE U2++; } + +#define ONE_ITERATION \ + \ + PTEST = PT1 >> 20; \ + \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + \ + PTX = (PT1 >> 18) & 7; \ + PT1 &= 0x1FFF; \ + PT2 &= 0x1FFF; \ + CLK = (int) mbedtls_timing_hardclock(); \ + \ + i = 0; \ + A = &WALK[PT1 ]; RES[i++] ^= *A; \ + B = &WALK[PT2 ]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \ + \ + IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \ + *A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \ + *B = IN ^ U1; \ + *C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \ + *D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \ + \ + if( PTEST & 1 ) SWAP( A, C ); \ + \ + IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ + *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ + *B = IN; CLK = (int) mbedtls_timing_hardclock(); \ + *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ + *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 4]; \ + B = &WALK[PT2 ^ 1]; \ + \ + PTEST = PT2 >> 1; \ + \ + PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \ + PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \ + PTY = (PT2 >> 10) & 7; \ + \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + \ + C = &WALK[PT1 ^ 5]; \ + D = &WALK[PT2 ^ 5]; \ + \ + RES[i++] ^= *A; \ + RES[i++] ^= *B; \ + RES[i++] ^= *C; \ + RES[i++] ^= *D; \ + \ + IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \ + *A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \ + *B = IN ^ U2; \ + *C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \ + *D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \ + \ + IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \ + *A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \ + *B = IN; \ + *C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \ + *D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \ + \ + PT1 = ( RES[( i - 8 ) ^ PTX] ^ \ + WALK[PT1 ^ PTX ^ 7] ) & (~1); \ + PT1 ^= (PT2 ^ 0x10) & 0x10; \ + \ + for( n++, i = 0; i < 16; i++ ) \ + hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; + +/* + * Entropy gathering function + */ +static void havege_fill( mbedtls_havege_state *hs ) +{ + int i, n = 0; + int U1, U2, *A, *B, *C, *D; + int PT1, PT2, *WALK, RES[16]; + int PTX, PTY, CLK, PTEST, IN; + + WALK = hs->WALK; + PT1 = hs->PT1; + PT2 = hs->PT2; + + PTX = U1 = 0; + PTY = U2 = 0; + + memset( RES, 0, sizeof( RES ) ); + + while( n < MBEDTLS_HAVEGE_COLLECT_SIZE * 4 ) + { + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + } + + hs->PT1 = PT1; + hs->PT2 = PT2; + + hs->offset[0] = 0; + hs->offset[1] = MBEDTLS_HAVEGE_COLLECT_SIZE / 2; +} + +/* + * HAVEGE initialization + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ) +{ + memset( hs, 0, sizeof( mbedtls_havege_state ) ); + + havege_fill( hs ); +} + +void mbedtls_havege_free( mbedtls_havege_state *hs ) +{ + if( hs == NULL ) + return; + + mbedtls_zeroize( hs, sizeof( mbedtls_havege_state ) ); +} + +/* + * HAVEGE rand function + */ +int mbedtls_havege_random( void *p_rng, unsigned char *buf, size_t len ) +{ + int val; + size_t use_len; + mbedtls_havege_state *hs = (mbedtls_havege_state *) p_rng; + unsigned char *p = buf; + + while( len > 0 ) + { + use_len = len; + if( use_len > sizeof(int) ) + use_len = sizeof(int); + + if( hs->offset[1] >= MBEDTLS_HAVEGE_COLLECT_SIZE ) + havege_fill( hs ); + + val = hs->pool[hs->offset[0]++]; + val ^= hs->pool[hs->offset[1]++]; + + memcpy( p, &val, use_len ); + + len -= use_len; + p += use_len; + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVEGE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/hmac_drbg.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/hmac_drbg.c new file mode 100644 index 0000000000..bf5f9b5bd3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/hmac_drbg.c @@ -0,0 +1,529 @@ +/* + * HMAC_DRBG implementation (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The NIST SP 800-90A DRBGs are described in the following publication. + * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + * References below are based on rev. 1 (January 2012). + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/hmac_drbg.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * HMAC_DRBG context initialization + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * HMAC_DRBG update, using optional additional data (10.1.2.2) + */ +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; + unsigned char sep[1]; + unsigned char K[MBEDTLS_MD_MAX_SIZE]; + + for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) + { + /* Step 1 or 4 */ + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ); + if( rounds == 2 ) + mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, K ); + + /* Step 2 or 5 */ + mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + } +} + +/* + * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ) +{ + int ret; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); + memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); + + mbedtls_hmac_drbg_update( ctx, data, data_len ); + + return( 0 ); +} + +/* + * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; + size_t seedlen; + + /* III. Check input length */ + if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || + ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) + { + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); + + /* IV. Gather entropy_len bytes of entropy for the seed */ + if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 ) + return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + + seedlen = ctx->entropy_len; + + /* 1. Concatenate entropy and additional data if any */ + if( additional != NULL && len != 0 ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* 2. Update state */ + mbedtls_hmac_drbg_update( ctx, seed, seedlen ); + + /* 3. Reset reseed_counter */ + ctx->reseed_counter = 1; + + /* 4. Done */ + return( 0 ); +} + +/* + * HMAC_DRBG initialisation (10.1.2.3 + 9.1) + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + int ret; + size_t entropy_len, md_size; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + md_size = mbedtls_md_get_size( md_info ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ); + memset( ctx->V, 0x01, md_size ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL; + + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + * + * (This also matches the sizes used in the NIST test vectors.) + */ + entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ + md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ + 32; /* better (256+) -> 256 bits */ + + /* + * For initialisation, use more entropy to emulate a nonce + * (Again, matches test vectors.) + */ + ctx->entropy_len = entropy_len * 3 / 2; + + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + ctx->entropy_len = entropy_len; + + return( 0 ); +} + +/* + * Set prediction resistance + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +/* + * Set entropy length grabbed for reseeds + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +/* + * Set reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +/* + * HMAC_DRBG random function with optional additional data: + * 10.1.2.5 (arabic) + 9.3 (Roman) + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t out_len, + const unsigned char *additional, size_t add_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + size_t left = out_len; + unsigned char *out = output; + + /* II. Check request length */ + if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG ); + + /* III. Check input length */ + if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + + /* 1. (aka VII and IX) Check reseed counter and PR */ + if( ctx->f_entropy != NULL && /* For no-reseeding instances */ + ( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON || + ctx->reseed_counter > ctx->reseed_interval ) ) + { + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; /* VII.4 */ + } + + /* 2. Use additional data if any */ + if( additional != NULL && add_len != 0 ) + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 3, 4, 5. Generate bytes */ + while( left != 0 ) + { + size_t use_len = left > md_len ? md_len : left; + + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + + memcpy( out, ctx->V, use_len ); + out += use_len; + left -= use_len; + } + + /* 6. Update */ + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 7. Update reseed counter */ + ctx->reseed_counter++; + + /* 8. Done */ + return( 0 ); +} + +/* + * HMAC_DRBG random function + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free an HMAC_DRBG context + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_md_free( &ctx->md_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + int ret; + FILE *f; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) ) + { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_hmac_drbg_update( ctx, buf, n ); + + return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +/* Dummy checkup routine */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +#define OUTPUT_LEN 80 + +/* From a NIST PR=true test vector */ +static const unsigned char entropy_pr[] = { + 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, + 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11, + 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, + 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, + 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 }; +static const unsigned char result_pr[OUTPUT_LEN] = { + 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39, + 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94, + 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, + 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, + 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab, + 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3, + 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 }; + +/* From a NIST PR=false test vector */ +static const unsigned char entropy_nopr[] = { + 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66, + 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8, + 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3, + 0xe9, 0x9d, 0xfe, 0xdf }; +static const unsigned char result_nopr[OUTPUT_LEN] = { + 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f, + 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6, + 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a, + 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec, + 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd, + 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49, + 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 }; + +/* "Entropy" from buffer */ +static size_t test_offset; +static int hmac_drbg_self_test_entropy( void *data, + unsigned char *buf, size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine for HMAC_DRBG with SHA-1 + */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + mbedtls_hmac_drbg_context ctx; + unsigned char buf[OUTPUT_LEN]; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + + mbedtls_hmac_drbg_init( &ctx ); + + /* + * PR = True + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = True) : " ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_pr, + NULL, 0 ) ); + mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_pr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * PR = False + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = False) : " ); + + mbedtls_hmac_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_nopr, + NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_HMAC_DRBG_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md.c new file mode 100644 index 0000000000..9c2ab6fc99 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md.c @@ -0,0 +1,471 @@ +/** + * \file mbedtls_md.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md.h" +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Reminder: update profiles in x509_crt.c when adding a new hash! + */ +static const int supported_digests[] ICACHE_RODATA_ATTR = { + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif + +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + MBEDTLS_MD_RIPEMD160, +#endif + +#if defined(MBEDTLS_MD5_C) + MBEDTLS_MD_MD5, +#endif + +#if defined(MBEDTLS_MD4_C) + MBEDTLS_MD_MD4, +#endif + +#if defined(MBEDTLS_MD2_C) + MBEDTLS_MD_MD2, +#endif + + MBEDTLS_MD_NONE +}; + +const int *mbedtls_md_list( void ) +{ + return( supported_digests ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return( NULL ); + + /* Get the appropriate digest information */ +#if defined(MBEDTLS_MD2_C) + if( !strcmp( "MD2", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 ); +#endif +#if defined(MBEDTLS_MD4_C) + if( !strcmp( "MD4", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 ); +#endif +#if defined(MBEDTLS_MD5_C) + if( !strcmp( "MD5", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + if( !strcmp( "RIPEMD160", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 ); +#endif +#if defined(MBEDTLS_SHA1_C) + if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + if( !strcmp( "SHA224", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 ); + if( !strcmp( "SHA256", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + if( !strcmp( "SHA384", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 ); + if( !strcmp( "SHA512", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); +#endif + return( NULL ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ) +{ + switch( md_type ) + { +#if defined(MBEDTLS_MD2_C) + case MBEDTLS_MD_MD2: + return( &mbedtls_md2_info ); +#endif +#if defined(MBEDTLS_MD4_C) + case MBEDTLS_MD_MD4: + return( &mbedtls_md4_info ); +#endif +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( &mbedtls_md5_info ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case MBEDTLS_MD_RIPEMD160: + return( &mbedtls_ripemd160_info ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( &mbedtls_sha1_info ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( &mbedtls_sha224_info ); + case MBEDTLS_MD_SHA256: + return( &mbedtls_sha256_info ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( &mbedtls_sha384_info ); + case MBEDTLS_MD_SHA512: + return( &mbedtls_sha512_info ); +#endif + default: + return( NULL ); + } +} + +void mbedtls_md_init( mbedtls_md_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md_context_t ) ); +} + +void mbedtls_md_free( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return; + + if( ctx->md_ctx != NULL ) + ctx->md_info->ctx_free_func( ctx->md_ctx ); + + if( ctx->hmac_ctx != NULL ) + { + mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); +} + +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ) +{ + if( dst == NULL || dst->md_info == NULL || + src == NULL || src->md_info == NULL || + dst->md_info != src->md_info ) + { + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + } + + dst->md_info->clone_func( dst->md_ctx, src->md_ctx ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) +{ + return mbedtls_md_setup( ctx, md_info, 1 ); +} +#endif + +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ) +{ + if( md_info == NULL || ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + + if( hmac != 0 ) + { + ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size ); + if( ctx->hmac_ctx == NULL ) + { + md_info->ctx_free_func( ctx->md_ctx ); + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + } + } + + ctx->md_info = md_info; + + return( 0 ); +} + +int mbedtls_md_starts( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->starts_func( ctx->md_ctx ); + + return( 0 ); +} + +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + md_info->digest_func( input, ilen, output ); + + return( 0 ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ) +{ + int ret; + FILE *f; + size_t n; + mbedtls_md_context_t ctx; + unsigned char buf[1024]; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_MD_FILE_IO_ERROR ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + goto cleanup; + + md_info->starts_func( ctx.md_ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md_info->update_func( ctx.md_ctx, buf, n ); + + if( ferror( f ) != 0 ) + { + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + goto cleanup; + } + + md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + fclose( f ); + mbedtls_md_free( &ctx ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + unsigned char sum[MBEDTLS_MD_MAX_SIZE]; + unsigned char *ipad, *opad; + size_t i; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( keylen > (size_t) ctx->md_info->block_size ) + { + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, key, keylen ); + ctx->md_info->finish_func( ctx->md_ctx, sum ); + + keylen = ctx->md_info->size; + key = sum; + } + + ipad = (unsigned char *) ctx->hmac_ctx; + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + memset( ipad, 0x36, ctx->md_info->block_size ); + memset( opad, 0x5C, ctx->md_info->block_size ); + + for( i = 0; i < keylen; i++ ) + { + ipad[i] = (unsigned char)( ipad[i] ^ key[i] ); + opad[i] = (unsigned char)( opad[i] ^ key[i] ); + } + + mbedtls_zeroize( sum, sizeof( sum ) ); + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; + unsigned char *opad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + ctx->md_info->finish_func( ctx->md_ctx, tmp ); + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, opad, ctx->md_info->block_size ); + ctx->md_info->update_func( ctx->md_ctx, tmp, ctx->md_info->size ); + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + unsigned char *ipad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ipad = (unsigned char *) ctx->hmac_ctx; + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_md_context_t ctx; + int ret; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &ctx, key, keylen ); + mbedtls_md_hmac_update( &ctx, input, ilen ); + mbedtls_md_hmac_finish( &ctx, output ); + + mbedtls_md_free( &ctx ); + + return( 0 ); +} + +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->process_func( ctx->md_ctx, data ); + + return( 0 ); +} + +int mbedtls_md_get_size( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( MBEDTLS_MD_NONE ); + + return md_info->type; +} + +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} + +#endif /* MBEDTLS_MD_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md2.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md2.c new file mode 100644 index 0000000000..8976701312 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md2.c @@ -0,0 +1,288 @@ +/* + * RFC 1115/1319 compliant MD2 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD2 algorithm was designed by Ron Rivest in 1989. + * + * http://www.ietf.org/rfc/rfc1115.txt + * http://www.ietf.org/rfc/rfc1319.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD2_C) + +#include "mbedtls/md2.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD2_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static const unsigned char PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +void mbedtls_md2_init( mbedtls_md2_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_free( mbedtls_md2_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ) +{ + *dst = *src; +} + +/* + * MD2 context setup + */ +void mbedtls_md2_starts( mbedtls_md2_context *ctx ) +{ + memset( ctx->cksum, 0, 16 ); + memset( ctx->state, 0, 46 ); + memset( ctx->buffer, 0, 16 ); + ctx->left = 0; +} + +#if !defined(MBEDTLS_MD2_PROCESS_ALT) +void mbedtls_md2_process( mbedtls_md2_context *ctx ) +{ + int i, j; + unsigned char t = 0; + + for( i = 0; i < 16; i++ ) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = + (unsigned char)( ctx->buffer[i] ^ ctx->state[i]); + } + + for( i = 0; i < 18; i++ ) + { + for( j = 0; j < 48; j++ ) + { + ctx->state[j] = (unsigned char) + ( ctx->state[j] ^ PI_SUBST[t] ); + t = ctx->state[j]; + } + + t = (unsigned char)( t + i ); + } + + t = ctx->cksum[15]; + + for( i = 0; i < 16; i++ ) + { + ctx->cksum[i] = (unsigned char) + ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] ); + t = ctx->cksum[i]; + } +} +#endif /* !MBEDTLS_MD2_PROCESS_ALT */ + +/* + * MD2 process buffer + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + + while( ilen > 0 ) + { + if( ctx->left + ilen > 16 ) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy( ctx->buffer + ctx->left, input, fill ); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if( ctx->left == 16 ) + { + ctx->left = 0; + mbedtls_md2_process( ctx ); + } + } +} + +/* + * MD2 final digest + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ) +{ + size_t i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + mbedtls_md2_process( ctx ); + + memcpy( ctx->buffer, ctx->cksum, 16 ); + mbedtls_md2_process( ctx ); + + memcpy( output, ctx->state, 16 ); +} + +#endif /* !MBEDTLS_MD2_ALT */ + +/* + * output = MD2( input buffer ) + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md2_context ctx; + + mbedtls_md2_init( &ctx ); + mbedtls_md2_starts( &ctx ); + mbedtls_md2_update( &ctx, input, ilen ); + mbedtls_md2_finish( &ctx, output ); + mbedtls_md2_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1319 test vectors + */ +static const char md2_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md2_test_sum[7][16] = +{ + { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D, + 0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 }, + { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72, + 0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 }, + { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B, + 0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB }, + { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B, + 0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 }, + { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB, + 0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B }, + { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39, + 0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD }, + { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D, + 0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 } +}; + +/* + * Checkup routine + */ +int mbedtls_md2_self_test( int verbose ) +{ + int i; + unsigned char md2sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD2 test #%d: ", i + 1 ); + + mbedtls_md2( (unsigned char *) md2_test_str[i], + strlen( md2_test_str[i] ), md2sum ); + + if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD2_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md4.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md4.c new file mode 100644 index 0000000000..11a77e3ae4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md4.c @@ -0,0 +1,384 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD4_C) + +#include "mbedtls/md4.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD4_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md4_init( mbedtls_md4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_free( mbedtls_md4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ) +{ + *dst = *src; +} + +/* + * MD4 context setup + */ +void mbedtls_md4_starts( mbedtls_md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +#if !defined(MBEDTLS_MD4_PROCESS_ALT) +void mbedtls_md4_process( mbedtls_md4_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} +#endif /* !MBEDTLS_MD4_PROCESS_ALT */ + +/* + * MD4 process buffer + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + mbedtls_md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_md4_update( ctx, (unsigned char *) md4_padding, padn ); + mbedtls_md4_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !MBEDTLS_MD4_ALT */ + +/* + * output = MD4( input buffer ) + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md4_context ctx; + + mbedtls_md4_init( &ctx ); + mbedtls_md4_starts( &ctx ); + mbedtls_md4_update( &ctx, input, ilen ); + mbedtls_md4_finish( &ctx, output ); + mbedtls_md4_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1320 test vectors + */ +static const char md4_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md4_test_sum[7][16] = +{ + { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31, + 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 }, + { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46, + 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 }, + { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52, + 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D }, + { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8, + 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B }, + { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD, + 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 }, + { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35, + 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 }, + { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19, + 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 } +}; + +/* + * Checkup routine + */ +int mbedtls_md4_self_test( int verbose ) +{ + int i; + unsigned char md4sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD4 test #%d: ", i + 1 ); + + mbedtls_md4( (unsigned char *) md4_test_str[i], + strlen( md4_test_str[i] ), md4sum ); + + if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD4_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md5.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md5.c new file mode 100644 index 0000000000..c36192f309 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md5.c @@ -0,0 +1,407 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD5_C) + +#include "mbedtls/md5.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD5_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md5_init( mbedtls_md5_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_free( mbedtls_md5_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +void mbedtls_md5_starts( mbedtls_md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +#if !defined(MBEDTLS_MD5_PROCESS_ALT) +void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} +#endif /* !MBEDTLS_MD5_PROCESS_ALT */ + +/* + * MD5 process buffer + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char md5_padding[64] ICACHE_RODATA_ATTR = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + unsigned char md5_padding_local[64]; + + memcpy(md5_padding_local, md5_padding, 64); + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_md5_update( ctx, md5_padding_local, padn ); + mbedtls_md5_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !MBEDTLS_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md5_context ctx; + + mbedtls_md5_init( &ctx ); + mbedtls_md5_starts( &ctx ); + mbedtls_md5_update( &ctx, input, ilen ); + mbedtls_md5_finish( &ctx, output ); + mbedtls_md5_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static const unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const int md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * Checkup routine + */ +int mbedtls_md5_self_test( int verbose ) +{ + int i; + unsigned char md5sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD5 test #%d: ", i + 1 ); + + mbedtls_md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md_wrap.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md_wrap.c new file mode 100644 index 0000000000..3d211598ed --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/md_wrap.c @@ -0,0 +1,575 @@ +/** + * \file md_wrap.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MD2_C) + +static void md2_starts_wrap( void *ctx ) +{ + mbedtls_md2_starts( (mbedtls_md2_context *) ctx ); +} + +static void md2_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md2_update( (mbedtls_md2_context *) ctx, input, ilen ); +} + +static void md2_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md2_finish( (mbedtls_md2_context *) ctx, output ); +} + +static void *md2_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md2_context ) ); + + if( ctx != NULL ) + mbedtls_md2_init( (mbedtls_md2_context *) ctx ); + + return( ctx ); +} + +static void md2_ctx_free( void *ctx ) +{ + mbedtls_md2_free( (mbedtls_md2_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md2_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md2_clone( (mbedtls_md2_context *) dst, + (const mbedtls_md2_context *) src ); +} + +static void md2_process_wrap( void *ctx, const unsigned char *data ) +{ + ((void) data); + + mbedtls_md2_process( (mbedtls_md2_context *) ctx ); +} + +const mbedtls_md_info_t mbedtls_md2_info = { + MBEDTLS_MD_MD2, + "MD2", + 16, + 16, + md2_starts_wrap, + md2_update_wrap, + md2_finish_wrap, + mbedtls_md2, + md2_ctx_alloc, + md2_ctx_free, + md2_clone_wrap, + md2_process_wrap, +}; + +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + +static void md4_starts_wrap( void *ctx ) +{ + mbedtls_md4_starts( (mbedtls_md4_context *) ctx ); +} + +static void md4_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md4_update( (mbedtls_md4_context *) ctx, input, ilen ); +} + +static void md4_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md4_finish( (mbedtls_md4_context *) ctx, output ); +} + +static void *md4_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md4_context ) ); + + if( ctx != NULL ) + mbedtls_md4_init( (mbedtls_md4_context *) ctx ); + + return( ctx ); +} + +static void md4_ctx_free( void *ctx ) +{ + mbedtls_md4_free( (mbedtls_md4_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md4_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md4_clone( (mbedtls_md4_context *) dst, + (const mbedtls_md4_context *) src ); +} + +static void md4_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_md4_process( (mbedtls_md4_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_md4_info = { + MBEDTLS_MD_MD4, + "MD4", + 16, + 64, + md4_starts_wrap, + md4_update_wrap, + md4_finish_wrap, + mbedtls_md4, + md4_ctx_alloc, + md4_ctx_free, + md4_clone_wrap, + md4_process_wrap, +}; + +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + +static void md5_starts_wrap( void *ctx ) +{ + mbedtls_md5_starts( (mbedtls_md5_context *) ctx ); +} + +static void md5_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md5_update( (mbedtls_md5_context *) ctx, input, ilen ); +} + +static void md5_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md5_finish( (mbedtls_md5_context *) ctx, output ); +} + +static void *md5_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md5_context ) ); + + if( ctx != NULL ) + mbedtls_md5_init( (mbedtls_md5_context *) ctx ); + + return( ctx ); +} + +static void md5_ctx_free( void *ctx ) +{ + mbedtls_md5_free( (mbedtls_md5_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md5_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md5_clone( (mbedtls_md5_context *) dst, + (const mbedtls_md5_context *) src ); +} + +static void md5_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_md5_process( (mbedtls_md5_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_md5_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_MD5, + "MD5", + 16, + 64, + md5_starts_wrap, + md5_update_wrap, + md5_finish_wrap, + mbedtls_md5, + md5_ctx_alloc, + md5_ctx_free, + md5_clone_wrap, + md5_process_wrap, +}; + +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + +static void ripemd160_starts_wrap( void *ctx ) +{ + mbedtls_ripemd160_starts( (mbedtls_ripemd160_context *) ctx ); +} + +static void ripemd160_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_ripemd160_update( (mbedtls_ripemd160_context *) ctx, input, ilen ); +} + +static void ripemd160_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_ripemd160_finish( (mbedtls_ripemd160_context *) ctx, output ); +} + +static void *ripemd160_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ripemd160_context ) ); + + if( ctx != NULL ) + mbedtls_ripemd160_init( (mbedtls_ripemd160_context *) ctx ); + + return( ctx ); +} + +static void ripemd160_ctx_free( void *ctx ) +{ + mbedtls_ripemd160_free( (mbedtls_ripemd160_context *) ctx ); + mbedtls_free( ctx ); +} + +static void ripemd160_clone_wrap( void *dst, const void *src ) +{ + mbedtls_ripemd160_clone( (mbedtls_ripemd160_context *) dst, + (const mbedtls_ripemd160_context *) src ); +} + +static void ripemd160_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_ripemd160_process( (mbedtls_ripemd160_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_ripemd160_info = { + MBEDTLS_MD_RIPEMD160, + "RIPEMD160", + 20, + 64, + ripemd160_starts_wrap, + ripemd160_update_wrap, + ripemd160_finish_wrap, + mbedtls_ripemd160, + ripemd160_ctx_alloc, + ripemd160_ctx_free, + ripemd160_clone_wrap, + ripemd160_process_wrap, +}; + +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + +static void sha1_starts_wrap( void *ctx ) +{ + mbedtls_sha1_starts( (mbedtls_sha1_context *) ctx ); +} + +static void sha1_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha1_update( (mbedtls_sha1_context *) ctx, input, ilen ); +} + +static void sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha1_finish( (mbedtls_sha1_context *) ctx, output ); +} + +static void *sha1_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha1_context ) ); + + if( ctx != NULL ) + mbedtls_sha1_init( (mbedtls_sha1_context *) ctx ); + + return( ctx ); +} + +static void sha1_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha1_clone( (mbedtls_sha1_context *) dst, + (const mbedtls_sha1_context *) src ); +} + +static void sha1_ctx_free( void *ctx ) +{ + mbedtls_sha1_free( (mbedtls_sha1_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha1_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha1_process( (mbedtls_sha1_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha1_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_SHA1, + "SHA1", + 20, + 64, + sha1_starts_wrap, + sha1_update_wrap, + sha1_finish_wrap, + mbedtls_sha1, + sha1_ctx_alloc, + sha1_ctx_free, + sha1_clone_wrap, + sha1_process_wrap, +}; + +#endif /* MBEDTLS_SHA1_C */ + +/* + * Wrappers for generic message digests + */ +#if defined(MBEDTLS_SHA256_C) + +static void sha224_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 1 ); +} + +static void sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update( (mbedtls_sha256_context *) ctx, input, ilen ); +} + +static void sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha256_finish( (mbedtls_sha256_context *) ctx, output ); +} + +static void sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 1 ); +} + +static void *sha224_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) ); + + if( ctx != NULL ) + mbedtls_sha256_init( (mbedtls_sha256_context *) ctx ); + + return( ctx ); +} + +static void sha224_ctx_free( void *ctx ) +{ + mbedtls_sha256_free( (mbedtls_sha256_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha224_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha256_clone( (mbedtls_sha256_context *) dst, + (const mbedtls_sha256_context *) src ); +} + +static void sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha256_process( (mbedtls_sha256_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha224_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_SHA224, + "SHA224", + 28, + 64, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +static void sha256_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 0 ); +} + +static void sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 0 ); +} + +const mbedtls_md_info_t mbedtls_sha256_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_SHA256, + "SHA256", + 32, + 64, + sha256_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha256_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + +static void sha384_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 1 ); +} + +static void sha384_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha512_update( (mbedtls_sha512_context *) ctx, input, ilen ); +} + +static void sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha512_finish( (mbedtls_sha512_context *) ctx, output ); +} + +static void sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( input, ilen, output, 1 ); +} + +static void *sha384_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha512_context ) ); + + if( ctx != NULL ) + mbedtls_sha512_init( (mbedtls_sha512_context *) ctx ); + + return( ctx ); +} + +static void sha384_ctx_free( void *ctx ) +{ + mbedtls_sha512_free( (mbedtls_sha512_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha384_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha512_clone( (mbedtls_sha512_context *) dst, + (const mbedtls_sha512_context *) src ); +} + +static void sha384_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha512_process( (mbedtls_sha512_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha384_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_SHA384, + "SHA384", + 48, + 128, + sha384_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha384_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +static void sha512_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 0 ); +} + +static void sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( input, ilen, output, 0 ); +} + +const mbedtls_md_info_t mbedtls_sha512_info ICACHE_RODATA_ATTR = { + MBEDTLS_MD_SHA512, + "SHA512", + 64, + 128, + sha512_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha512_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_MD_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/memory_buffer_alloc.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/memory_buffer_alloc.c new file mode 100644 index 0000000000..b2c775a3d6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/memory_buffer_alloc.c @@ -0,0 +1,750 @@ +/* + * Buffer-based memory allocator + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#include "mbedtls/memory_buffer_alloc.h" + +/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C + is dependent upon MBEDTLS_PLATFORM_C */ +#include "mbedtls/platform.h" + +#include + +#if defined(MBEDTLS_MEMORY_BACKTRACE) +#include +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define MAGIC1 0xFF00AA55 +#define MAGIC2 0xEE119966 +#define MAX_BT 20 + +typedef struct _memory_header memory_header; +struct _memory_header +{ + size_t magic1; + size_t size; + size_t alloc; + memory_header *prev; + memory_header *next; + memory_header *prev_free; + memory_header *next_free; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + char **trace; + size_t trace_count; +#endif + size_t magic2; +}; + +typedef struct +{ + unsigned char *buf; + size_t len; + memory_header *first; + memory_header *first_free; + int verify; +#if defined(MBEDTLS_MEMORY_DEBUG) + size_t alloc_count; + size_t free_count; + size_t total_used; + size_t maximum_used; + size_t header_count; + size_t maximum_header_count; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +buffer_alloc_ctx; + +static buffer_alloc_ctx heap; + +#if defined(MBEDTLS_MEMORY_DEBUG) +static void debug_header( memory_header *hdr ) +{ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + size_t i; +#endif + + mbedtls_fprintf( stderr, "HDR: PTR(%10zu), PREV(%10zu), NEXT(%10zu), " + "ALLOC(%zu), SIZE(%10zu)\n", + (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next, + hdr->alloc, hdr->size ); + mbedtls_fprintf( stderr, " FPREV(%10zu), FNEXT(%10zu)\n", + (size_t) hdr->prev_free, (size_t) hdr->next_free ); + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + mbedtls_fprintf( stderr, "TRACE: \n" ); + for( i = 0; i < hdr->trace_count; i++ ) + mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] ); + mbedtls_fprintf( stderr, "\n" ); +#endif +} + +static void debug_chain() +{ + memory_header *cur = heap.first; + + mbedtls_fprintf( stderr, "\nBlock list\n" ); + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next; + } + + mbedtls_fprintf( stderr, "Free list\n" ); + cur = heap.first_free; + + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next_free; + } +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +static int verify_header( memory_header *hdr ) +{ + if( hdr->magic1 != MAGIC1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->magic2 != MAGIC2 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->alloc > 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" ); +#endif + return( 1 ); + } + + if( hdr->prev != NULL && hdr->prev == hdr->next ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev == next\n" ); +#endif + return( 1 ); + } + + if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" ); +#endif + return( 1 ); + } + + return( 0 ); +} + +static int verify_chain() +{ + memory_header *prv = heap.first, *cur = heap.first->next; + + if( verify_header( heap.first ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of first header " + "failed\n" ); +#endif + return( 1 ); + } + + if( heap.first->prev != NULL ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "first->prev != NULL\n" ); +#endif + return( 1 ); + } + + while( cur != NULL ) + { + if( verify_header( cur ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of header " + "failed\n" ); +#endif + return( 1 ); + } + + if( cur->prev != prv ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "cur->prev != prv\n" ); +#endif + return( 1 ); + } + + prv = cur; + cur = cur->next; + } + + return( 0 ); +} + +static void *buffer_alloc_calloc( size_t n, size_t size ) +{ + memory_header *new, *cur = heap.first_free; + unsigned char *p; + void *ret; + size_t original_len, len; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + void *trace_buffer[MAX_BT]; + size_t trace_cnt; +#endif + + if( heap.buf == NULL || heap.first == NULL ) + return( NULL ); + + original_len = len = n * size; + + if( n != 0 && len / n != size ) + return( NULL ); + + if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + len += MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + // Find block that fits + // + while( cur != NULL ) + { + if( cur->size >= len ) + break; + + cur = cur->next_free; + } + + if( cur == NULL ) + return( NULL ); + + if( cur->alloc != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.alloc_count++; +#endif + + // Found location, split block if > memory_header + 4 room left + // + if( cur->size - len < sizeof(memory_header) + + MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + cur->alloc = 1; + + // Remove from free_list + // + if( cur->prev_free != NULL ) + cur->prev_free->next_free = cur->next_free; + else + heap.first_free = cur->next_free; + + if( cur->next_free != NULL ) + cur->next_free->prev_free = cur->prev_free; + + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); + } + + p = ( (unsigned char *) cur ) + sizeof(memory_header) + len; + new = (memory_header *) p; + + new->size = cur->size - len - sizeof(memory_header); + new->alloc = 0; + new->prev = cur; + new->next = cur->next; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + new->trace = NULL; + new->trace_count = 0; +#endif + new->magic1 = MAGIC1; + new->magic2 = MAGIC2; + + if( new->next != NULL ) + new->next->prev = new; + + // Replace cur with new in free_list + // + new->prev_free = cur->prev_free; + new->next_free = cur->next_free; + if( new->prev_free != NULL ) + new->prev_free->next_free = new; + else + heap.first_free = new; + + if( new->next_free != NULL ) + new->next_free->prev_free = new; + + cur->alloc = 1; + cur->size = len; + cur->next = new; + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count++; + if( heap.header_count > heap.maximum_header_count ) + heap.maximum_header_count = heap.header_count; + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); +} + +static void buffer_alloc_free( void *ptr ) +{ + memory_header *hdr, *old = NULL; + unsigned char *p = (unsigned char *) ptr; + + if( ptr == NULL || heap.buf == NULL || heap.first == NULL ) + return; + + if( p < heap.buf || p > heap.buf + heap.len ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed " + "space\n" ); +#endif + mbedtls_exit( 1 ); + } + + p -= sizeof(memory_header); + hdr = (memory_header *) p; + + if( verify_header( hdr ) != 0 ) + mbedtls_exit( 1 ); + + if( hdr->alloc != 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + + hdr->alloc = 0; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.free_count++; + heap.total_used -= hdr->size; +#endif + + // Regroup with block before + // + if( hdr->prev != NULL && hdr->prev->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->prev->size += sizeof(memory_header) + hdr->size; + hdr->prev->next = hdr->next; + old = hdr; + hdr = hdr->prev; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + free( old->trace ); +#endif + memset( old, 0, sizeof(memory_header) ); + } + + // Regroup with block after + // + if( hdr->next != NULL && hdr->next->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->size += sizeof(memory_header) + hdr->next->size; + old = hdr->next; + hdr->next = hdr->next->next; + + if( hdr->prev_free != NULL || hdr->next_free != NULL ) + { + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr->next_free; + else + heap.first_free = hdr->next_free; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr->prev_free; + } + + hdr->prev_free = old->prev_free; + hdr->next_free = old->next_free; + + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr; + else + heap.first_free = hdr; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + free( old->trace ); +#endif + memset( old, 0, sizeof(memory_header) ); + } + + // Prepend to free_list if we have not merged + // (Does not have to stay in same order as prev / next list) + // + if( old == NULL ) + { + hdr->next_free = heap.first_free; + if( heap.first_free != NULL ) + heap.first_free->prev_free = hdr; + heap.first_free = hdr; + } + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + hdr->trace = NULL; + hdr->trace_count = 0; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); +} + +void mbedtls_memory_buffer_set_verify( int verify ) +{ + heap.verify = verify; +} + +int mbedtls_memory_buffer_alloc_verify() +{ + return verify_chain(); +} + +#if defined(MBEDTLS_MEMORY_DEBUG) +void mbedtls_memory_buffer_alloc_status() +{ + mbedtls_fprintf( stderr, + "Current use: %zu blocks / %zu bytes, max: %zu blocks / " + "%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n", + heap.header_count, heap.total_used, + heap.maximum_header_count, heap.maximum_used, + heap.maximum_header_count * sizeof( memory_header ) + + heap.maximum_used, + heap.alloc_count, heap.free_count ); + + if( heap.first->next == NULL ) + mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" ); + else + { + mbedtls_fprintf( stderr, "Memory currently allocated:\n" ); + debug_chain(); + } +} + +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ) +{ + *max_used = heap.maximum_used; + *max_blocks = heap.maximum_header_count; +} + +void mbedtls_memory_buffer_alloc_max_reset( void ) +{ + heap.maximum_used = 0; + heap.maximum_header_count = 0; +} + +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ) +{ + *cur_used = heap.total_used; + *cur_blocks = heap.header_count; +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +#if defined(MBEDTLS_THREADING_C) +static void *buffer_alloc_calloc_mutexed( size_t n, size_t size ) +{ + void *buf; + if( mbedtls_mutex_lock( &heap.mutex ) != 0 ) + return( NULL ); + buf = buffer_alloc_calloc( n, size ); + if( mbedtls_mutex_unlock( &heap.mutex ) ) + return( NULL ); + return( buf ); +} + +static void buffer_alloc_free_mutexed( void *ptr ) +{ + /* We have to good option here, but corrupting the heap seems + * worse than loosing memory. */ + if( mbedtls_mutex_lock( &heap.mutex ) ) + return; + buffer_alloc_free( ptr ); + (void) mbedtls_mutex_unlock( &heap.mutex ); +} +#endif /* MBEDTLS_THREADING_C */ + +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ) +{ + memset( &heap, 0, sizeof(buffer_alloc_ctx) ); + memset( buf, 0, len ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &heap.mutex ); + mbedtls_platform_set_calloc_free( buffer_alloc_calloc_mutexed, + buffer_alloc_free_mutexed ); +#else + mbedtls_platform_set_calloc_free( buffer_alloc_calloc, buffer_alloc_free ); +#endif + + if( (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + /* Adjust len first since buf is used in the computation */ + len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + heap.buf = buf; + heap.len = len; + + heap.first = (memory_header *) buf; + heap.first->size = len - sizeof(memory_header); + heap.first->magic1 = MAGIC1; + heap.first->magic2 = MAGIC2; + heap.first_free = heap.first; +} + +void mbedtls_memory_buffer_alloc_free() +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &heap.mutex ); +#endif + mbedtls_zeroize( &heap, sizeof(buffer_alloc_ctx) ); +} + +#if defined(MBEDTLS_SELF_TEST) +static int check_pointer( void *p ) +{ + if( p == NULL ) + return( -1 ); + + if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 ) + return( -1 ); + + return( 0 ); +} + +static int check_all_free( ) +{ + if( +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used != 0 || +#endif + heap.first != heap.first_free || + (void *) heap.first != (void *) heap.buf ) + { + return( -1 ); + } + + return( 0 ); +} + +#define TEST_ASSERT( condition ) \ + if( ! (condition) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + \ + ret = 1; \ + goto cleanup; \ + } + +int mbedtls_memory_buffer_alloc_self_test( int verbose ) +{ + unsigned char buf[1024]; + unsigned char *p, *q, *r, *end; + int ret = 0; + + if( verbose != 0 ) + mbedtls_printf( " MBA test #1 (basic alloc-free cycle): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + /* Memorize end to compare with the next test */ + end = heap.buf + heap.len; + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #2 (buf not aligned): " ); + + mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 ); + + TEST_ASSERT( heap.buf + heap.len == end ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #3 (full): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) ); + + TEST_ASSERT( check_pointer( p ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( p ); + + p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 ); + q = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( q ); + + TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL ); + + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_memory_buffer_alloc_free( ); + + return( ret ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/net.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/net.c new file mode 100644 index 0000000000..a77268c557 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/net.c @@ -0,0 +1,575 @@ +/* + * TCP/IP or UDP/IP networking functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NET_C) + +#include "mbedtls/net.h" + +#include + +#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ + !defined(EFI32) + +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +/* Enables getaddrinfo() & Co */ +#define _WIN32_WINNT 0x0501 +#include + +#include +#include + +#if defined(_MSC_VER) +#if defined(_WIN32_WCE) +#pragma comment( lib, "ws2.lib" ) +#else +#pragma comment( lib, "ws2_32.lib" ) +#endif +#endif /* _MSC_VER */ + +#define read(fd,buf,len) recv(fd,(char*)buf,(int) len,0) +#define write(fd,buf,len) send(fd,(char*)buf,(int) len,0) +#define close(fd) closesocket(fd) + +static int wsa_init_done = 0; + +#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* Some MS functions want int and MSVC warns if we pass size_t, + * but the standard fucntions use socklen_t, so cast only for MSVC */ +#if defined(_MSC_VER) +#define MSVC_INT_CAST (int) +#else +#define MSVC_INT_CAST +#endif + +#include +#include + +#include + +#include + +/* + * Prepare for using the sockets interface + */ +static int net_prepare( void ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else +#if !defined(EFIX64) && !defined(EFI32) + signal( SIGPIPE, SIG_IGN ); +#endif +#endif + return( 0 ); +} + +/* + * Initialize a context + */ +void mbedtls_net_init( mbedtls_net_context *ctx ) +{ + ctx->fd = -1; +} + +/* + * Initiate a TCP connection with host:port and the given protocol + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ) +{ + int ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Do name resolution with both IPv6 and IPv4 */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + + if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a connection succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) + { + ret = 0; + break; + } + + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_CONNECT_FAILED; + } + + freeaddrinfo( addr_list ); + + return( ret ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) +{ + int n, ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + if( bind_ip == NULL ) + hints.ai_flags = AI_PASSIVE; + + if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a binding succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + n = 1; + if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_BIND_FAILED; + continue; + } + + /* Listen only makes sense for TCP */ + if( proto == MBEDTLS_NET_PROTO_TCP ) + { + if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_LISTEN_FAILED; + continue; + } + } + + /* I we ever get there, it's a success */ + ret = 0; + break; + } + + freeaddrinfo( addr_list ); + + return( ret ); + +} + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + ((void) ctx); + return( WSAGetLastError() == WSAEWOULDBLOCK ); +} +#else +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + * + * Note: on a blocking socket this function always returns 0! + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ + if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) + return( 0 ); + + switch( errno ) + { +#if defined EAGAIN + case EAGAIN: +#endif +#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return( 1 ); + } + return( 0 ); +} +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* + * Accept a connection from a remote client + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ) +{ + int ret; + int type; + + struct sockaddr_storage client_addr; + +#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ + defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) + socklen_t n = (socklen_t) sizeof( client_addr ); + socklen_t type_len = (socklen_t) sizeof( type ); +#else + int n = (int) sizeof( client_addr ); + int type_len = (int) sizeof( type ); +#endif + + /* Is this a TCP or UDP socket? */ + if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, &type_len ) != 0 || + ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) + { + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + if( type == SOCK_STREAM ) + { + /* TCP: actual accept() */ + ret = client_ctx->fd = (int) accept( bind_ctx->fd, + (struct sockaddr *) &client_addr, &n ); + } + else + { + /* UDP: wait for a message, but keep it in the queue */ + char buf[1] = { 0 }; + + ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, + (struct sockaddr *) &client_addr, &n ); + +#if defined(_WIN32) + if( ret == SOCKET_ERROR && + WSAGetLastError() == WSAEMSGSIZE ) + { + /* We know buf is too small, thanks, just peeking here */ + ret = 0; + } +#endif + } + + if( ret < 0 ) + { + if( net_would_block( bind_ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + /* UDP: hijack the listening socket to communicate with the client, + * then bind a new socket to accept new connections */ + if( type != SOCK_STREAM ) + { + struct sockaddr_storage local_addr; + int one = 1; + + if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + + client_ctx->fd = bind_ctx->fd; + bind_ctx->fd = -1; /* In case we exit early */ + + n = sizeof( struct sockaddr_storage ); + if( getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) socket( local_addr.ss_family, + SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || + setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof( one ) ) != 0 ) + { + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + } + + if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) + { + return( MBEDTLS_ERR_NET_BIND_FAILED ); + } + } + + if( client_ip != NULL ) + { + if( client_addr.ss_family == AF_INET ) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); + } + else + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; + *ip_len = sizeof( addr6->sin6_addr.s6_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); + } + } + + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 0; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); +#endif +} + +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 1; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); +#endif +} + +/* + * Portable usleep helper + */ +void mbedtls_net_usleep( unsigned long usec ) +{ +#if defined(_WIN32) + Sleep( ( usec + 999 ) / 1000 ); +#else + struct timeval tv; + tv.tv_sec = usec / 1000000; +#if defined(__unix__) || defined(__unix) || \ + ( defined(__APPLE__) && defined(__MACH__) ) + tv.tv_usec = (suseconds_t) usec % 1000000; +#else + tv.tv_usec = usec % 1000000; +#endif + select( 0, NULL, NULL, NULL, &tv ); +#endif +} + +/* + * Read at most 'len' characters + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) read( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + return( ret ); +} + +/* + * Read at most 'len' characters, blocking for at most 'timeout' ms + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + FD_ZERO( &read_fds ); + FD_SET( fd, &read_fds ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); + + /* Zero fds ready means we timed out */ + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_TIMEOUT ); + + if( ret < 0 ) + { +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAEINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#else + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + /* This call will not block */ + return( mbedtls_net_recv( ctx, buf, len ) ); +} + +/* + * Write at most 'len' characters + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) write( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); +#endif + + return( MBEDTLS_ERR_NET_SEND_FAILED ); + } + + return( ret ); +} + +/* + * Gracefully close the connection + */ +void mbedtls_net_free( mbedtls_net_context *ctx ) +{ + if( ctx->fd == -1 ) + return; + + shutdown( ctx->fd, 2 ); + close( ctx->fd ); + + ctx->fd = -1; +} + +#endif /* MBEDTLS_NET_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/oid.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/oid.c new file mode 100644 index 0000000000..0d606c69a0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/oid.c @@ -0,0 +1,650 @@ +/** + * \file oid.c + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_OID_C) + +#include "mbedtls/oid.h" +#include "mbedtls/rsa.h" + +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +/* + * Macro to automatically add the size of #define'd OIDs + */ +#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s) + +/* + * Macro to generate an internal function for oid_XXX_from_asn1() (used by + * the other functions) + */ +#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ +static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \ +{ \ + const TYPE_T *p = LIST; \ + const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \ + if( p == NULL || oid == NULL ) return( NULL ); \ + while( cur->asn1 != NULL ) { \ + if( cur->asn1_len == oid->len && \ + memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ + return( p ); \ + } \ + p++; \ + cur = (const mbedtls_oid_descriptor_t *) p; \ + } \ + return( NULL ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from the + * descriptor of an mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->descriptor.ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving two attributes from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + *ATTR2 = data->ATTR2; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on a single + * attribute from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ +int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on two + * attributes from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ + size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * For X520 attribute types + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + const char *short_name; +} oid_x520_attr_t; + +static const oid_x520_attr_t oid_x520_attr_type[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" }, + "CN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" }, + "C", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" }, + "L", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" }, + "ST", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" }, + "O", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" }, + "OU", + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" }, + "emailAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" }, + "serialNumber", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" }, + "postalAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" }, + "postalCode", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" }, + "SN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" }, + "GN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" }, + "initials", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" }, + "generationQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" }, + "title", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" }, + "dnQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" }, + "pseudonym", + }, + { + { ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" }, + "DC", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" }, + "uniqueIdentifier", + }, + { + { NULL, 0, NULL, NULL }, + NULL, + } +}; + +FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type) +FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name) + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/* + * For X509 extensions + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + int ext_type; +} oid_x509_ext_t; + +static const oid_x509_ext_t oid_x509_ext[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, + MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, + }, + { + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + MBEDTLS_X509_EXT_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, + }, + { + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + MBEDTLS_X509_EXT_NS_CERT_TYPE, + }, + { + { NULL, 0, NULL, NULL }, + 0, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext) +FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type) + +static const mbedtls_oid_descriptor_t oid_ext_key_usage[] ICACHE_RODATA_ATTR = +{ + { ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" }, + { ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" }, + { ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" }, + { ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" }, + { ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" }, + { ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage) +FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description) +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For SignatureAlgorithmIdentifier + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_pk_type_t pk_alg; +} oid_sig_alg_t; + +static const oid_sig_alg_t oid_sig_alg[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" }, + MBEDTLS_MD_MD2, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" }, + MBEDTLS_MD_MD4, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" }, + MBEDTLS_MD_MD5, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +// { +// { ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" }, +// MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA, +// }, +// { +// { ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" }, +// MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA, +// }, +// { +// { ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" }, +// MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA, +// }, +// { +// { ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" }, +// MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA, +// }, +// { +// { ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" }, +// MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA, +// }, + { + { ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" }, + MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg) +FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description) +FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +/* + * For PublicKeyInfo (PKCS1, RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_pk_type_t pk_alg; +} oid_pk_alg_t; + +static const oid_pk_alg_t oid_pk_alg[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" }, + MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" }, + MBEDTLS_PK_ECKEY, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" }, + MBEDTLS_PK_ECKEY_DH, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg) + +#if defined(MBEDTLS_ECP_C) +/* + * For namedCurve (RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_ecp_group_id grp_id; +} oid_ecp_grp_t; + +static const oid_ecp_grp_t oid_ecp_grp[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" }, + MBEDTLS_ECP_DP_SECP192R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" }, + MBEDTLS_ECP_DP_SECP224R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" }, + MBEDTLS_ECP_DP_SECP256R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" }, + MBEDTLS_ECP_DP_SECP384R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" }, + MBEDTLS_ECP_DP_SECP521R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" }, + MBEDTLS_ECP_DP_SECP192K1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" }, + MBEDTLS_ECP_DP_SECP224K1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" }, + MBEDTLS_ECP_DP_SECP256K1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" }, + MBEDTLS_ECP_DP_BP256R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" }, + MBEDTLS_ECP_DP_BP384R1, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" }, + MBEDTLS_ECP_DP_BP512R1, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_ECP_DP_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) +FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id) +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_CIPHER_C) +/* + * For PKCS#5 PBES2 encryption algorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_cipher_type_t cipher_alg; +} oid_cipher_alg_t; + +static const oid_cipher_alg_t oid_cipher_alg[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" }, + MBEDTLS_CIPHER_DES_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" }, + MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; +} oid_md_alg_t; + +static const oid_md_alg_t oid_md_alg[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" }, + MBEDTLS_MD_MD2, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" }, + MBEDTLS_MD_MD4, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" }, + MBEDTLS_MD_MD5, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" }, + MBEDTLS_MD_SHA1, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" }, + MBEDTLS_MD_SHA256, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" }, + MBEDTLS_MD_SHA512, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PKCS12_C) +/* + * For PKCS#12 PBEs + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_cipher_type_t cipher_alg; +} oid_pkcs12_pbe_alg_t; + +static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] ICACHE_RODATA_ATTR = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg) +FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_PKCS12_C */ + +#define OID_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +/* Return the x.y.z.... style numeric string for the given OID */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, + const mbedtls_asn1_buf *oid ) +{ + int ret; + size_t i, n; + unsigned int value; + char *p; + + p = buf; + n = size; + + /* First byte contains first two dots */ + if( oid->len > 0 ) + { + ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 ); + OID_SAFE_SNPRINTF; + } + + value = 0; + for( i = 1; i < oid->len; i++ ) + { + /* Prevent overflow in value. */ + if( ( ( value << 7 ) >> 7 ) != value ) + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); + + value <<= 7; + value += oid->p[i] & 0x7F; + + if( !( oid->p[i] & 0x80 ) ) + { + /* Last byte */ + ret = mbedtls_snprintf( p, n, ".%d", value ); + OID_SAFE_SNPRINTF; + value = 0; + } + } + + return( (int) ( size - n ) ); +} + +#endif /* MBEDTLS_OID_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/padlock.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/padlock.c new file mode 100644 index 0000000000..b85ff9cd2c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/padlock.c @@ -0,0 +1,170 @@ +/* + * VIA PadLock support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This implementation is based on the VIA PadLock Programming Guide: + * + * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/ + * programming_guide.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PADLOCK_C) + +#include "mbedtls/padlock.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86) + +/* + * PadLock detection routine + */ +int mbedtls_padlock_has_support( int feature ) +{ + static int flags = -1; + int ebx = 0, edx = 0; + + if( flags == -1 ) + { + asm( "movl %%ebx, %0 \n\t" + "movl $0xC0000000, %%eax \n\t" + "cpuid \n\t" + "cmpl $0xC0000001, %%eax \n\t" + "movl $0, %%edx \n\t" + "jb unsupported \n\t" + "movl $0xC0000001, %%eax \n\t" + "cpuid \n\t" + "unsupported: \n\t" + "movl %%edx, %1 \n\t" + "movl %2, %%ebx \n\t" + : "=m" (ebx), "=m" (edx) + : "m" (ebx) + : "eax", "ecx", "edx" ); + + flags = edx; + } + + return( flags & feature ); +} + +/* + * PadLock AES-ECB block en(de)cryption + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ebx = 0; + uint32_t *rk; + uint32_t *blk; + uint32_t *ctrl; + unsigned char buf[256]; + + rk = ctx->rk; + blk = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( blk, input, 16 ); + + ctrl = blk + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 ); + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl $1, %%ecx \n\t" + "movl %2, %%edx \n\t" + "movl %3, %%ebx \n\t" + "movl %4, %%esi \n\t" + "movl %4, %%edi \n\t" + ".byte 0xf3,0x0f,0xa7,0xc8 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk) + : "memory", "ecx", "edx", "esi", "edi" ); + + memcpy( output, blk, 16 ); + + return( 0 ); +} + +/* + * PadLock AES-CBC buffer en(de)cryption + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ebx = 0; + size_t count; + uint32_t *rk; + uint32_t *iw; + uint32_t *ctrl; + unsigned char buf[256]; + + if( ( (long) input & 15 ) != 0 || + ( (long) output & 15 ) != 0 ) + return( MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED ); + + rk = ctx->rk; + iw = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( iw, iv, 16 ); + + ctrl = iw + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode ^ 1 ) - 10 ) << 9 ); + + count = ( length + 15 ) >> 4; + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl %2, %%ecx \n\t" + "movl %3, %%edx \n\t" + "movl %4, %%ebx \n\t" + "movl %5, %%esi \n\t" + "movl %6, %%edi \n\t" + "movl %7, %%eax \n\t" + ".byte 0xf3,0x0f,0xa7,0xd0 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (count), "m" (ctrl), + "m" (rk), "m" (input), "m" (output), "m" (iw) + : "memory", "eax", "ecx", "edx", "esi", "edi" ); + + memcpy( iv, iw, 16 ); + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86 */ + +#endif /* MBEDTLS_PADLOCK_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pem.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pem.c new file mode 100644 index 0000000000..1ee3966e1e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pem.c @@ -0,0 +1,447 @@ +/* + * Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + +#include "mbedtls/pem.h" +#include "mbedtls/base64.h" +#include "mbedtls/des.h" +#include "mbedtls/aes.h" +#include "mbedtls/md5.h" +#include "mbedtls/cipher.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#if defined(MBEDTLS_PEM_PARSE_C) +void mbedtls_pem_init( mbedtls_pem_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pem_context ) ); +} + +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) +/* + * Read a 16-byte hex string and convert it to binary + */ +static int pem_get_iv( const unsigned char *s, unsigned char *iv, + size_t iv_len ) +{ + size_t i, j, k; + + memset( iv, 0, iv_len ); + + for( i = 0; i < iv_len * 2; i++, s++ ) + { + if( *s >= '0' && *s <= '9' ) j = *s - '0'; else + if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else + if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + k = ( ( i & 1 ) != 0 ) ? j : j << 4; + + iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); + } + + return( 0 ); +} + +static void pem_pbkdf1( unsigned char *key, size_t keylen, + unsigned char *iv, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_md5_context md5_ctx; + unsigned char md5sum[16]; + size_t use_len; + + mbedtls_md5_init( &md5_ctx ); + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); + return; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, md5sum, 16 ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); +} + +#if defined(MBEDTLS_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des_decrypt( unsigned char des_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des_context des_ctx; + unsigned char des_key[8]; + + mbedtls_des_init( &des_ctx ); + + pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ); + + mbedtls_des_setkey_dec( &des_ctx, des_key ); + mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, + des_iv, buf, buf ); + + mbedtls_des_free( &des_ctx ); + mbedtls_zeroize( des_key, 8 ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des3_decrypt( unsigned char des3_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des3_context des3_ctx; + unsigned char des3_key[24]; + + mbedtls_des3_init( &des3_ctx ); + + pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ); + + mbedtls_des3_set3key_dec( &des3_ctx, des3_key ); + mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, + des3_iv, buf, buf ); + + mbedtls_des3_free( &des3_ctx ); + mbedtls_zeroize( des3_key, 24 ); +} +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_aes_context aes_ctx; + unsigned char aes_key[32]; + + mbedtls_aes_init( &aes_ctx ); + + pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ); + + mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ); + mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, + aes_iv, buf, buf ); + + mbedtls_aes_free( &aes_ctx ); + mbedtls_zeroize( aes_key, keylen ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, const unsigned char *pwd, + size_t pwdlen, size_t *use_len ) +{ + int ret, enc; + size_t len; + unsigned char *buf; + const unsigned char *s1, *s2, *end; +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + unsigned char pem_iv[16]; + mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + + if( ctx == NULL ) + return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA ); + + s1 = (unsigned char *) strstr( (const char *) data, header ); + + if( s1 == NULL ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s2 = (unsigned char *) strstr( (const char *) data, footer ); + + if( s2 == NULL || s2 <= s1 ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s1 += strlen( header ); + if( *s1 == ' ' ) s1++; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + end = s2; + end += strlen( footer ); + if( *end == ' ' ) end++; + if( *end == '\r' ) end++; + if( *end == '\n' ) end++; + *use_len = end - data; + + enc = 0; + + if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + enc++; + + s1 += 22; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + +#if defined(MBEDTLS_DES_C) + if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; + + s1 += 23; + if( pem_get_iv( s1, pem_iv, 8 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } + else if( memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_CBC; + + s1 += 18; + if( pem_get_iv( s1, pem_iv, 8) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) + { + if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_128_CBC; + else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_192_CBC; + else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_256_CBC; + else + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + s1 += 22; + if( pem_get_iv( s1, pem_iv, 16 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 32; + } +#endif /* MBEDTLS_AES_C */ + + if( enc_alg == MBEDTLS_CIPHER_NONE ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); +#else + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + if( s1 == s2 ) + return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 ); + + if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + } + + if( enc != 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + if( pwd == NULL ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); + } + +#if defined(MBEDTLS_DES_C) + if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) + pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) + pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC ) + pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) + pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) + pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_AES_C */ + + /* + * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 + * length bytes (allow 4 to be sure) in all known use cases. + * + * Use that as heurisitic to try detecting password mismatchs. + */ + if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + ctx->buf = buf; + ctx->buflen = len; + + return( 0 ); +} + +void mbedtls_pem_free( mbedtls_pem_context *ctx ) +{ + mbedtls_free( ctx->buf ); + mbedtls_free( ctx->info ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_pem_context ) ); +} +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ) +{ + int ret; + unsigned char *encode_buf, *c, *p = buf; + size_t len = 0, use_len, add_len = 0; + + mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); + add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; + + if( use_len + add_len > buf_len ) + { + *olen = use_len + add_len; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + if( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, + der_len ) ) != 0 ) + { + mbedtls_free( encode_buf ); + return( ret ); + } + + memcpy( p, header, strlen( header ) ); + p += strlen( header ); + c = encode_buf; + + while( use_len ) + { + len = ( use_len > 64 ) ? 64 : use_len; + memcpy( p, c, len ); + use_len -= len; + p += len; + c += len; + *p++ = '\n'; + } + + memcpy( p, footer, strlen( footer ) ); + p += strlen( footer ); + + *p++ = '\0'; + *olen = p - buf; + + mbedtls_free( encode_buf ); + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk.c new file mode 100644 index 0000000000..10bd0a5828 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk.c @@ -0,0 +1,374 @@ +/* + * Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#include "mbedtls/pk_internal.h" + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialise a mbedtls_pk_context + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->pk_info = NULL; + ctx->pk_ctx = NULL; +} + +/* + * Free (the components of) a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return; + + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +/* + * Get pk_info structure from type + */ +const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) +{ + switch( pk_type ) { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_PK_RSA: + return( &mbedtls_rsa_info ); +#endif +#if defined(MBEDTLS_ECP_C) + case MBEDTLS_PK_ECKEY: + return( &mbedtls_eckey_info ); + case MBEDTLS_PK_ECKEY_DH: + return( &mbedtls_eckeydh_info ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_PK_ECDSA: + return( &mbedtls_ecdsa_info ); +#endif + /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + default: + return( NULL ); + } +} + +/* + * Initialise context + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) +{ + if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Initialize an RSA-alt context + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ) +{ + mbedtls_rsa_alt_context *rsa_alt; + const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info; + + if( ctx == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + rsa_alt = (mbedtls_rsa_alt_context *) ctx->pk_ctx; + + rsa_alt->key = key; + rsa_alt->decrypt_func = decrypt_func; + rsa_alt->sign_func = sign_func; + rsa_alt->key_len_func = key_len_func; + + return( 0 ); +} +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/* + * Tell if a PK can do the operations of the given type + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) +{ + /* null or NONE context can't do anything */ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->can_do( type ) ); +} + +/* + * Helper for mbedtls_pk_sign and mbedtls_pk_verify + */ +static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len ) +{ + const mbedtls_md_info_t *md_info; + + if( *hash_len != 0 ) + return( 0 ); + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( -1 ); + + *hash_len = mbedtls_md_get_size( md_info ); + return( 0 ); +} + +/* + * Verify a signature + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->verify_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len ) ); +} + +/* + * Verify a signature with options + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ! mbedtls_pk_can_do( ctx, type ) ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + if( type == MBEDTLS_PK_RSASSA_PSS ) + { +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V21) + int ret; + const mbedtls_pk_rsassa_pss_options *pss_opts; + + if( options == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) options; + + if( sig_len < mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + ret = mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_pk_rsa( *ctx ), + NULL, NULL, MBEDTLS_RSA_PUBLIC, + md_alg, (unsigned int) hash_len, hash, + pss_opts->mgf1_hash_id, + pss_opts->expected_salt_len, + sig ); + if( ret != 0 ) + return( ret ); + + if( sig_len > mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +#else + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); +#endif + } + + /* General case: no options */ + if( options != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) ); +} + +/* + * Make a signature + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->sign_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng ) ); +} + +/* + * Decrypt message + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->decrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Encrypt message + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->encrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Check public-private key pair + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) +{ + if( pub == NULL || pub->pk_info == NULL || + prv == NULL || prv->pk_info == NULL || + prv->pk_info->check_pair_func == NULL ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + else + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + + return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); +} + +/* + * Get key size in bits + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); +} + +/* + * Export debug information + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->debug_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + ctx->pk_info->debug_func( ctx->pk_ctx, items ); + return( 0 ); +} + +/* + * Access the PK type name + */ +const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( "invalid PK" ); + + return( ctx->pk_info->name ); +} + +/* + * Access the PK type + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_PK_NONE ); + + return( ctx->pk_info->type ); +} + +#endif /* MBEDTLS_PK_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk_wrap.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk_wrap.c new file mode 100644 index 0000000000..626c3b9ca1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pk_wrap.c @@ -0,0 +1,495 @@ +/* + * Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_internal.h" + +/* Even if RSA not activated, for the sake of RSA-alt */ +#include "mbedtls/rsa.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_RSA_C) +static int rsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA || + type == MBEDTLS_PK_RSASSA_PSS ); +} + +static size_t rsa_get_bitlen( const void *ctx ) +{ + return( 8 * ((const mbedtls_rsa_context *) ctx)->len ); +} + +static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + + if( sig_len < ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_rsa_pkcs1_verify( (mbedtls_rsa_context *) ctx, NULL, NULL, + MBEDTLS_RSA_PUBLIC, md_alg, + (unsigned int) hash_len, hash, sig ) ) != 0 ) + return( ret ); + + if( sig_len > ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +} + +static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + *sig_len = ((mbedtls_rsa_context *) ctx)->len; + + return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ilen != ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, f_rng, p_rng, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +static int rsa_encrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + *olen = ((mbedtls_rsa_context *) ctx)->len; + + if( *olen > osize ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + return( mbedtls_rsa_pkcs1_encrypt( (mbedtls_rsa_context *) ctx, + f_rng, p_rng, MBEDTLS_RSA_PUBLIC, ilen, input, output ) ); +} + +static int rsa_check_pair_wrap( const void *pub, const void *prv ) +{ + return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, + (const mbedtls_rsa_context *) prv ) ); +} + +static void *rsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_context ) ); + + if( ctx != NULL ) + mbedtls_rsa_init( (mbedtls_rsa_context *) ctx, 0, 0 ); + + return( ctx ); +} + +static void rsa_free_wrap( void *ctx ) +{ + mbedtls_rsa_free( (mbedtls_rsa_context *) ctx ); + mbedtls_free( ctx ); +} + +static void rsa_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.N"; + items->value = &( ((mbedtls_rsa_context *) ctx)->N ); + + items++; + + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.E"; + items->value = &( ((mbedtls_rsa_context *) ctx)->E ); +} + +const mbedtls_pk_info_t mbedtls_rsa_info ICACHE_RODATA_ATTR = { + MBEDTLS_PK_RSA, + "RSA", + rsa_get_bitlen, + rsa_can_do, + rsa_verify_wrap, + rsa_sign_wrap, + rsa_decrypt_wrap, + rsa_encrypt_wrap, + rsa_check_pair_wrap, + rsa_alloc_wrap, + rsa_free_wrap, + rsa_debug, +}; +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Generic EC key + */ +static int eckey_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH || + type == MBEDTLS_PK_ECDSA ); +} + +static size_t eckey_get_bitlen( const void *ctx ) +{ + return( ((mbedtls_ecp_keypair *) ctx)->grp.pbits ); +} + +#if defined(MBEDTLS_ECDSA_C) +/* Forward declarations */ +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +static int eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len, + f_rng, p_rng ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +#endif /* MBEDTLS_ECDSA_C */ + +static int eckey_check_pair( const void *pub, const void *prv ) +{ + return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, + (const mbedtls_ecp_keypair *) prv ) ); +} + +static void *eckey_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); + + if( ctx != NULL ) + mbedtls_ecp_keypair_init( ctx ); + + return( ctx ); +} + +static void eckey_free_wrap( void *ctx ) +{ + mbedtls_ecp_keypair_free( (mbedtls_ecp_keypair *) ctx ); + mbedtls_free( ctx ); +} + +static void eckey_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_ECP; + items->name = "eckey.Q"; + items->value = &( ((mbedtls_ecp_keypair *) ctx)->Q ); +} + +const mbedtls_pk_info_t mbedtls_eckey_info ICACHE_RODATA_ATTR = { + MBEDTLS_PK_ECKEY, + "EC", + eckey_get_bitlen, + eckey_can_do, +#if defined(MBEDTLS_ECDSA_C) + eckey_verify_wrap, + eckey_sign_wrap, +#else + NULL, + NULL, +#endif + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, + eckey_free_wrap, + eckey_debug, +}; + +/* + * EC key restricted to ECDH + */ +static int eckeydh_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH ); +} + +const mbedtls_pk_info_t mbedtls_eckeydh_info ICACHE_RODATA_ATTR = { + MBEDTLS_PK_ECKEY_DH, + "EC_DH", + eckey_get_bitlen, /* Same underlying key structure */ + eckeydh_can_do, + NULL, + NULL, + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, /* Same underlying key structure */ + eckey_free_wrap, /* Same underlying key structure */ + eckey_debug, /* Same underlying key structure */ +}; +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ECDSA_C) +static int ecdsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECDSA ); +} + +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature( (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecdsa_write_signature( (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) ); +} + +static void *ecdsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_init( (mbedtls_ecdsa_context *) ctx ); + + return( ctx ); +} + +static void ecdsa_free_wrap( void *ctx ) +{ + mbedtls_ecdsa_free( (mbedtls_ecdsa_context *) ctx ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_ecdsa_info ICACHE_RODATA_ATTR = { + MBEDTLS_PK_ECDSA, + "ECDSA", + eckey_get_bitlen, /* Compatible key structures */ + ecdsa_can_do, + ecdsa_verify_wrap, + ecdsa_sign_wrap, + NULL, + NULL, + eckey_check_pair, /* Compatible key structures */ + ecdsa_alloc_wrap, + ecdsa_free_wrap, + eckey_debug, /* Compatible key structures */ +}; +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Support for alternative RSA-private implementations + */ + +static int rsa_alt_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA ); +} + +static size_t rsa_alt_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( 8 * rsa_alt->key_len_func( rsa_alt->key ) ); +} + +static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + + *sig_len = rsa_alt->key_len_func( rsa_alt->key ); + + return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_alt_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + + ((void) f_rng); + ((void) p_rng); + + if( ilen != rsa_alt->key_len_func( rsa_alt->key ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( rsa_alt->decrypt_func( rsa_alt->key, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +#if defined(MBEDTLS_RSA_C) +static int rsa_alt_check_pair( const void *pub, const void *prv ) +{ + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char hash[32]; + size_t sig_len = 0; + int ret; + + if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + memset( hash, 0x2a, sizeof( hash ) ); + + if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + hash, sizeof( hash ), + sig, &sig_len, NULL, NULL ) ) != 0 ) + { + return( ret ); + } + + if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +static void *rsa_alt_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_alt_context ) ); + + if( ctx != NULL ) + memset( ctx, 0, sizeof( mbedtls_rsa_alt_context ) ); + + return( ctx ); +} + +static void rsa_alt_free_wrap( void *ctx ) +{ + mbedtls_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_rsa_alt_info ICACHE_RODATA_ATTR = { + MBEDTLS_PK_RSA_ALT, + "RSA-alt", + rsa_alt_get_bitlen, + rsa_alt_can_do, + NULL, + rsa_alt_sign_wrap, + rsa_alt_decrypt_wrap, + NULL, +#if defined(MBEDTLS_RSA_C) + rsa_alt_check_pair, +#else + NULL, +#endif + rsa_alt_alloc_wrap, + rsa_alt_free_wrap, + NULL, +}; + +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +#endif /* MBEDTLS_PK_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs11.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs11.c new file mode 100644 index 0000000000..0ea64252ee --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs11.c @@ -0,0 +1,240 @@ +/** + * \file pkcs11.c + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/pkcs11.h" + +#if defined(MBEDTLS_PKCS11_C) + +#include "mbedtls/md.h" +#include "mbedtls/oid.h" +#include "mbedtls/x509_crt.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pkcs11_context ) ); +} + +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + unsigned char *cert_blob = NULL; + size_t cert_blob_size = 0; + + if( cert == NULL ) + { + ret = 2; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, NULL, + &cert_blob_size ) != CKR_OK ) + { + ret = 3; + goto cleanup; + } + + cert_blob = mbedtls_calloc( 1, cert_blob_size ); + if( NULL == cert_blob ) + { + ret = 4; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, cert_blob, + &cert_blob_size ) != CKR_OK ) + { + ret = 5; + goto cleanup; + } + + if( 0 != mbedtls_x509_crt_parse( cert, cert_blob, cert_blob_size ) ) + { + ret = 6; + goto cleanup; + } + + ret = 0; + +cleanup: + if( NULL != cert_blob ) + mbedtls_free( cert_blob ); + + return( ret ); +} + + +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + mbedtls_x509_crt cert; + + mbedtls_x509_crt_init( &cert ); + + if( priv_key == NULL ) + goto cleanup; + + if( 0 != mbedtls_pkcs11_x509_cert_bind( &cert, pkcs11_cert ) ) + goto cleanup; + + priv_key->len = mbedtls_pk_get_len( &cert.pk ); + priv_key->pkcs11h_cert = pkcs11_cert; + + ret = 0; + +cleanup: + mbedtls_x509_crt_free( &cert ); + + return( ret ); +} + +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ) +{ + if( NULL != priv_key ) + pkcs11h_certificate_freeCertificate( priv_key->pkcs11h_cert ); +} + +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + size_t input_len, output_len; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + output_len = input_len = ctx->len; + + if( input_len < 16 || input_len > output_max_len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Determine size of output buffer */ + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, NULL, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( output_len > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, output, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + *olen = output_len; + return( 0 ); +} + +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t sig_len = 0, asn_len = 0, oid_size = 0; + unsigned char *p = sig; + const char *oid; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + asn_len = 10 + oid_size; + } + + sig_len = ctx->len; + if( hashlen > sig_len || asn_len > sig_len || + hashlen + asn_len > sig_len ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + } + + memcpy( p, hash, hashlen ); + + if( pkcs11h_certificate_signAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, sig, + asn_len + hashlen, sig, &sig_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +#endif /* defined(MBEDTLS_PKCS11_C) */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs12.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs12.c new file mode 100644 index 0000000000..7023b9dbc8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs12.c @@ -0,0 +1,365 @@ +/* + * PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 + * + * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS12_C) + +#include "mbedtls/pkcs12.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" + +#include + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations ) +{ + int ret; + unsigned char **p = ¶ms->p; + const unsigned char *end = params->p + params->len; + + /* + * pkcs-12PbeParams ::= SEQUENCE { + * salt OCTET STRING, + * iterations INTEGER + * } + * + */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#define PKCS12_MAX_PWDLEN 128 + +static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen ) +{ + int ret, iterations; + mbedtls_asn1_buf salt; + size_t i; + unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; + + if( pwdlen > PKCS12_MAX_PWDLEN ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + memset( &salt, 0, sizeof(mbedtls_asn1_buf) ); + memset( &unipwd, 0, sizeof(unipwd) ); + + if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, + &iterations ) ) != 0 ) + return( ret ); + + for( i = 0; i < pwdlen; i++ ) + unipwd[i * 2 + 1] = pwd[i]; + + if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 ) + { + return( ret ); + } + + if( iv == NULL || ivlen == 0 ) + return( 0 ); + + if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +#undef PKCS12_MAX_PWDLEN + +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ +#if !defined(MBEDTLS_ARC4_C) + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) len); + ((void) output); + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); +#else + int ret; + unsigned char key[16]; + mbedtls_arc4_context ctx; + ((void) mode); + + mbedtls_arc4_init( &ctx ); + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1, + pwd, pwdlen, + key, 16, NULL, 0 ) ) != 0 ) + { + return( ret ); + } + + mbedtls_arc4_setup( &ctx, key, 16 ); + if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_arc4_free( &ctx ); + + return( ret ); +#endif /* MBEDTLS_ARC4_C */ +} + +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ + int ret, keylen = 0; + unsigned char key[32]; + unsigned char iv[16]; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_cipher_context_t cipher_ctx; + size_t olen = 0; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_bitlen / 8; + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, + key, keylen, + iv, cipher_info->iv_size ) ) != 0 ) + { + return( ret ); + } + + mbedtls_cipher_init( &cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len, + output, &olen ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; + +exit: + mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_zeroize( iv, sizeof( iv ) ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, + const unsigned char *filler, size_t fill_len ) +{ + unsigned char *p = data; + size_t use_len; + + while( data_len > 0 ) + { + use_len = ( data_len > fill_len ) ? fill_len : data_len; + memcpy( p, filler, use_len ); + p += use_len; + data_len -= use_len; + } +} + +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t md_type, int id, int iterations ) +{ + int ret; + unsigned int j; + + unsigned char diversifier[128]; + unsigned char salt_block[128], pwd_block[128], hash_block[128]; + unsigned char hash_output[MBEDTLS_MD_MAX_SIZE]; + unsigned char *p; + unsigned char c; + + size_t hlen, use_len, v, i; + + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + // This version only allows max of 64 bytes of password or salt + if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + mbedtls_md_init( &md_ctx ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + return( ret ); + hlen = mbedtls_md_get_size( md_info ); + + if( hlen <= 32 ) + v = 64; + else + v = 128; + + memset( diversifier, (unsigned char) id, v ); + + pkcs12_fill_buffer( salt_block, v, salt, saltlen ); + pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); + + p = data; + while( datalen > 0 ) + { + // Calculate hash( diversifier || salt_block || pwd_block ) + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 ) + goto exit; + + // Perform remaining ( iterations - 1 ) recursive hash calculations + for( i = 1; i < (size_t) iterations; i++ ) + { + if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 ) + goto exit; + } + + use_len = ( datalen > hlen ) ? hlen : datalen; + memcpy( p, hash_output, use_len ); + datalen -= use_len; + p += use_len; + + if( datalen == 0 ) + break; + + // Concatenating copies of hash_output into hash_block (B) + pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); + + // B += 1 + for( i = v; i > 0; i-- ) + if( ++hash_block[i - 1] != 0 ) + break; + + // salt_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = salt_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + salt_block[i - 1] = j & 0xFF; + } + + // pwd_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = pwd_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + pwd_block[i - 1] = j & 0xFF; + } + } + + ret = 0; + +exit: + mbedtls_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_zeroize( hash_output, sizeof( hash_output ) ); + + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PKCS12_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs5.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs5.c new file mode 100644 index 0000000000..44af9869b1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkcs5.c @@ -0,0 +1,405 @@ +/** + * \file pkcs5.c + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * PKCS#5 includes PBKDF2 and more + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS5_C) + +#include "mbedtls/pkcs5.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations, + int *keylen, mbedtls_md_type_t *md_type ) +{ + int ret; + mbedtls_asn1_buf prf_alg_oid; + unsigned char *p = params->p; + const unsigned char *end = params->p + params->len; + + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + /* + * PBKDF2-params ::= SEQUENCE { + * salt OCTET STRING, + * iterationCount INTEGER, + * keyLength INTEGER OPTIONAL + * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 + * } + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + salt->p = p; + p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_HMAC_SHA1, &prf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + *md_type = MBEDTLS_MD_SHA1; + + if( p != end ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + int ret, iterations = 0, keylen = 0; + unsigned char *p, *end; + mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params; + mbedtls_asn1_buf salt; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; + unsigned char key[32], iv[32]; + size_t olen = 0; + const mbedtls_md_info_t *md_info; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_md_context_t md_ctx; + mbedtls_cipher_type_t cipher_alg; + mbedtls_cipher_context_t cipher_ctx; + + p = pbe_params->p; + end = p + pbe_params->len; + + /* + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + */ + if( pbe_params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + // Only PBKDF2 supported at the moment + // + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params, + &salt, &iterations, &keylen, + &md_type ) ) != 0 ) + { + return( ret ); + } + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &enc_scheme_oid, + &enc_scheme_params ) ) != 0 ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( mbedtls_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + cipher_info = mbedtls_cipher_info_from_type( cipher_alg ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + /* + * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored + * since it is optional and we don't know if it was set or not + */ + keylen = cipher_info->key_bitlen / 8; + + if( enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || + enc_scheme_params.len != cipher_info->iv_size ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT ); + } + + mbedtls_md_init( &md_ctx ); + mbedtls_cipher_init( &cipher_ctx ); + + memcpy( iv, enc_scheme_params.p, enc_scheme_params.len ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, + iterations, keylen, key ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len, + data, datalen, output, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH; + +exit: + mbedtls_md_free( &md_ctx ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + int ret, j; + unsigned int i; + unsigned char md1[MBEDTLS_MD_MAX_SIZE]; + unsigned char work[MBEDTLS_MD_MAX_SIZE]; + unsigned char md_size = mbedtls_md_get_size( ctx->md_info ); + size_t use_len; + unsigned char *out_p = output; + unsigned char counter[4]; + + memset( counter, 0, 4 ); + counter[3] = 1; + + if( iteration_count > 0xFFFFFFFF ) + return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA ); + + while( key_length ) + { + // U1 ends up in work + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 ) + return( ret ); + + memcpy( md1, work, md_size ); + + for( i = 1; i < iteration_count; i++ ) + { + // U2 ends up in md1 + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 ) + return( ret ); + + // U1 xor U2 + // + for( j = 0; j < md_size; j++ ) + work[j] ^= md1[j]; + } + + use_len = ( key_length < md_size ) ? key_length : md_size; + memcpy( out_p, work, use_len ); + + key_length -= (uint32_t) use_len; + out_p += use_len; + + for( i = 4; i > 0; i-- ) + if( ++counter[i - 1] != 0 ) + break; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +int mbedtls_pkcs5_self_test( int verbose ) +{ + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1): skipped\n\n" ); + + return( 0 ); +} +#else + +#define MAX_TESTS 6 + +static const size_t plen[MAX_TESTS] = + { 8, 8, 8, 24, 9 }; + +static const unsigned char password[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +static const size_t slen[MAX_TESTS] = + { 4, 4, 4, 36, 5 }; + +static const unsigned char salt[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +static const uint32_t it_cnt[MAX_TESTS] = + { 1, 2, 4096, 4096, 4096 }; + +static const uint32_t key_len[MAX_TESTS] = + { 20, 20, 20, 25, 16 }; + +static const unsigned char result_key[MAX_TESTS][32] = +{ + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 }, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 }, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 }, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, +}; + +int mbedtls_pkcs5_self_test( int verbose ) +{ + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret, i; + unsigned char key[64]; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if( info_sha1 == NULL ) + { + ret = 1; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 ) + { + ret = 1; + goto exit; + } + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1) #%d: ", i ); + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i], + slen[i], it_cnt[i], key_len[i], key ); + if( ret != 0 || + memcmp( result_key[i], key, key_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + mbedtls_printf( "\n" ); + +exit: + mbedtls_md_free( &sha1_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_SHA1_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_PKCS5_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkparse.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkparse.c new file mode 100644 index 0000000000..275429e603 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkparse.c @@ -0,0 +1,1293 @@ +/* + * Public Key layer for parsing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_PARSE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_FS_IO) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + mbedtls_free( *buf ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse a private key + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + if( pwd == NULL ) + ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); + else + ret = mbedtls_pk_parse_key( ctx, buf, n, + (const unsigned char *) pwd, strlen( pwd ) ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +/* + * Load and parse a public key + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_pk_parse_public_key( ctx, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_ECP_C) +/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + * } + */ +static int pk_get_ecparams( unsigned char **p, const unsigned char *end, + mbedtls_asn1_buf *params ) +{ + int ret; + + /* Tag may be either OID or SEQUENCE */ + params->tag = **p; + if( params->tag != MBEDTLS_ASN1_OID +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) +#endif + ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. + * WARNING: the resulting group should only be used with + * pk_group_id_from_specified(), since its base point may not be set correctly + * if it was encoded compressed. + * + * SpecifiedECDomain ::= SEQUENCE { + * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), + * fieldID FieldID {{FieldTypes}}, + * curve Curve, + * base ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL, + * hash HashAlgorithm OPTIONAL, + * ... + * } + * + * We only support prime-field as field type, and ignore hash and cofactor. + */ +static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + unsigned char *p = params->p; + const unsigned char * const end = params->p + params->len; + const unsigned char *end_field, *end_curve; + size_t len; + int ver; + + /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ + if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ver < 1 || ver > 3 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + /* + * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_field = p + len; + + /* + * FIELD-ID ::= TYPE-IDENTIFIER + * FieldTypes FIELD-ID ::= { + * { Prime-p IDENTIFIED BY prime-field } | + * { Characteristic-two IDENTIFIED BY characteristic-two-field } + * } + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || + memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) + { + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + + p += len; + + /* Prime-p ::= INTEGER -- Field of size p. */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + if( p != end_field ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * -- Shall be present if used in SpecifiedECDomain + * -- with version equal to ecdpVer2 or ecdpVer3 + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_curve = p + len; + + /* + * FieldElement ::= OCTET STRING + * containing an integer in the case of a prime field + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + /* Ignore seed BIT STRING OPTIONAL */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) + p += len; + + if( p != end_curve ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * ECPoint ::= OCTET STRING + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, + ( const unsigned char *) p, len ) ) != 0 ) + { + /* + * If we can't read the point because it's compressed, cheat by + * reading only the X coordinate and the parity bit of Y. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || + ( p[0] != 0x02 && p[0] != 0x03 ) || + len != mbedtls_mpi_size( &grp->P ) + 1 || + mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || + mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || + mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + + p += len; + + /* + * order INTEGER + */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + /* + * Allow optional elements by purposefully not enforcing p == end here. + */ + + return( 0 ); +} + +/* + * Find the group id associated with an (almost filled) group as generated by + * pk_group_from_specified(), or return an error if unknown. + */ +static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) +{ + int ret = 0; + mbedtls_ecp_group ref; + const mbedtls_ecp_group_id *id; + + mbedtls_ecp_group_init( &ref ); + + for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) + { + /* Load the group associated to that id */ + mbedtls_ecp_group_free( &ref ); + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); + + /* Compare to the group we were given, starting with easy tests */ + if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && + mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && + /* For Y we may only know the parity bit, so compare only that */ + mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) + { + break; + } + + } + +cleanup: + mbedtls_ecp_group_free( &ref ); + + *grp_id = *id; + + if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + + return( ret ); +} + +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID + */ +static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id ) +{ + int ret; + mbedtls_ecp_group grp; + + mbedtls_ecp_group_init( &grp ); + + if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) + goto cleanup; + + ret = pk_group_id_from_group( &grp, grp_id ); + +cleanup: + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ + +/* + * Use EC parameters to initialise an EC group + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + */ +static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + + if( params->tag == MBEDTLS_ASN1_OID ) + { + if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); + } + else + { +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) + return( ret ); +#else + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +#endif + } + + /* + * grp may already be initilialized; if so, make sure IDs match + */ + if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * EC public key is an EC point + * + * The caller is responsible for clearing the structure upon failure if + * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE + * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. + */ +static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, + mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, + (const unsigned char *) *p, end - *p ) ) == 0 ) + { + ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); + } + + /* + * We know mbedtls_ecp_point_read_binary consumed all bytes or failed + */ + *p = (unsigned char *) end; + + return( ret ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_get_rsapubkey( unsigned char **p, + const unsigned char *end, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->E ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +/* Get a PK algorithm identifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +static int pk_get_pk_alg( unsigned char **p, + const unsigned char *end, + mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) +{ + int ret; + mbedtls_asn1_buf alg_oid; + + memset( params, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); + + if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + /* + * No parameters with RSA (only for EC) + */ + if( *pk_alg == MBEDTLS_PK_RSA && + ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || + params->len != 0 ) ) + { + return( MBEDTLS_ERR_PK_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ) +{ + int ret; + size_t len; + mbedtls_asn1_buf alg_params; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) + { + ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); + if( ret == 0 ) + ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); + } else +#endif /* MBEDTLS_ECP_C */ + ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; + + if( ret == 0 && *p != end ) + ret = MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + + if( ret != 0 ) + mbedtls_pk_free( pk ); + + return( ret ); +} + +#if defined(MBEDTLS_RSA_C) +/* + * Parse a PKCS#1 encoded private RSA key + */ +static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( rsa->ver != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + if( p != end ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( ( ret = mbedtls_rsa_check_privkey( rsa ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Parse a SEC1 encoded private EC key + */ +static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, + const unsigned char *key, + size_t keylen ) +{ + int ret; + int version, pubkey_done; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + unsigned char *end2; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + pubkey_done = 0; + if( p != end ) + { + /* + * Is 'parameters' present? + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || + ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + /* + * Is 'publickey' present? If not, or if we can't read it (eg because it + * is compressed), create it from the private key. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( p + len != end2 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) + pubkey_done = 1; + else + { + /* + * The only acceptable failure mode of pk_get_ecpubkey() above + * is if the point format is not recognized. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( ! pubkey_done && + ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, + NULL, NULL ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ECP_C */ + +/* + * Parse an unencrypted PKCS#8 encoded private key + */ +static int pk_parse_key_pkcs8_unencrypted_der( + mbedtls_pk_context *pk, + const unsigned char* key, + size_t keylen ) +{ + int ret, version; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + /* + * This function parses the PrivatKeyInfo object (PKCS#8 v1.2 = RFC 5208) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * + * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey + */ + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); + + if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + return( 0 ); +} + +/* + * Parse an encrypted PKCS#8 encoded private key + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) +static int pk_parse_key_pkcs8_encrypted_der( + mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret, decrypted = 0; + size_t len; + unsigned char buf[2048]; + unsigned char *p, *end; + mbedtls_asn1_buf pbe_alg_oid, pbe_params; +#if defined(MBEDTLS_PKCS12_C) + mbedtls_cipher_type_t cipher_alg; + mbedtls_md_type_t md_alg; +#endif + + memset( buf, 0, sizeof( buf ) ); + + p = (unsigned char *) key; + end = p + keylen; + + if( pwdlen == 0 ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivatKeyInfo object (PKCS#8) + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData + * } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + * + * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len > sizeof( buf ) ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* + * Decrypt EncryptedData with appropriate PDE + */ +#if defined(MBEDTLS_PKCS12_C) + if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, + cipher_alg, md_alg, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, + MBEDTLS_PKCS12_PBE_DECRYPT, + pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + return( ret ); + } + + // Best guess for password mismatch when using RC4. If first tag is + // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + // + if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PKCS5_C) + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS5_C */ + { + ((void) pwd); + } + + if( decrypted == 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); +} +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + +/* + * Parse a private key + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + const mbedtls_pk_info_t *pk_info; + +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + + if( ret == 0 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN EC PRIVATE KEY-----", + "-----END EC PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_ECP_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, + pem.buf, pem.buflen, + pwd, pwdlen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ +#else + ((void) ret); + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_PEM_PARSE_C */ + + /* + * At this point we only know it's not a PEM formatted key. Could be any + * of the known DER encoded private key formats + * + * We try the different DER format parsers to see if one passes without + * error + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, + pwd, pwdlen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); + + if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) + { + return( ret ); + } +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + +#if defined(MBEDTLS_RSA_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_ECP_C */ + + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +} + +/* + * Parse a public key + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char *p; +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PUBLIC KEY-----", + "-----END PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + key = pem.buf; + keylen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_PEM_PARSE_C */ + p = (unsigned char *) key; + + ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + + return( ret ); +} + +#endif /* MBEDTLS_PK_PARSE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkwrite.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkwrite.c new file mode 100644 index 0000000000..83b798c119 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/pkwrite.c @@ -0,0 +1,439 @@ +/* + * Public Key layer for writing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_WRITE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->N ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public key is an EC point + */ +static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; + + if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, buf, sizeof( buf ) ) ) != 0 ) + { + return( ret ); + } + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *p -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_ECP_C */ + +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ) +{ + int ret; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) ); + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + const char *oid; + + c = buf + size; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + { + return( ret ); + } + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); + } +#endif + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len, + par_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c = buf + size; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->QP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DQ ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->Q ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->P ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->D ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->N ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key ); + size_t pub_len = 0, par_len = 0; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + + /* publicKey */ + MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + *--c = 0; + pub_len += 1; + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ); + len += pub_len; + + /* parameters */ + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) ); + + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) ); + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + len += par_len; + + /* privateKey: write as MPI then fix tag */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); + *c = MBEDTLS_ASN1_OCTET_STRING; + + /* version */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +#if defined(MBEDTLS_PEM_WRITE_C) + +#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" +#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n" + +#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n" +#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" + +/* + * Max sizes of key per types. Shown as tag + len (+ content). + */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSA public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 9 (rsa oid) + * + 1 + 1 (params null) + * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) + * RSAPublicKey ::= SEQUENCE { 1 + 3 + * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 + * } + */ +#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE + +/* + * RSA private keys: + * RSAPrivateKey ::= SEQUENCE { 1 + 3 + * version Version, 1 + 1 + 1 + * modulus INTEGER, 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported) + * } + */ +#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \ + MBEDTLS_MPI_MAX_SIZE % 2 +#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \ + + 5 * MPI_MAX_SIZE_2 + +#else /* MBEDTLS_RSA_C */ + +#define RSA_PUB_DER_MAX_BYTES 0 +#define RSA_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 7 (ec oid) + * + 1 + 1 + 9 (namedCurve oid) + * subjectPublicKey BIT STRING 1 + 2 + 1 [1] + * + 1 (point format) [1] + * + 2 * ECP_MAX (coords) [1] + * } + */ +#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES + +/* + * EC private keys: + * ECPrivateKey ::= SEQUENCE { 1 + 2 + * version INTEGER , 1 + 1 + 1 + * privateKey OCTET STRING, 1 + 1 + ECP_MAX + * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9) + * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above + * } + */ +#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES + +#else /* MBEDTLS_ECP_C */ + +#define ECP_PUB_DER_MAX_BYTES 0 +#define ECP_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_ECP_C */ + +#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES +#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \ + RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES + +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PUB_DER_MAX_BYTES]; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PRV_DER_MAX_BYTES]; + const char *begin, *end; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + begin = PEM_BEGIN_PRIVATE_KEY_RSA; + end = PEM_END_PRIVATE_KEY_RSA; + } + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + begin = PEM_BEGIN_PRIVATE_KEY_EC; + end = PEM_END_PRIVATE_KEY_EC; + } + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_pem_write_buffer( begin, end, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_PK_WRITE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/platform.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/platform.c new file mode 100644 index 0000000000..d634c6277e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/platform.c @@ -0,0 +1,193 @@ +/* + * Platform abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) + +#include "mbedtls/platform.h" + +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +static void *platform_calloc_uninit( size_t n, size_t size ) +{ + ((void) n); + ((void) size); + return( NULL ); +} + +#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit +#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */ + +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +static void platform_free_uninit( void *ptr ) +{ + ((void) ptr); +} + +#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FREE */ + +void * (*mbedtls_calloc)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +void (*mbedtls_free)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ) +{ + mbedtls_calloc = calloc_func; + mbedtls_free = free_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_MEMORY */ + +#if defined(_WIN32) +#include +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + int ret; + va_list argp; + + /* Avoid calling the invalid parameter handler by checking ourselves */ + if( s == NULL || n == 0 || fmt == NULL ) + return( -1 ); + + va_start( argp, fmt ); +#if defined(_TRUNCATE) + ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp ); +#else + ret = _vsnprintf( s, n, fmt, argp ); + if( ret < 0 || (size_t) ret == n ) + { + s[n-1] = '\0'; + ret = -1; + } +#endif + va_end( argp ); + + return( ret ); +} +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_snprintf_uninit( char * s, size_t n, + const char * format, ... ) +{ + ((void) s); + ((void) n); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_SNPRINTF platform_snprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_SNPRINTF */ + +int (*mbedtls_snprintf)( char * s, size_t n, + const char * format, + ... ) = MBEDTLS_PLATFORM_STD_SNPRINTF; + +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, + ... ) ) +{ + mbedtls_snprintf = snprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_printf_uninit( const char *format, ... ) +{ + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_PRINTF platform_printf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_PRINTF */ + +int (*mbedtls_printf)( const char *, ... ) = MBEDTLS_PLATFORM_STD_PRINTF; + +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ) +{ + mbedtls_printf = printf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_fprintf_uninit( FILE *stream, const char *format, ... ) +{ + ((void) stream); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_FPRINTF platform_fprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FPRINTF */ + +int (*mbedtls_fprintf)( FILE *, const char *, ... ) = + MBEDTLS_PLATFORM_STD_FPRINTF; + +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) ) +{ + mbedtls_fprintf = fprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static void platform_exit_uninit( int status ) +{ + ((void) status); +} + +#define MBEDTLS_PLATFORM_STD_EXIT platform_exit_uninit +#endif /* !MBEDTLS_PLATFORM_STD_EXIT */ + +void (*mbedtls_exit)( int status ) = MBEDTLS_PLATFORM_STD_EXIT; + +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ) +{ + mbedtls_exit = exit_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +#endif /* MBEDTLS_PLATFORM_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ripemd160.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ripemd160.c new file mode 100644 index 0000000000..a55cc3eb41 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ripemd160.c @@ -0,0 +1,464 @@ +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + +#include "mbedtls/ripemd160.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ) +{ + *dst = *src; +} + +/* + * RIPEMD-160 context setup + */ +void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, const unsigned char data[64] ) +{ + uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1( x, y, z ) ( x ^ y ^ z ) +#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) +#define F3( x, y, z ) ( ( x | ~y ) ^ z ) +#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) +#define F5( x, y, z ) ( x ^ ( y | ~z ) ) + +#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + a += f( b, c, d ) + X[r] + k; \ + a = S( a, s ) + e; \ + c = S( c, 10 ); + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + P( a, b, c, d, e, r, s, F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2( A, B, C, D, E, 0, 11, 5, 8 ); + P2( E, A, B, C, D, 1, 14, 14, 9 ); + P2( D, E, A, B, C, 2, 15, 7, 9 ); + P2( C, D, E, A, B, 3, 12, 0, 11 ); + P2( B, C, D, E, A, 4, 5, 9, 13 ); + P2( A, B, C, D, E, 5, 8, 2, 15 ); + P2( E, A, B, C, D, 6, 7, 11, 15 ); + P2( D, E, A, B, C, 7, 9, 4, 5 ); + P2( C, D, E, A, B, 8, 11, 13, 7 ); + P2( B, C, D, E, A, 9, 13, 6, 7 ); + P2( A, B, C, D, E, 10, 14, 15, 8 ); + P2( E, A, B, C, D, 11, 15, 8, 11 ); + P2( D, E, A, B, C, 12, 6, 1, 14 ); + P2( C, D, E, A, B, 13, 7, 10, 14 ); + P2( B, C, D, E, A, 14, 9, 3, 12 ); + P2( A, B, C, D, E, 15, 8, 12, 6 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2( E, A, B, C, D, 7, 7, 6, 9 ); + P2( D, E, A, B, C, 4, 6, 11, 13 ); + P2( C, D, E, A, B, 13, 8, 3, 15 ); + P2( B, C, D, E, A, 1, 13, 7, 7 ); + P2( A, B, C, D, E, 10, 11, 0, 12 ); + P2( E, A, B, C, D, 6, 9, 13, 8 ); + P2( D, E, A, B, C, 15, 7, 5, 9 ); + P2( C, D, E, A, B, 3, 15, 10, 11 ); + P2( B, C, D, E, A, 12, 7, 14, 7 ); + P2( A, B, C, D, E, 0, 12, 15, 7 ); + P2( E, A, B, C, D, 9, 15, 8, 12 ); + P2( D, E, A, B, C, 5, 9, 12, 7 ); + P2( C, D, E, A, B, 2, 11, 4, 6 ); + P2( B, C, D, E, A, 14, 7, 9, 15 ); + P2( A, B, C, D, E, 11, 13, 1, 13 ); + P2( E, A, B, C, D, 8, 12, 2, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2( D, E, A, B, C, 3, 11, 15, 9 ); + P2( C, D, E, A, B, 10, 13, 5, 7 ); + P2( B, C, D, E, A, 14, 6, 1, 15 ); + P2( A, B, C, D, E, 4, 7, 3, 11 ); + P2( E, A, B, C, D, 9, 14, 7, 8 ); + P2( D, E, A, B, C, 15, 9, 14, 6 ); + P2( C, D, E, A, B, 8, 13, 6, 6 ); + P2( B, C, D, E, A, 1, 15, 9, 14 ); + P2( A, B, C, D, E, 2, 14, 11, 12 ); + P2( E, A, B, C, D, 7, 8, 8, 13 ); + P2( D, E, A, B, C, 0, 13, 12, 5 ); + P2( C, D, E, A, B, 6, 6, 2, 14 ); + P2( B, C, D, E, A, 13, 5, 10, 13 ); + P2( A, B, C, D, E, 11, 12, 0, 13 ); + P2( E, A, B, C, D, 5, 7, 4, 7 ); + P2( D, E, A, B, C, 12, 5, 13, 5 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2( C, D, E, A, B, 1, 11, 8, 15 ); + P2( B, C, D, E, A, 9, 12, 6, 5 ); + P2( A, B, C, D, E, 11, 14, 4, 8 ); + P2( E, A, B, C, D, 10, 15, 1, 11 ); + P2( D, E, A, B, C, 0, 14, 3, 14 ); + P2( C, D, E, A, B, 8, 15, 11, 14 ); + P2( B, C, D, E, A, 12, 9, 15, 6 ); + P2( A, B, C, D, E, 4, 8, 0, 14 ); + P2( E, A, B, C, D, 13, 9, 5, 6 ); + P2( D, E, A, B, C, 3, 14, 12, 9 ); + P2( C, D, E, A, B, 7, 5, 2, 12 ); + P2( B, C, D, E, A, 15, 6, 13, 9 ); + P2( A, B, C, D, E, 14, 8, 9, 12 ); + P2( E, A, B, C, D, 5, 6, 7, 5 ); + P2( D, E, A, B, C, 6, 5, 10, 15 ); + P2( C, D, E, A, B, 2, 12, 14, 8 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2( B, C, D, E, A, 4, 9, 12, 8 ); + P2( A, B, C, D, E, 0, 15, 15, 5 ); + P2( E, A, B, C, D, 5, 5, 10, 12 ); + P2( D, E, A, B, C, 9, 11, 4, 9 ); + P2( C, D, E, A, B, 7, 6, 1, 12 ); + P2( B, C, D, E, A, 12, 8, 5, 5 ); + P2( A, B, C, D, E, 2, 13, 8, 14 ); + P2( E, A, B, C, D, 10, 12, 7, 6 ); + P2( D, E, A, B, C, 14, 5, 6, 8 ); + P2( C, D, E, A, B, 1, 12, 2, 13 ); + P2( B, C, D, E, A, 3, 13, 13, 6 ); + P2( A, B, C, D, E, 8, 14, 14, 5 ); + P2( E, A, B, C, D, 11, 11, 0, 15 ); + P2( D, E, A, B, C, 6, 8, 3, 13 ); + P2( C, D, E, A, B, 15, 5, 9, 11 ); + P2( B, C, D, E, A, 13, 6, 11, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_ripemd160_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_ripemd160_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char ripemd160_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_ripemd160_update( ctx, ripemd160_padding, padn ); + mbedtls_ripemd160_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_UINT32_LE( ctx->state[4], output, 16 ); +} + +/* + * output = RIPEMD-160( input buffer ) + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ) +{ + mbedtls_ripemd160_context ctx; + + mbedtls_ripemd160_init( &ctx ); + mbedtls_ripemd160_starts( &ctx ); + mbedtls_ripemd160_update( &ctx, input, ilen ); + mbedtls_ripemd160_finish( &ctx, output ); + mbedtls_ripemd160_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * Test vectors from the RIPEMD-160 paper and + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html#HMAC + */ +#define TESTS 8 +#define KEYS 2 +static const char *ripemd160_test_input[TESTS] = +{ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", +}; + +static const unsigned char ripemd160_test_md[TESTS][20] = +{ + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, + { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, + 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, + { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, + 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb }, +}; + +/* + * Checkup routine + */ +int mbedtls_ripemd160_self_test( int verbose ) +{ + int i; + unsigned char output[20]; + + memset( output, 0, sizeof output ); + + for( i = 0; i < TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " RIPEMD-160 test #%d: ", i + 1 ); + + mbedtls_ripemd160( (const unsigned char *) ripemd160_test_input[i], + strlen( ripemd160_test_input[i] ), + output ); + + if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RIPEMD160_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/rsa.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/rsa.c new file mode 100644 index 0000000000..efdd055c41 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/rsa.c @@ -0,0 +1,1705 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. + * + * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf + * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PKCS1_V21) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ) +{ + memset( ctx, 0, sizeof( mbedtls_rsa_context ) ); + + mbedtls_rsa_set_padding( ctx, padding, hash_id ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Set padding for an existing RSA context + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id ) +{ + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mbedtls_mpi P1, Q1, H, G; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); + + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mbedtls_mpi_swap( &ctx->P, &ctx->Q ); + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &ctx->N ) != nbits ) + continue; + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G ); + + if( ret != 0 ) + { + mbedtls_rsa_free( ctx ); + return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_GENPRIME */ + +/* + * Check a public RSA key + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) +{ + if( !ctx->N.p || !ctx->E.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->N ) < 128 || + mbedtls_mpi_bitlen( &ctx->N ) > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->E ) < 2 || + mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + return( 0 ); +} + +/* + * Check a private RSA key + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) +{ + int ret; + mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; + + if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 ) + return( ret ); + + if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 ); + mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ ); + mbedtls_mpi_init( &QP ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); + /* + * Check for a valid PKCS1v2 private key + */ + if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || + mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || + mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || + mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || + mbedtls_mpi_cmp_int( &L2, 0 ) != 0 || + mbedtls_mpi_cmp_int( &I, 1 ) != 0 || + mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + +cleanup: + mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 ); + mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ ); + mbedtls_mpi_free( &QP ); + + if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) + return( ret ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret ); + + return( 0 ); +} + +/* + * Check if contexts holding a public and private key match + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ) +{ + if( mbedtls_rsa_check_pubkey( pub ) != 0 || + mbedtls_rsa_check_privkey( prv ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 || + mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T; + + mbedtls_mpi_init( &T ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int rsa_prepare_blinding( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count = 0; + + if( ctx->Vf.p != NULL ) + { + /* We already have blinding values, just update them by squaring */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); + + goto cleanup; + } + + /* Unblinding value: Vf = random number, invertible mod N */ + do { + if( count++ > 10 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); + + /* Blinding value: Vi = Vf^(-e) mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); + + +cleanup: + return( ret ); +} + +/* + * Do an RSA private key operation + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T, T1, T2; + + /* Make sure we have private key info, prevent possible misuse */ + if( ctx->P.p == NULL || ctx->Q.p == NULL || ctx->D.p == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + if( f_rng != NULL ) + { + /* + * Blinding + * T = T * Vi mod N + */ + MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + +#if defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); +#else + /* + * faster decryption using the CRT + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * T = T2 + T * Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if( f_rng != NULL ) + { + /* + * Unblind + * T = T * Vf mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, + size_t slen, mbedtls_md_context_t *md_ctx ) +{ + unsigned char mask[MBEDTLS_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + + memset( mask, 0, MBEDTLS_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = mbedtls_md_get_size( md_ctx->md_info ); + + // Generate and apply dbMask + // + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, src, slen ); + mbedtls_md_update( md_ctx, counter, 4 ); + mbedtls_md_finish( md_ctx, mask ); + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = mbedtls_md_get_size( md_info ); + + if( olen < ilen + 2 * hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + // Generate a random octet string seed + // + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + // Construct DB + // + mbedtls_md( md_info, label, label_len, p ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + mbedtls_md_init( &md_ctx ); + mbedtls_md_setup( &md_ctx, md_info, 0 ); + + // maskedDB: Apply dbMask to DB + // + mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ); + + // maskedSeed: Apply seedMask to seed + // + mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( olen < ilen + 11 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == MBEDTLS_RSA_PUBLIC ) + { + *p++ = MBEDTLS_RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + // Check if RNG failed to generate data + // + if( rng_dl == 0 || ret != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p++; + } + } + else + { + *p++ = MBEDTLS_RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Add the message padding, then do an RSA operation + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen, i, pad_len; + unsigned char *p, bad, pad_done; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + /* + * Parameters sanity checks + */ + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * RSA operation + */ + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + return( ret ); + + /* + * Unmask data and generate lHash + */ + hlen = mbedtls_md_get_size( md_info ); + + mbedtls_md_init( &md_ctx ); + mbedtls_md_setup( &md_ctx, md_info, 0 ); + + /* Generate lHash */ + mbedtls_md( md_info, label, label_len, lhash ); + + /* seed: Apply seedMask to maskedSeed */ + mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ); + + /* DB: Apply dbMask to maskedDB */ + mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + /* + * Check contents, in "constant-time" + */ + p = buf; + bad = 0; + + bad |= *p++; /* First byte must be 0 */ + + p += hlen; /* Skip seed */ + + /* Check lHash */ + for( i = 0; i < hlen; i++ ) + bad |= lhash[i] ^ *p++; + + /* Get zero-padding len, but always read till end of buffer + * (minus one, for the 01 byte) */ + pad_len = 0; + pad_done = 0; + for( i = 0; i < ilen - 2 * hlen - 2; i++ ) + { + pad_done |= p[i]; + pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_len; + bad |= *p++ ^ 0x01; + + /* + * The only information "leaked" is whether the padding was correct or not + * (eg, no data is copied if it was not correct). This meets the + * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between + * the different error conditions. + */ + if( bad != 0 ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( ilen - ( p - buf ) > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret; + size_t ilen, pad_count = 0, i; + unsigned char *p, bad, pad_done = 0; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + bad = 0; + + /* + * Check and get padding len in "constant-time" + */ + bad |= *p++; /* First byte must be 0 */ + + /* This test does not depend on secret data */ + if( mode == MBEDTLS_RSA_PRIVATE ) + { + bad |= *p++ ^ MBEDTLS_RSA_CRYPT; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + else + { + bad |= *p++ ^ MBEDTLS_RSA_SIGN; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ( p[i] != 0xFF ); + pad_count += ( pad_done == 0 ); + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + + if( bad ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( ilen - ( p - buf ) > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation, then remove the message padding + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen, + input, output, output_max_len ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0, + olen, input, output, + output_max_len ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[MBEDTLS_MD_MAX_SIZE]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( md_alg != MBEDTLS_MD_NONE ) + { + // Gather length of hash to sign + // + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( sig, 0, olen ); + + // Generate salt of length slen + // + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + // Note: EMSA-PSS encoding is over the length of N - 1 bits + // + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + p += olen - hlen * 2 - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + mbedtls_md_init( &md_ctx ); + mbedtls_md_setup( &md_ctx, md_info, 0 ); + + // Generate H = Hash( M' ) + // + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, p, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, salt, slen ); + mbedtls_md_finish( &md_ctx, p ); + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + offset = 1; + + // maskedDB: Apply dbMask to DB + // + mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, sig ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t nb_pad, olen, oid_size = 0; + unsigned char *p = sig; + const char *oid = NULL; + unsigned char *sig_try = NULL, *verif = NULL; + size_t i; + unsigned char diff; + volatile unsigned char diff_no_optimize; + int ret; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + nb_pad = olen - 3; + + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad -= 10 + oid_size; + + hashlen = mbedtls_md_get_size( md_info ); + } + + nb_pad -= hashlen; + + if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + if( md_alg == MBEDTLS_MD_NONE ) + { + memcpy( p, hash, hashlen ); + } + else + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + memcpy( p, hash, hashlen ); + } + + if( mode == MBEDTLS_RSA_PUBLIC ) + return( mbedtls_rsa_public( ctx, sig, sig ) ); + + /* + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + sig_try = mbedtls_calloc( 1, ctx->len ); + if( sig_try == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + verif = mbedtls_calloc( 1, ctx->len ); + if( verif == NULL ) + { + mbedtls_free( sig_try ); + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + } + + MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); + + /* Compare in constant time just in case */ + for( diff = 0, i = 0; i < ctx->len; i++ ) + diff |= verif[i] ^ sig[i]; + diff_no_optimize = diff; + + if( diff_no_optimize != 0 ) + { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy( sig, sig_try, ctx->len ); + +cleanup: + mbedtls_free( sig_try ); + mbedtls_free( verif ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char result[MBEDTLS_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t slen, msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + // Gather length of hash to sign + // + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( mgf1_hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + slen = siglen - hlen - 1; /* Currently length of salt + padding */ + + memset( zeros, 0, 8 ); + + // Note: EMSA-PSS verification is over the length of N - 1 bits + // + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_md_init( &md_ctx ); + mbedtls_md_setup( &md_ctx, md_info, 0 ); + + mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( p < buf + siglen && *p == 0 ) + p++; + + if( p == buf + siglen || + *p++ != 0x01 ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* Actual salt len */ + slen -= p - buf; + + if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + slen != (size_t) expected_salt_len ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + // Generate H = Hash( M' ) + // + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, zeros, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, p, slen ); + mbedtls_md_finish( &md_ctx, result ); + + mbedtls_md_free( &md_ctx ); + + if( memcmp( p + slen, result, hlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); +} + +/* + * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) + ? (mbedtls_md_type_t) ctx->hash_id + : md_alg; + + return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode, + md_alg, hashlen, hash, + mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY, + sig ) ); + +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + int ret; + size_t len, siglen, asn1_len; + unsigned char *p, *end; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + mbedtls_md_type_t msg_md_alg; + const mbedtls_md_info_t *md_info; + mbedtls_asn1_buf oid; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != MBEDTLS_RSA_SIGN ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + len = siglen - ( p - buf ); + + if( len == hashlen && md_alg == MBEDTLS_MD_NONE ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + } + + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + hashlen = mbedtls_md_get_size( md_info ); + + end = p + len; + + // Parse the ASN.1 structure inside the PKCS#1 v1.5 structure + // + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len + 2 != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len + 6 + hashlen != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + oid.p = p; + p += oid.len; + + if( mbedtls_oid_get_md_alg( &oid, &msg_md_alg ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( md_alg != msg_md_alg ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + /* + * assume the algorithm parameters must be NULL + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len != hashlen ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( memcmp( p, hash, hashlen ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p += hashlen; + + if( p != end ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation and check the message digest + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Copy the components of an RSA key + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) +{ + int ret; + + dst->ver = src->ver; + dst->len = src->len; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) ); + + dst->padding = src->padding; + dst->hash_id = src->hash_id; + +cleanup: + if( ret != 0 ) + mbedtls_rsa_free( dst ); + + return( ret ); +} + +/* + * Free the components of an RSA key + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ) +{ + mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->RN ); + mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP ); + mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +} + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +#if defined(MBEDTLS_PKCS1_V15) +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ +#if !defined(__OpenBSD__) + size_t i; + + if( rng_state != NULL ) + rng_state = NULL; + + for( i = 0; i < len; ++i ) + output[i] = rand(); +#else + if( rng_state != NULL ) + rng_state = NULL; + + arc4random_buf( output, len ); +#endif /* !OpenBSD */ + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Checkup routine + */ +int mbedtls_rsa_self_test( int verbose ) +{ + int ret = 0; +#if defined(MBEDTLS_PKCS1_V15) + size_t len; + mbedtls_rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(MBEDTLS_SHA1_C) + unsigned char sha1sum[20]; +#endif + + mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 ); + + rsa.len = KEY_LEN; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.N , 16, RSA_N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.E , 16, RSA_E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.D , 16, RSA_D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.P , 16, RSA_P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.Q , 16, RSA_Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DP, 16, RSA_DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DQ, 16, RSA_DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.QP, 16, RSA_QP ) ); + + if( verbose != 0 ) + mbedtls_printf( " RSA key validation: " ); + + if( mbedtls_rsa_check_pubkey( &rsa ) != 0 || + mbedtls_rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, PT_LEN, + rsa_plaintext, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 decryption : " ); + + if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, &len, + rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +#if defined(MBEDTLS_SHA1_C) + if( verbose != 0 ) + mbedtls_printf( "PKCS#1 data sign : " ); + + mbedtls_sha1( rsa_plaintext, PT_LEN, sha1sum ); + + if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 sig. verify: " ); + + if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); +#endif /* MBEDTLS_SHA1_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +cleanup: + mbedtls_rsa_free( &rsa ); +#else /* MBEDTLS_PKCS1_V15 */ + ((void) verbose); +#endif /* MBEDTLS_PKCS1_V15 */ + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RSA_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha1.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha1.c new file mode 100644 index 0000000000..c9acc64eee --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha1.c @@ -0,0 +1,451 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/sha1.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA1_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] ICACHE_RODATA_ATTR = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + unsigned char sha1_padding_local[64]; + + memcpy(sha1_padding_local, sha1_padding, 64); + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding_local, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + +#endif /* !MBEDTLS_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + mbedtls_sha1_starts( &ctx ); + mbedtls_sha1_update( &ctx, input, ilen ); + mbedtls_sha1_finish( &ctx, output ); + mbedtls_sha1_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * Checkup routine + */ +int mbedtls_sha1_self_test( int verbose ) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " SHA-1 test #%d: ", i + 1 ); + + mbedtls_sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha1_update( &ctx, buf, buflen ); + } + else + mbedtls_sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + mbedtls_sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha256.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha256.c new file mode 100644 index 0000000000..946e6724ad --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha256.c @@ -0,0 +1,449 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#include "mbedtls/sha256.h" +#include "c_types.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA256_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; +} + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + +#if defined(MBEDTLS_SHA256_SMALLER) + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + + temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3]; + A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; +} +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_padding[64] ICACHE_RODATA_ATTR = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + unsigned char sha256_padding_local[64]; + + memcpy(sha256_padding_local, sha256_padding, 64); + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding_local, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); +} + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + mbedtls_sha256_starts( &ctx, is224 ); + mbedtls_sha256_update( &ctx, input, ilen ); + mbedtls_sha256_finish( &ctx, output ); + mbedtls_sha256_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha256_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha256_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha256_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * Checkup routine + */ +int mbedtls_sha256_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + mbedtls_sha256_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha256_update( &ctx, buf, buflen ); + } + else + mbedtls_sha256_update( &ctx, sha256_test_buf[j], + sha256_test_buflen[j] ); + + mbedtls_sha256_finish( &ctx, sha256sum ); + + if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha256_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha512.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha512.c new file mode 100644 index 0000000000..f8be80eb15 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/sha512.c @@ -0,0 +1,505 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA512_C) + +#include "mbedtls/sha512.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 +#else + #define UL64(x) x##ULL +#endif +#include "c_types.h" +#include "mem.h" +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA512_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif /* GET_UINT64_BE */ + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif /* PUT_UINT64_BE */ + +/* + * Round constants + */ +static const uint64_t K[80] ICACHE_RODATA_ATTR STORE_ATTR = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; +} + +#if !defined(MBEDTLS_SHA512_PROCESS_ALT) +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} +#endif /* !MBEDTLS_SHA512_PROCESS_ALT */ + +/* + * SHA-512 process buffer + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + unsigned int left; + + if( ilen == 0 ) + return; + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha512_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + mbedtls_sha512_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha512_padding[128] ICACHE_RODATA_ATTR STORE_ATTR = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-512 final digest + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ) +{ + size_t last, padn; + uint64_t high, low; + unsigned char msglen[16]; + unsigned char sha512_padding_local[128]; + + memcpy(sha512_padding_local, sha512_padding, 128); + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (size_t)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + + mbedtls_sha512_update( ctx, sha512_padding_local, padn ); + mbedtls_sha512_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +#endif /* !MBEDTLS_SHA512_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + mbedtls_sha512_context ctx; + + mbedtls_sha512_init( &ctx ); + mbedtls_sha512_starts( &ctx, is384 ); + mbedtls_sha512_update( &ctx, input, ilen ); + mbedtls_sha512_finish( &ctx, output ); + mbedtls_sha512_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha512_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const int sha512_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha512_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * Checkup routine + */ +int mbedtls_sha512_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha512sum[64]; + mbedtls_sha512_context ctx; + + mbedtls_sha512_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + mbedtls_sha512_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha512_update( &ctx, buf, buflen ); + } + else + mbedtls_sha512_update( &ctx, sha512_test_buf[j], + sha512_test_buflen[j] ); + + mbedtls_sha512_finish( &ctx, sha512sum ); + + if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha512_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cache.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cache.c new file mode 100644 index 0000000000..711bc535c0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cache.c @@ -0,0 +1,326 @@ +/* + * SSL session cache implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CACHE_C) + +#include "mbedtls/ssl_cache.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ) +{ + memset( cache, 0, sizeof( mbedtls_ssl_cache_context ) ); + + cache->timeout = MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT; + cache->max_entries = MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &cache->mutex ); +#endif +} + +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + time_t t = time( NULL ); +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *entry; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &cache->mutex ) != 0 ) + return( 1 ); +#endif + + cur = cache->chain; + entry = NULL; + + while( cur != NULL ) + { + entry = cur; + cur = cur->next; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - entry->timestamp ) > cache->timeout ) + continue; +#endif + + if( session->ciphersuite != entry->session.ciphersuite || + session->compression != entry->session.compression || + session->id_len != entry->session.id_len ) + continue; + + if( memcmp( session->id, entry->session.id, + entry->session.id_len ) != 0 ) + continue; + + memcpy( session->master, entry->session.master, 48 ); + + session->verify_result = entry->session.verify_result; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Restore peer certificate (without rest of the original chain) + */ + if( entry->peer_cert.p != NULL ) + { + if( ( session->peer_cert = mbedtls_calloc( 1, + sizeof(mbedtls_x509_crt) ) ) == NULL ) + { + ret = 1; + goto exit; + } + + mbedtls_x509_crt_init( session->peer_cert ); + if( mbedtls_x509_crt_parse( session->peer_cert, entry->peer_cert.p, + entry->peer_cert.len ) != 0 ) + { + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + ret = 1; + goto exit; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + ret = 0; + goto exit; + } + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + time_t t = time( NULL ), oldest = 0; + mbedtls_ssl_cache_entry *old = NULL; +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *prv; + int count = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &cache->mutex ) ) != 0 ) + return( ret ); +#endif + + cur = cache->chain; + prv = NULL; + + while( cur != NULL ) + { + count++; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - cur->timestamp ) > cache->timeout ) + { + cur->timestamp = t; + break; /* expired, reuse this slot, update timestamp */ + } +#endif + + if( memcmp( session->id, cur->session.id, cur->session.id_len ) == 0 ) + break; /* client reconnected, keep timestamp for session id */ + +#if defined(MBEDTLS_HAVE_TIME) + if( oldest == 0 || cur->timestamp < oldest ) + { + oldest = cur->timestamp; + old = cur; + } +#endif + + prv = cur; + cur = cur->next; + } + + if( cur == NULL ) + { +#if defined(MBEDTLS_HAVE_TIME) + /* + * Reuse oldest entry if max_entries reached + */ + if( count >= cache->max_entries ) + { + if( old == NULL ) + { + ret = 1; + goto exit; + } + + cur = old; + } +#else /* MBEDTLS_HAVE_TIME */ + /* + * Reuse first entry in chain if max_entries reached, + * but move to last place + */ + if( count >= cache->max_entries ) + { + if( cache->chain == NULL ) + { + ret = 1; + goto exit; + } + + cur = cache->chain; + cache->chain = cur->next; + cur->next = NULL; + prv->next = cur; + } +#endif /* MBEDTLS_HAVE_TIME */ + else + { + /* + * max_entries not reached, create new entry + */ + cur = mbedtls_calloc( 1, sizeof(mbedtls_ssl_cache_entry) ); + if( cur == NULL ) + { + ret = 1; + goto exit; + } + + if( prv == NULL ) + cache->chain = cur; + else + prv->next = cur; + } + +#if defined(MBEDTLS_HAVE_TIME) + cur->timestamp = t; +#endif + } + + memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * If we're reusing an entry, free its certificate first + */ + if( cur->peer_cert.p != NULL ) + { + mbedtls_free( cur->peer_cert.p ); + memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) ); + } + + /* + * Store peer certificate + */ + if( session->peer_cert != NULL ) + { + cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len ); + if( cur->peer_cert.p == NULL ) + { + ret = 1; + goto exit; + } + + memcpy( cur->peer_cert.p, session->peer_cert->raw.p, + session->peer_cert->raw.len ); + cur->peer_cert.len = session->peer_cert->raw.len; + + cur->session.peer_cert = NULL; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + ret = 0; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +#if defined(MBEDTLS_HAVE_TIME) +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ) +{ + if( timeout < 0 ) timeout = 0; + + cache->timeout = timeout; +} +#endif /* MBEDTLS_HAVE_TIME */ + +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ) +{ + if( max < 0 ) max = 0; + + cache->max_entries = max; +} + +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ) +{ + mbedtls_ssl_cache_entry *cur, *prv; + + cur = cache->chain; + + while( cur != NULL ) + { + prv = cur; + cur = cur->next; + + mbedtls_ssl_session_free( &prv->session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_free( prv->peer_cert.p ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + mbedtls_free( prv ); + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &cache->mutex ); +#endif +} + +#endif /* MBEDTLS_SSL_CACHE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ciphersuites.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ciphersuites.c new file mode 100644 index 0000000000..862deb38a6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ciphersuites.c @@ -0,0 +1,1853 @@ +/** + * \file ssl_ciphersuites.c + * + * \brief SSL ciphersuites for mbed TLS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#include "mbedtls/ssl_ciphersuites.h" +#include "mbedtls/ssl.h" + +#include "c_types.h" + +#include + +/* + * Ordered from most preferred to least preferred in terms of security. + * + * Current rule (except rc4, weak and null which come last): + * 1. By key exchange: + * Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK + * 2. By key length and cipher: + * AES-256 > Camellia-256 > AES-128 > Camellia-128 > 3DES + * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8 + * 4. By hash function used when relevant + * 5. By key exchange/auth again: EC > non-EC + */ +static const int ciphersuite_preference[] ICACHE_RODATA_ATTR STORE_ATTR = +{ +#if defined(MBEDTLS_SSL_CIPHERSUITES) + MBEDTLS_SSL_CIPHERSUITES, +#else + /* All AES-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + + /* All AES-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + + /* All remaining >= 128-bit ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + + /* The PSK ephemeral suites */ + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, + + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, + + MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + + /* The ECJPAKE suite */ + MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, + + /* All AES-256 suites */ + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + + /* All AES-128 suites */ + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + + /* All remaining >= 128-bit suites */ + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + + /* The RSA PSK suites */ + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, + + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, + + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + + /* The PSK suites */ + MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, + + MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, + + MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, + + /* RC4 suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, + + /* Weak suites */ + MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, + + /* NULL suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, + + MBEDTLS_TLS_RSA_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_WITH_NULL_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_PSK_WITH_NULL_SHA, + +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + 0 +}; + +static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] ICACHE_RODATA_ATTR STORE_ATTR = +{ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, "TLS-ECDHE-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, "TLS-ECDHE-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, "TLS-DHE-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, "TLS-DHE-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, "TLS-DHE-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, "TLS-DHE-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM, "TLS-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, "TLS-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM, "TLS-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, "TLS-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, "TLS-RSA-WITH-RC4-128-MD5", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, "TLS-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, "TLS-ECDH-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, "TLS-ECDH-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, "TLS-ECDH-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, "TLS-ECDH-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, "TLS-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, "TLS-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, "TLS-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, "TLS-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, "TLS-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, "TLS-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM, "TLS-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, "TLS-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM, "TLS-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, "TLS-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, "TLS-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, "TLS-DHE-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, "TLS-DHE-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, "TLS-DHE-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, "TLS-DHE-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, "TLS-DHE-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, "TLS-DHE-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, "TLS-DHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, "TLS-ECDHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, "TLS-RSA-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, "TLS-RSA-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, "TLS-RSA-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, "TLS-ECJPAKE-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECJPAKE, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_NULL_MD5, "TLS-RSA-WITH-NULL-MD5", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA, "TLS-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA256, "TLS-RSA-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA, "TLS-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA256, "TLS-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA384, "TLS-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, "TLS-DHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, "TLS-DHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, "TLS-DHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, "TLS-ECDHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, "TLS-ECDHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, "TLS-ECDHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, "TLS-RSA-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, "TLS-RSA-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, "TLS-RSA-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS-DHE-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, "TLS-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ + + { 0, "", + MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, + 0, 0, 0, 0, 0 } +}; + +#if defined(MBEDTLS_SSL_CIPHERSUITES) +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + return( ciphersuite_preference ); +} +#else +#define MAX_CIPHERSUITES sizeof( ciphersuite_definitions ) / \ + sizeof( ciphersuite_definitions[0] ) +static int supported_ciphersuites[MAX_CIPHERSUITES]; +static int supported_init = 0; + +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + /* + * On initial call filter out all ciphersuites not supported by current + * build based on presence in the ciphersuite_definitions. + */ + if( supported_init == 0 ) + { + const int *p; + int *q; + + for( p = ciphersuite_preference, q = supported_ciphersuites; + *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; + p++ ) + { +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + const mbedtls_ssl_ciphersuite_t *cs_info; + if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL && + cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 ) +#else + if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL ) +#endif + *(q++) = *p; + } + *q = 0; + + supported_init = 1; + } + + return( supported_ciphersuites ); +} +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( + const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + if( NULL == ciphersuite_name ) + return( NULL ); + + while( cur->id != 0 ) + { + if( 0 == strcmp( cur->name, ciphersuite_name ) ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + while( cur->id != 0 ) + { + if( cur->id == ciphersuite ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id ); + + if( cur == NULL ) + return( "unknown" ); + + return( cur->name ); +} + +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_string( ciphersuite_name ); + + if( cur == NULL ) + return( 0 ); + + return( cur->id ); +} + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + return( MBEDTLS_PK_RSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( MBEDTLS_PK_ECDSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( MBEDTLS_PK_ECKEY ); + + default: + return( MBEDTLS_PK_NONE ); + } +} +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cli.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cli.c new file mode 100644 index 0000000000..c41f046a0b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cli.c @@ -0,0 +1,3393 @@ +/* + * SSLv3/TLSv1 client-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CLI_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t hostname_len; + + *olen = 0; + + if( ssl->hostname == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + hostname_len = strlen( ssl->hostname ); + + if( end < p || (size_t)( end - p ) < hostname_len + 9 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 5) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 5) ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 3) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 3) ) & 0xFF ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, hostname_len ); + + *olen = hostname_len + 9; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding renegotiation extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 + ssl->verify_data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Secure renegotiation + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + + *p++ = 0x00; + *p++ = ( ssl->verify_data_len + 1 ) & 0xFF; + *p++ = ssl->verify_data_len & 0xFF; + + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + + *olen = 5 + ssl->verify_data_len; +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Only if we handle at least one key exchange that needs signatures. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static void ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t sig_alg_len = 0; + const int *md; +#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) + unsigned char *sig_alg_list = buf + 6; +#endif + + *olen = 0; + + if( ssl->conf->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) ); + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_len += 2; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_len += 2; +#endif + } + + if( end < p || (size_t)( end - p ) < sig_alg_len + 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Prepare signature_algorithms extension (TLS 1.2) + */ + sig_alg_len = 0; + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_RSA; +#endif + } + + /* + * enum { + * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + * sha512(6), (255) + * } HashAlgorithm; + * + * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + * SignatureAlgorithm; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2..2^16-2>; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + *olen = 6 + sig_alg_len; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + unsigned char *elliptic_curve_list = p + 6; + size_t elliptic_curve_len = 0; + const mbedtls_ecp_curve_info *info; +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *grp_id; +#else + ((void) ssl); +#endif + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) ); + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) + { +#endif + elliptic_curve_len += 2; + } + + if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + elliptic_curve_len = 0; + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) + { +#endif + + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; + } + + if( elliptic_curve_len == 0 ) + return; + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len ) ) & 0xFF ); + + *olen = 6 + elliptic_curve_len; +} + +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_point_formats extension" ) ); + + if( end < p || (size_t)( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly extension if we can't use EC J-PAKE anyway */ + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding ecjpake_kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + /* + * We may need to send ClientHello multiple times for Hello verification. + * We don't want to compute fresh values every time (both for performance + * and consistency reasons), so cache the extension content. + */ + if( ssl->handshake->ecjpake_cache == NULL || + ssl->handshake->ecjpake_cache_len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "generating new ecjpake parameters" ) ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + ssl->handshake->ecjpake_cache = mbedtls_calloc( 1, kkpp_len ); + if( ssl->handshake->ecjpake_cache == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "allocation failed" ) ); + return; + } + + memcpy( ssl->handshake->ecjpake_cache, p + 2, kkpp_len ); + ssl->handshake->ecjpake_cache_len = kkpp_len; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "re-using cached ecjpake parameters" ) ); + + kkpp_len = ssl->handshake->ecjpake_cache_len; + + if( (size_t)( end - p - 2 ) < kkpp_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + memcpy( p + 2, ssl->handshake->ecjpake_cache, kkpp_len ); + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->conf->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding truncated_hmac extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding encrypt_then_mac " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding extended_master_secret " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t tlen = ssl->session_negotiate->ticket_len; + + *olen = 0; + + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding session ticket extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 + tlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( tlen ) & 0xFF ); + + *olen = 4; + + if( ssl->session_negotiate->ticket == NULL || tlen == 0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "sending session ticket of length %d", tlen ) ); + + memcpy( p, ssl->session_negotiate->ticket, tlen ); + + *olen += tlen; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += (unsigned char)( strlen( *cur ) & 0xFF ) + 1; + + if( end < p || (size_t)( end - p ) < 6 + alpnlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + *p = (unsigned char)( strlen( *cur ) & 0xFF ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 (ext_type) - 2 (ext_len) - 2 (list_len) */ + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + /* Extension length = olen - 2 (ext_type) - 2 (ext_len) */ + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Generate random bytes for ClientHello + */ +static int ssl_generate_random( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->handshake->randbytes; +#if defined(MBEDTLS_HAVE_TIME) + time_t t; +#endif + + /* + * When responding to a verify request, MUST reuse random (RFC 6347 4.2.1) + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie != NULL ) + { + return( 0 ); + } +#endif + +#if defined(MBEDTLS_HAVE_TIME) + t = time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t i, n, olen, ext_len = 0; + unsigned char *buf; + unsigned char *p, *q; + unsigned char offer_compress; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + ssl->major_ver = ssl->conf->min_major_ver; + ssl->minor_ver = ssl->conf->min_minor_ver; + } + + if( ssl->conf->max_major_ver == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, " + "consider using mbedtls_ssl_config_defaults()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 highest version supported + * 6 . 9 current UNIX time + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", + buf[4], buf[5] ) ); + + if( ( ret = ssl_generate_random( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_generate_random", ret ); + return( ret ); + } + + memcpy( p, ssl->handshake->randbytes, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", p, 32 ); + p += 32; + + /* + * 38 . 38 session id length + * 39 . 39+n session id + * 39+n . 39+n DTLS only: cookie length (1 byte) + * 40+n . .. DTSL only: cookie + * .. . .. ciphersuitelist length (2 bytes) + * .. . .. ciphersuitelist + * .. . .. compression methods length (1 byte) + * .. . .. compression methods + * .. . .. extensions length (2 bytes) + * .. . .. extensions + */ + n = ssl->session_negotiate->id_len; + + if( n < 16 || n > 32 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->handshake->resume == 0 ) + { + n = 0; + } + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + /* + * RFC 5077 section 3.4: "When presenting a ticket, the client MAY + * generate and include a Session ID in the TLS ClientHello." + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ssl->session_negotiate->ticket != NULL && + ssl->session_negotiate->ticket_len != 0 ) + { + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 ); + + if( ret != 0 ) + return( ret ); + + ssl->session_negotiate->id_len = n = 32; + } + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + *p++ = (unsigned char) n; + + for( i = 0; i < n; i++ ) + *p++ = ssl->session_negotiate->id[i]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); + + /* + * DTLS cookie + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no verify cookie to send" ) ); + *p++ = 0; + } + else + { + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + + *p++ = ssl->handshake->verify_cookie_len; + memcpy( p, ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + p += ssl->handshake->verify_cookie_len; + } + } +#endif + + /* + * Ciphersuite list + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + /* Skip writing ciphersuite length for now */ + n = 0; + q = p; + p += 2; + + for( i = 0; ciphersuites[i] != 0; i++ ) + { + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + continue; + + if( ciphersuite_info->min_minor_ver > ssl->conf->max_minor_ver || + ciphersuite_info->max_minor_ver < ssl->conf->min_minor_ver ) + continue; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + continue; +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + ciphersuite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + continue; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + continue; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x", + ciphersuites[i] ) ); + + n++; + *p++ = (unsigned char)( ciphersuites[i] >> 8 ); + *p++ = (unsigned char)( ciphersuites[i] ); + } + + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ); + n++; + } + + /* Some versions of OpenSSL don't handle it correctly if not at end */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + if( ssl->conf->fallback == MBEDTLS_SSL_IS_FALLBACK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding FALLBACK_SCSV" ) ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ); + n++; + } +#endif + + *q++ = (unsigned char)( n >> 7 ); + *q++ = (unsigned char)( n << 1 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + offer_compress = 1; +#else + offer_compress = 0; +#endif + + /* + * We don't support compression with DTLS right now: is many records come + * in the same datagram, uncompressing one could overwrite the next one. + * We don't want to add complexity for handling that case unless there is + * an actual need for it. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + offer_compress = 0; +#endif + + if( offer_compress ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d", + MBEDTLS_SSL_COMPRESS_DEFLATE, MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 2; + *p++ = MBEDTLS_SSL_COMPRESS_DEFLATE; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", + MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 1; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + + // First write extensions, then the total length + // +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ssl_write_hostname_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + ssl_write_signature_algorithms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_supported_elliptic_curves_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + /* olen unused if all extensions are disabled */ + ((void) olen); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + + return( 0 ); +} + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len * 2 || + buf[0] != ssl->verify_data_len * 2 || + mbedtls_ssl_safer_memcmp( buf + 1, + ssl->own_verify_data, ssl->verify_data_len ) != 0 || + mbedtls_ssl_safer_memcmp( buf + 1 + ssl->verify_data_len, + ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x00 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours (and len is always 1) + */ + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->conf->mfl_code ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->new_session_ticket = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_point_formats_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + list_size = buf[0]; + if( list_size + 1 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no point format in common" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( ssl->transform_negotiate->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + /* If we got here, we no longer need our cached extension */ + mbedtls_free( ssl->handshake->ecjpake_cache ); + ssl->handshake->ecjpake_cache = NULL; + ssl->handshake->ecjpake_cache_len = 0; + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const char **p; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + name_len = buf[2]; + if( name_len != list_len - 1 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* Check that the server chosen protocol was in our list and save it */ + for( p = ssl->conf->alpn_list; *p != NULL; p++ ) + { + if( name_len == strlen( *p ) && + memcmp( buf + 3, *p, name_len ) == 0 ) + { + ssl->alpn_chosen = *p; + return( 0 ); + } + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Parse HelloVerifyRequest. Only called after verifying the HS type. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + const unsigned char *p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + int major_ver, minor_ver; + unsigned char cookie_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, p ); + p += 2; + + /* + * Since the RFC is not clear on this point, accept DTLS 1.0 (TLS 1.1) + * even is lower than our min version. + */ + if( major_ver < MBEDTLS_SSL_MAJOR_VERSION_3 || + minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 || + major_ver > ssl->conf->max_major_ver || + minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server version" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + cookie_len = *p++; + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie", p, cookie_len ); + + mbedtls_free( ssl->handshake->verify_cookie ); + + ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len ); + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", cookie_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ssl->handshake->verify_cookie, p, cookie_len ); + ssl->handshake->verify_cookie_len = cookie_len; + + /* Start over at ClientHello */ + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + mbedtls_ssl_reset_checksum( ssl ); + + mbedtls_ssl_recv_flight_completed( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) +{ + int ret, i; + size_t n; + size_t ext_len; + unsigned char *buf, *ext; + unsigned char comp; +#if defined(MBEDTLS_ZLIB_SUPPORT) + int accept_comp; +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const mbedtls_ssl_ciphersuite_t *suite_info; +#if defined(MBEDTLS_DEBUG_C) + uint32_t t; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + buf = ssl->in_msg; + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_records_seen++; + + if( ssl->conf->renego_max_records >= 0 && + ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by server" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-handshake message during renego" ) ); + return( MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( buf[0] == MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received hello verify request" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + return( ssl_parse_hello_verify_request( ssl ) ); + } + else + { + /* We made it through the verification process */ + mbedtls_free( ssl->handshake->verify_cookie ); + ssl->handshake->verify_cookie = NULL; + ssl->handshake->verify_cookie_len = 0; + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ssl->in_hslen < 38 + mbedtls_ssl_hs_hdr_len( ssl ) || + buf[0] != MBEDTLS_SSL_HS_SERVER_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* + * 0 . 1 server_version + * 2 . 33 random (maybe including 4 bytes of Unix time) + * 34 . 34 session_id length = n + * 35 . 34+n session_id + * 35+n . 36+n cipher_suite + * 37+n . 37+n compression_method + * + * 38+n . 39+n extensions length (optional) + * 40+n . .. extensions + */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver || + ssl->major_ver > ssl->conf->max_major_ver || + ssl->minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server version out of bounds - " + " min: [%d:%d], server: [%d:%d], max: [%d:%d]", + ssl->conf->min_major_ver, ssl->conf->min_minor_ver, + ssl->major_ver, ssl->minor_ver, + ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + +#if defined(MBEDTLS_DEBUG_C) + t = ( (uint32_t) buf[2] << 24 ) + | ( (uint32_t) buf[3] << 16 ) + | ( (uint32_t) buf[4] << 8 ) + | ( (uint32_t) buf[5] ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#endif + + memcpy( ssl->handshake->randbytes + 32, buf + 2, 32 ); + + n = buf[34]; + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 2, 32 ); + + if( n > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->in_hslen > mbedtls_ssl_hs_hdr_len( ssl ) + 39 + n ) + { + ext_len = ( ( buf[38 + n] << 8 ) + | ( buf[39 + n] ) ); + + if( ( ext_len > 0 && ext_len < 4 ) || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 40 + n + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else if( ssl->in_hslen == mbedtls_ssl_hs_hdr_len( ssl ) + 38 + n ) + { + ext_len = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* ciphersuite (used later) */ + i = ( buf[35 + n] << 8 ) | buf[36 + n]; + + /* + * Read and check compression + */ + comp = buf[37 + n]; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + accept_comp = 0; + else +#endif + accept_comp = 1; + + if( comp != MBEDTLS_SSL_COMPRESS_NULL && + ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) ) +#else /* MBEDTLS_ZLIB_SUPPORT */ + if( comp != MBEDTLS_SSL_COMPRESS_NULL ) +#endif/* MBEDTLS_ZLIB_SUPPORT */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * Initialize update checksum functions + */ + ssl->transform_negotiate->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->transform_negotiate->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 35, n ); + + /* + * Check if the session can be resumed + */ + if( ssl->handshake->resume == 0 || n == 0 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->session_negotiate->ciphersuite != i || + ssl->session_negotiate->compression != comp || + ssl->session_negotiate->id_len != n || + memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 ) + { + ssl->state++; + ssl->handshake->resume = 0; +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif + ssl->session_negotiate->ciphersuite = i; + ssl->session_negotiate->compression = comp; + ssl->session_negotiate->id_len = n; + memcpy( ssl->session_negotiate->id, buf + 35, n ); + } + else + { + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %04x", i ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[37 + n] ) ); + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL +#if defined(MBEDTLS_ARC4_C) + || ( ssl->conf->arc4_disabled && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) ); + + i = 0; + while( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + if( comp != MBEDTLS_SSL_COMPRESS_NULL +#if defined(MBEDTLS_ZLIB_SUPPORT) + && comp != MBEDTLS_SSL_COMPRESS_DEFLATE +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + ssl->session_negotiate->compression = comp; + + ext = buf + 40 + n; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) ); + + while( ext_len ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + if( ( ret = ssl_parse_renegotiation_info( ssl, ext + 4, + ext_size ) ) != 0 ) + return( ret ); + + break; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + if( ( ret = ssl_parse_max_fragment_length_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated_hmac extension" ) ); + + if( ( ret = ssl_parse_truncated_hmac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt_then_mac extension" ) ); + + if( ( ret = ssl_parse_encrypt_then_mac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended_master_secret extension" ) ); + + if( ( ret = ssl_parse_extended_ms_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session_ticket extension" ) ); + + if( ( ret = ssl_parse_session_ticket_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_point_formats extension" ) ); + + if( ( ret = ssl_parse_supported_point_formats_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake_kkpp extension" ) ); + + if( ( ret = ssl_parse_ecjpake_kkpp( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + if( ( ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ) ) != 0 ) + return( ret ); + + break; +#endif /* MBEDTLS_SSL_ALPN */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl, unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_dhm_read_params( &ssl->handshake->dhm_ctx, p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, ( "mbedtls_dhm_read_params" ), ret ); + return( ret ); + } + + if( ssl->handshake->dhm_ctx.len * 8 < ssl->conf->dhm_min_bitlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DHM prime too short: %d < %d", + ssl->handshake->dhm_ctx.len * 8, + ssl->conf->dhm_min_bitlen ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + if( ( ret = mbedtls_ecdh_read_params( &ssl->handshake->ecdh_ctx, + (const unsigned char **) p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret ); + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message (ECDHE curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t len; + ((void) ssl); + + /* + * PSK parameters: + * + * opaque psk_identity_hint<0..2^16-1>; + */ + len = (*p)[0] << 8 | (*p)[1]; + *p += 2; + + if( (*p) + len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message (psk_identity_hint length)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + // TODO: Retrieve PSK identity hint and callback to app + // + *p += len; + ret = 0; + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +/* + * Generate a pre-master secret and encrypt it with the server's RSA key + */ +static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, + size_t offset, size_t *olen, + size_t pms_offset ) +{ + int ret; + size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2; + unsigned char *p = ssl->handshake->premaster + pms_offset; + + if( offset + len_bytes > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small for encrypted pms" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Generate (part of) the pre-master as + * struct { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret; + */ + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p + 2, 46 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_rng", ret ); + return( ret ); + } + + ssl->handshake->pmslen = 48; + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Now write it out, encrypted + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk, + p, ssl->handshake->pmslen, + ssl->out_msg + offset + len_bytes, olen, + MBEDTLS_SSL_MAX_CONTENT_LEN - offset - len_bytes, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( len_bytes == 2 ) + { + ssl->out_msg[offset+0] = (unsigned char)( *olen >> 8 ); + ssl->out_msg[offset+1] = (unsigned char)( *olen ); + *olen += 2; + } +#endif + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_signature_algorithm( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg ) +{ + ((void) ssl); + *md_alg = MBEDTLS_MD_NONE; + *pk_alg = MBEDTLS_PK_NONE; + + /* Only in TLS 1.2 */ + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + return( 0 ); + } + + if( (*p) + 2 > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + /* + * Get hash algorithm + */ + if( ( *md_alg = mbedtls_ssl_md_alg_from_hash( (*p)[0] ) ) == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server used unsupported " + "HashAlgorithm %d", *(p)[0] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Get signature algorithm + */ + if( ( *pk_alg = mbedtls_ssl_pk_alg_from_sig( (*p)[1] ) ) == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used unsupported " + "SignatureAlgorithm %d", (*p)[1] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Check if the hash is acceptable + */ + if( mbedtls_ssl_check_sig_hash( ssl, *md_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used HashAlgorithm " + "that was not offered" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used SignatureAlgorithm %d", (*p)[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used HashAlgorithm %d", (*p)[0] ) ); + *p += 2; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ecp_keypair *peer_key; + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + peer_key = mbedtls_pk_ec( ssl->session_negotiate->peer_cert->pk ); + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key, + MBEDTLS_ECDH_THEIRS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + unsigned char *p, *end; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * ServerKeyExchange may be skipped with PSK and RSA-PSK when the server + * doesn't use a psk_identity_hint + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE ) + { + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + ssl->record_read = 1; + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + MBEDTLS_SSL_DEBUG_BUF( 3, "server key exchange", p, end - p ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ssl_parse_server_psk_hint( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } /* FALLTROUGH */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + ; /* nothing more to do */ + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ssl_parse_server_dh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + size_t sig_len, hashlen; + unsigned char hash[64]; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + size_t params_len = p - params; + + /* + * Handle the digitally-signed structure + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( ssl_parse_signature_algorithm( ssl, &p, end, + &md_alg, &pk_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( pk_alg != mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + + /* Default hash for ECDSA is SHA-1 */ + if( pk_alg == MBEDTLS_PK_ECDSA && md_alg == MBEDTLS_MD_NONE ) + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Read signature + */ + sig_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( end != p + sig_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "signature", p, sig_len ); + + /* + * Compute the hash that has been signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + hashlen = 36; + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, params, params_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, params, params_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + mbedtls_md_context_t ctx; + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, + mbedtls_md_info_from_type( md_alg ), 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, params, params_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Verify signature + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, + md_alg, hash, hashlen, p, sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +exit: + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf, *p; + size_t n = 0, m = 0; + size_t cert_type_len = 0, dn_len = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->record_read == 0 ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->record_read = 1; + } + + ssl->client_auth = 0; + ssl->state++; + + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + ssl->client_auth++; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + + if( ssl->client_auth == 0 ) + goto exit; + + ssl->record_read = 0; + + // TODO: handshake_failure alert for an anonymous server to request + // client authentication + + /* + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2^16-1>; -- TLS 1.2 only + * DistinguishedName certificate_authorities<0..2^16-1>; + * } CertificateRequest; + */ + buf = ssl->in_msg; + + // Retrieve cert types + // + cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )]; + n = cert_type_len; + + if( ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + p = buf + mbedtls_ssl_hs_hdr_len( ssl ) + 1; + while( cert_type_len > 0 ) + { +#if defined(MBEDTLS_RSA_C) + if( *p == MBEDTLS_SSL_CERT_TYPE_RSA_SIGN && + mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) + { + ssl->handshake->cert_type = MBEDTLS_SSL_CERT_TYPE_RSA_SIGN; + break; + } + else +#endif +#if defined(MBEDTLS_ECDSA_C) + if( *p == MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN && + mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECDSA ) ) + { + ssl->handshake->cert_type = MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN; + break; + } + else +#endif + { + ; /* Unsupported cert type, ignore */ + } + + cert_type_len--; + p++; + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* Ignored, see comments about hash in write_certificate_verify */ + // TODO: should check the signature part against our pk_key though + size_t sig_alg_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n] ) ); + + m += 2; + n += sig_alg_len; + + if( ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* Ignore certificate_authorities, we only have one cert anyway */ + // TODO: should not send cert if no CA matches + dn_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + m + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + m + n] ) ); + + n += dn_len; + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 3 + m + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + +exit: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + + return( 0 ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_parse_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) ); + + if( ssl->record_read == 0 ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + ssl->record_read = 0; + + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) || + ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO_DONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) ); + + return( 0 ); +} + +static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + /* + * DHM key exchange -- send G^X mod P + */ + n = ssl->handshake->dhm_ctx.len; + + ssl->out_msg[4] = (unsigned char)( n >> 8 ); + ssl->out_msg[5] = (unsigned char)( n ); + i = 6; + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + /* + * ECDH key exchange -- send client public value + */ + i = 4; + + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, + &n, + &ssl->out_msg[i], 1000, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * opaque psk_identity<0..2^16-1>; + */ + if( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for PSK" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + i = 4; + n = ssl->conf->psk_identity_len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity too long or " + "SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + memcpy( ssl->out_msg + i, ssl->conf->psk_identity, ssl->conf->psk_identity_len ); + i += ssl->conf->psk_identity_len; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + n = 0; + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 2 ) ) != 0 ) + return( ret ); + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + /* + * ClientDiffieHellmanPublic public (DHM send G^X mod P) + */ + n = ssl->handshake->dhm_ctx.len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity or DHM size too long" + " or SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * ClientECDiffieHellmanPublic public; + */ + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n, + &ssl->out_msg[i], MBEDTLS_SSL_MAX_CONTENT_LEN - i, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + i = 4; + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 0 ) ) != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + i = 4; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + ssl->out_msg + i, MBEDTLS_SSL_MAX_CONTENT_LEN - i, &n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + { + ((void) ciphersuite_info); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen = i + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + size_t n = 0, offset = 0; + unsigned char hash[48]; + unsigned char *hash_start = hash; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + unsigned int hashlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->client_auth == 0 || mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for certificate" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Make an RSA signature of the handshake digests + */ + ssl->handshake->calc_verify( ssl, hash ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(handshake_messages); + * + * sha_hash + * SHA(handshake_messages); + */ + hashlen = 36; + md_alg = MBEDTLS_MD_NONE; + + /* + * For ECDSA, default hash is SHA-1 only + */ + if( mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque handshake_messages[handshake_messages_length]; + * }; + * + * Taking shortcut here. We assume that the server always allows the + * PRF Hash function and has sent it in the allowed signature + * algorithms list received in the Certificate Request message. + * + * Until we encounter a server that does not, we will take this + * shortcut. + * + * Reason: Otherwise we should have running hashes for SHA512 and SHA224 + * in order to satisfy 'weird' needs from the server side. + */ + if( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + md_alg = MBEDTLS_MD_SHA384; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA384; + } + else + { + md_alg = MBEDTLS_MD_SHA256; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA256; + } + ssl->out_msg[5] = mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + offset = 2; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen, + ssl->out_msg + 6 + offset, &n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 ); + ssl->out_msg[5 + offset] = (unsigned char)( n ); + + ssl->out_msglen = 6 + n + offset; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + uint32_t lifetime; + size_t ticket_len; + unsigned char *ticket; + const unsigned char *msg; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 0 . 3 ticket_lifetime_hint + * 4 . 5 ticket_len (n) + * 6 . 5+n ticket content + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_NEW_SESSION_TICKET || + ssl->in_hslen < 6 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + msg = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + + lifetime = ( msg[0] << 24 ) | ( msg[1] << 16 ) | + ( msg[2] << 8 ) | ( msg[3] ); + + ticket_len = ( msg[4] << 8 ) | ( msg[5] ); + + if( ticket_len + 6 + mbedtls_ssl_hs_hdr_len( ssl ) != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", ticket_len ) ); + + /* We're not waiting for a NewSessionTicket message any more */ + ssl->handshake->new_session_ticket = 0; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + /* + * Zero-length ticket means the server changed his mind and doesn't want + * to send a ticket after all, so just forget it + */ + if( ticket_len == 0 ) + return( 0 ); + + mbedtls_zeroize( ssl->session_negotiate->ticket, + ssl->session_negotiate->ticket_len ); + mbedtls_free( ssl->session_negotiate->ticket ); + ssl->session_negotiate->ticket = NULL; + ssl->session_negotiate->ticket_len = 0; + + if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket, msg + 6, ticket_len ); + + ssl->session_negotiate->ticket = ticket; + ssl->session_negotiate->ticket_len = ticket_len; + ssl->session_negotiate->ticket_lifetime = lifetime; + + /* + * RFC 5077 section 3.4: + * "If the client receives a session ticket from the server, then it + * discards any Session ID that was sent in the ServerHello." + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket in use, discarding session id" ) ); + ssl->session_negotiate->id_len = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- client side -- single step + */ +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + /* Change state now, so that it is right in mbedtls_ssl_read_record(), used + * by DTLS for dropping out-of-sequence ChangeCipherSpec records */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC && + ssl->handshake->new_session_ticket != 0 ) + { + ssl->state = MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET; + } +#endif + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * ==> ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_write_client_hello( ssl ); + break; + + /* + * <== ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_parse_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_parse_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_parse_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_parse_server_hello_done( ssl ); + break; + + /* + * ==> ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_write_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_write_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); +#if defined(ESP8266_PLATFORM) + mbedtls_write_finished(ssl); +#endif + break; + + /* + * <== ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + ret = ssl_parse_new_session_ticket( ssl ); + break; +#endif + + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_CLI_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cookie.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cookie.c new file mode 100644 index 0000000000..7e0c573ad5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_cookie.c @@ -0,0 +1,260 @@ +/* + * DTLS cookie callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_COOKIE_C) + +#include "mbedtls/ssl_cookie.h" +#include "mbedtls/ssl_internal.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * If DTLS is in use, then at least one of SHA-1, SHA-256, SHA-512 is + * available. Try SHA-256 first, 512 wastes resources since we need to stay + * with max 32 bytes of cookie for DTLS 1.0 + */ +#if defined(MBEDTLS_SHA256_C) +#define COOKIE_MD MBEDTLS_MD_SHA224 +#define COOKIE_MD_OUTLEN 32 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA512_C) +#define COOKIE_MD MBEDTLS_MD_SHA384 +#define COOKIE_MD_OUTLEN 48 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA1_C) +#define COOKIE_MD MBEDTLS_MD_SHA1 +#define COOKIE_MD_OUTLEN 20 +#define COOKIE_HMAC_LEN 20 +#else +#error "DTLS hello verify needs SHA-1 or SHA-2" +#endif + +/* + * Cookies are formed of a 4-bytes timestamp (or serial number) and + * an HMAC of timestemp and client ID. + */ +#define COOKIE_LEN ( 4 + COOKIE_HMAC_LEN ) + +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_init( &ctx->hmac_ctx ); +#if !defined(MBEDTLS_HAVE_TIME) + ctx->serial = 0; +#endif + ctx->timeout = MBEDTLS_SSL_COOKIE_TIMEOUT; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ) +{ + ctx->timeout = delay; +} + +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_free( &ctx->hmac_ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + + mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_cookie_ctx ) ); +} + +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char key[COOKIE_MD_OUTLEN]; + + if( ( ret = f_rng( p_rng, key, sizeof( key ) ) ) != 0 ) + return( ret ); + + ret = mbedtls_md_setup( &ctx->hmac_ctx, mbedtls_md_info_from_type( COOKIE_MD ), 1 ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_md_hmac_starts( &ctx->hmac_ctx, key, sizeof( key ) ); + if( ret != 0 ) + return( ret ); + + mbedtls_zeroize( key, sizeof( key ) ); + + return( 0 ); +} + +/* + * Generate the HMAC part of a cookie + */ +static int ssl_cookie_hmac( mbedtls_md_context_t *hmac_ctx, + const unsigned char time[4], + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char hmac_out[COOKIE_MD_OUTLEN]; + + if( (size_t)( end - *p ) < COOKIE_HMAC_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + if( mbedtls_md_hmac_reset( hmac_ctx ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, time, 4 ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, cli_id, cli_id_len ) != 0 || + mbedtls_md_hmac_finish( hmac_ctx, hmac_out ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( *p, hmac_out, COOKIE_HMAC_LEN ); + *p += COOKIE_HMAC_LEN; + + return( 0 ); +} + +/* + * Generate cookie for DTLS ClientHello verification + */ +int mbedtls_ssl_cookie_write( void *p_ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + int ret; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long t; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( (size_t)( end - *p ) < COOKIE_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_HAVE_TIME) + t = (unsigned long) time( NULL ); +#else + t = ctx->serial++; +#endif + + (*p)[0] = (unsigned char)( t >> 24 ); + (*p)[1] = (unsigned char)( t >> 16 ); + (*p)[2] = (unsigned char)( t >> 8 ); + (*p)[3] = (unsigned char)( t ); + *p += 4; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + ret = ssl_cookie_hmac( &ctx->hmac_ctx, *p - 4, + p, end, cli_id, cli_id_len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Check a cookie + */ +int mbedtls_ssl_cookie_check( void *p_ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char ref_hmac[COOKIE_HMAC_LEN]; + int ret = 0; + unsigned char *p = ref_hmac; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long cur_time, cookie_time; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cookie_len != COOKIE_LEN ) + return( -1 ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + if( ssl_cookie_hmac( &ctx->hmac_ctx, cookie, + &p, p + sizeof( ref_hmac ), + cli_id, cli_id_len ) != 0 ) + ret = -1; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + if( ret != 0 ) + return( ret ); + + if( mbedtls_ssl_safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) + return( -1 ); + +#if defined(MBEDTLS_HAVE_TIME) + cur_time = (unsigned long) time( NULL ); +#else + cur_time = ctx->serial; +#endif + + cookie_time = ( (unsigned long) cookie[0] << 24 ) | + ( (unsigned long) cookie[1] << 16 ) | + ( (unsigned long) cookie[2] << 8 ) | + ( (unsigned long) cookie[3] ); + + if( ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout ) + return( -1 ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_srv.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_srv.c new file mode 100644 index 0000000000..86cf5d85b5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_srv.c @@ -0,0 +1,3884 @@ +/* + * SSLv3/TLSv1 server-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_SRV_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ) +{ + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + mbedtls_free( ssl->cli_id ); + + if( ( ssl->cli_id = mbedtls_calloc( 1, ilen ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->cli_id, info, ilen ); + ssl->cli_id_len = ilen; + + return( 0 ); +} + +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ) +{ + conf->f_cookie_write = f_cookie_write; + conf->f_cookie_check = f_cookie_check; + conf->p_cookie = p_cookie; +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse ServerName extension" ) ); + + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while( servername_list_size > 0 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->conf->f_sni( ssl->conf->p_sni, + ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len || + buf[0] != ssl->verify_data_len || + mbedtls_ssl_safer_memcmp( buf + 1, ssl->peer_verify_data, + ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t sig_alg_list_size; + const unsigned char *p; + const unsigned char *end = buf + len; + const int *md_cur; + + + sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( sig_alg_list_size + 2 != len || + sig_alg_list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * For now, ignore the SignatureAlgorithm part and rely on offered + * ciphersuites only for that part. To be fixed later. + * + * So, just look at the HashAlgorithm part. + */ + for( md_cur = ssl->conf->sig_hashes; *md_cur != MBEDTLS_MD_NONE; md_cur++ ) { + for( p = buf + 2; p < end; p += 2 ) { + if( *md_cur == (int) mbedtls_ssl_md_alg_from_hash( p[0] ) ) { + ssl->handshake->sig_alg = p[0]; + goto have_sig_alg; + } + } + } + + /* Some key echanges do not need signatures at all */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no signature_algorithm in common" ) ); + return( 0 ); + +have_sig_alg: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d", + ssl->handshake->sig_alg ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_elliptic_curves( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size, our_size; + const unsigned char *p; + const mbedtls_ecp_curve_info *curve_info, **curves; + + list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( list_size + 2 != len || + list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Should never happen unless client duplicates the extension */ + if( ssl->handshake->curves != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Don't allow our peer to make us allocate too much memory, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > MBEDTLS_ECP_DP_MAX ) + our_size = MBEDTLS_ECP_DP_MAX; + + if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ssl->handshake->curves = curves; + + p = buf + 2; + while( list_size > 0 && our_size > 1 ) + { + curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); + + if( curve_info != NULL ) + { + *curves++ = curve_info; + our_size--; + } + + list_size -= 2; + p += 2; + } + + return( 0 ); +} + +static int ssl_parse_supported_point_formats( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + list_size = buf[0]; + if( list_size + 1 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + return( ret ); + } + + /* Only mark the extension as OK when we're sure it is */ + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_session session; + + mbedtls_ssl_session_init( &session ); + + if( ssl->conf->f_ticket_parse == NULL || + ssl->conf->f_ticket_write == NULL ) + { + return( 0 ); + } + + /* Remember the client asked us to send a new ticket */ + ssl->handshake->new_session_ticket = 1; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) ); + + if( len == 0 ) + return( 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* + * Failures are ok: just ignore the ticket and proceed. + */ + if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket, &session, + buf, len ) ) != 0 ) + { + mbedtls_ssl_session_free( &session ); + + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) ); + else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) ); + else + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_parse", ret ); + + return( 0 ); + } + + /* + * Keep the session ID sent by the client, since we MUST send it back to + * inform them we're accepting the ticket (RFC 5077 section 3.4) + */ + session.id_len = ssl->session_negotiate->id_len; + memcpy( &session.id, ssl->session_negotiate->id, session.id_len ); + + mbedtls_ssl_session_free( ssl->session_negotiate ); + memcpy( ssl->session_negotiate, &session, sizeof( mbedtls_ssl_session ) ); + + /* Zeroize instead of free as we copied the content */ + mbedtls_zeroize( &session, sizeof( mbedtls_ssl_session ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) ); + + ssl->handshake->resume = 1; + + /* Don't send a new ticket after all, this one is OK */ + ssl->handshake->new_session_ticket = 0; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, cur_len, ours_len; + const unsigned char *theirs, *start, *end; + const char **ours; + + /* If ALPN not configured, just ignore the extension */ + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* + * Use our order of preference + */ + start = buf + 2; + end = buf + len; + for( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for( theirs = start; theirs != end; theirs += cur_len ) + { + /* If the list is well formed, we should get equality first */ + if( theirs > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cur_len = *theirs++; + + /* Empty strings MUST NOT be included */ + if( cur_len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( cur_len == ours_len && + memcmp( theirs, *ours, cur_len ) == 0 ) + { + ssl->alpn_chosen = *ours; + return( 0 ); + } + } + } + + /* If we get there, no match was found */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Auxiliary functions for ServerHello parsing and related actions + */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * Return 0 if the given key uses one of the acceptable curves, -1 otherwise + */ +#if defined(MBEDTLS_ECDSA_C) +static int ssl_check_key_curve( mbedtls_pk_context *pk, + const mbedtls_ecp_curve_info **curves ) +{ + const mbedtls_ecp_curve_info **crv = curves; + mbedtls_ecp_group_id grp_id = mbedtls_pk_ec( *pk )->grp.id; + + while( *crv != NULL ) + { + if( (*crv)->grp_id == grp_id ) + return( 0 ); + crv++; + } + + return( -1 ); +} +#endif /* MBEDTLS_ECDSA_C */ + +/* + * Try picking a certificate for this ciphersuite, + * return 0 on success and -1 on failure. + */ +static int ssl_pick_cert( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t * ciphersuite_info ) +{ + mbedtls_ssl_key_cert *cur, *list, *fallback = NULL; + mbedtls_pk_type_t pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + uint32_t flags; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_key_cert != NULL ) + list = ssl->handshake->sni_key_cert; + else +#endif + list = ssl->conf->key_cert; + + if( pk_alg == MBEDTLS_PK_NONE ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite requires certificate" ) ); + + if( list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server has no certificate" ) ); + return( -1 ); + } + + for( cur = list; cur != NULL; cur = cur->next ) + { + MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", + cur->cert ); + + if( ! mbedtls_pk_can_do( cur->key, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); + continue; + } + + /* + * This avoids sending the client a cert it'll reject based on + * keyUsage or other extensions. + * + * It also allows the user to provision different certificates for + * different uses based on keyUsage, eg if they want to avoid signing + * and decrypting with the same RSA key. + */ + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, + MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " + "(extended) key usage extension" ) ); + continue; + } + +#if defined(MBEDTLS_ECDSA_C) + if( pk_alg == MBEDTLS_PK_ECDSA && + ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); + continue; + } +#endif + + /* + * Try to select a SHA-1 certificate for pre-1.2 clients, but still + * present them a SHA-higher cert rather than failing if it's the only + * one we got that satisfies the other conditions. + */ + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 && + cur->cert->sig_md != MBEDTLS_MD_SHA1 ) + { + if( fallback == NULL ) + fallback = cur; + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate not preferred: " + "sha-2 with pre-TLS 1.2 client" ) ); + continue; + } + } + + /* If we get there, we got a winner */ + break; + } + + if( cur == NULL ) + cur = fallback; + + /* Do not update ssl->handshake->key_cert unless there is a match */ + if( cur != NULL ) + { + ssl->handshake->key_cert = cur; + MBEDTLS_SSL_DEBUG_CRT( 3, "selected certificate chain, certificate", + ssl->handshake->key_cert->cert ); + return( 0 ); + } + + return( -1 ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Check if a given ciphersuite is suitable for use with our config/keys/etc + * Sets ciphersuite_info only if the suite matches. + */ +static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id, + const mbedtls_ssl_ciphersuite_t **ciphersuite_info ) +{ + const mbedtls_ssl_ciphersuite_t *suite_info; + + suite_info = mbedtls_ssl_ciphersuite_from_id( suite_id ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "trying ciphersuite: %s", suite_info->name ) ); + + if( suite_info->min_minor_ver > ssl->minor_ver || + suite_info->max_minor_ver < ssl->minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: version" ) ); + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + return( 0 ); +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: rc4" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + ( ssl->handshake->cli_exts & MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: ecjpake " + "not configured or ext missing" ) ); + return( 0 ); + } +#endif + + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + if( mbedtls_ssl_ciphersuite_uses_ec( suite_info ) && + ( ssl->handshake->curves == NULL || + ssl->handshake->curves[0] == NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no common elliptic curve" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /* If the ciphersuite requires a pre-shared key and we don't + * have one, skip it now rather than failing later */ + if( mbedtls_ssl_ciphersuite_uses_psk( suite_info ) && + ssl->conf->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: no pre-shared key" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Final check: if ciphersuite requires us to have a + * certificate/key of a particular type: + * - select the appropriate certificate if we have one, or + * - try the next ciphersuite if we don't + * This must be done last since we modify the key_cert list. + */ + if( ssl_pick_cert( ssl, suite_info ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no suitable certificate" ) ); + return( 0 ); + } +#endif + + *ciphersuite_info = suite_info; + return( 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + unsigned int i, j; + size_t n; + unsigned int ciph_len, sess_len, chal_len; + unsigned char *buf, *p; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + buf = ssl->in_hdr; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, 5 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d", + buf[2] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d", + ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]", + buf[3], buf[4] ) ); + + /* + * SSLv2 Client Hello + * + * Record layer: + * 0 . 1 message length + * + * SSL layer: + * 2 . 2 message type + * 3 . 4 protocol version + */ + if( buf[2] != MBEDTLS_SSL_HS_CLIENT_HELLO || + buf[3] != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF; + + if( n < 17 || n > 512 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + ssl->minor_ver = ( buf[4] <= ssl->conf->max_minor_ver ) + ? buf[4] : ssl->conf->max_minor_ver; + + if( ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + ssl->handshake->max_major_ver = buf[3]; + ssl->handshake->max_minor_ver = buf[4]; + + if( ( ret = mbedtls_ssl_fetch_input( ssl, 2 + n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + ssl->handshake->update_checksum( ssl, buf + 2, n ); + + buf = ssl->in_msg; + n = ssl->in_left - 5; + + /* + * 0 . 1 ciphersuitelist length + * 2 . 3 session id length + * 4 . 5 challenge length + * 6 . .. ciphersuitelist + * .. . .. session id + * .. . .. challenge + */ + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, n ); + + ciph_len = ( buf[0] << 8 ) | buf[1]; + sess_len = ( buf[2] << 8 ) | buf[3]; + chal_len = ( buf[4] << 8 ) | buf[5]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d", + ciph_len, sess_len, chal_len ) ); + + /* + * Make sure each parameter length is valid + */ + if( ciph_len < 3 || ( ciph_len % 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( sess_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( chal_len < 8 || chal_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( n != 6 + ciph_len + sess_len + chal_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + 6, ciph_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", + buf + 6 + ciph_len, sess_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, challenge", + buf + 6 + ciph_len + sess_len, chal_len ); + + p = buf + 6 + ciph_len; + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->id_len ); + + p += sess_len; + memset( ssl->handshake->randbytes, 0, 64 ); + memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len ); + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && p[1] == 0 && p[2] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV " + "during renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[2] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) + { + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + { + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) +#endif + { + if( p[0] != 0 || + p[1] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[2] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite_v2; + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite_v2: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; + mbedtls_ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); + + /* + * SSLv2 Client Hello relevant renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ + +static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + size_t i, j; + size_t ciph_offset, comp_offset, ext_offset; + size_t msg_len, ciph_len, sess_len, comp_len, ext_len; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + size_t cookie_offset, cookie_len; +#endif + unsigned char *buf, *p, *ext; +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + int major, minor; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +read_record_header: +#endif + /* + * If renegotiating, then the input was read with mbedtls_ssl_read_record(), + * otherwise read it ourselves manually in order to support SSLv2 + * ClientHello, which doesn't use the same record layer format. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + } + + buf = ssl->in_hdr; + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM ) +#endif + if( ( buf[0] & 0x80 ) != 0 ) + return ssl_parse_client_hello_v2( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, mbedtls_ssl_hdr_len( ssl ) ); + + /* + * SSLv3/TLS Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 11 DTLS: epoch + record sequence number + * 3 . 4 message length + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d", + buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d", + ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, protocol version: [%d:%d]", + buf[1], buf[2] ) ); + + mbedtls_ssl_read_version( &major, &minor, ssl->conf->transport, buf + 1 ); + + /* According to RFC 5246 Appendix E.1, the version here is typically + * "{03,00}, the lowest version number supported by the client, [or] the + * value of ClientHello.client_version", so the only meaningful check here + * is the major version shouldn't be less than 3 */ + if( major < MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* For DTLS if this is the initial handshake, remember the client sequence + * number to use it in our next message (RFC 6347 4.2.1) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + /* Epoch should be 0 for initial handshakes */ + if( ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + memcpy( ssl->out_ctr + 2, ssl->in_ctr + 2, 6 ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record, discarding" ) ); + ssl->next_record_offset = 0; + ssl->in_left = 0; + goto read_record_header; + } + + /* No MAC to check yet, so we can update right now */ + mbedtls_ssl_dtls_replay_update( ssl ); +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Set by mbedtls_ssl_read_record() */ + msg_len = ssl->in_hslen; + } + else +#endif + { + if( msg_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->next_record_offset = msg_len + mbedtls_ssl_hdr_len( ssl ); + else +#endif + ssl->in_left = 0; + } + + buf = ssl->in_msg; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, msg_len ); + + ssl->handshake->update_checksum( ssl, buf, msg_len ); + + /* + * Handshake layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 DTLS only: message seqence number + * 6 . 8 DTLS only: fragment offset + * 9 . 11 DTLS only: fragment length + */ + if( msg_len < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + + /* We don't support fragmentation of ClientHello (yet?) */ + if( buf[1] != 0 || + msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* + * Copy the client's handshake message_seq on initial handshakes, + * check sequence number on renego. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + /* This couldn't be done in ssl_prepare_handshake_record() */ + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + + if( cli_msg_seq != ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message_seq: " + "%d (expected %d)", cli_msg_seq, + ssl->handshake->in_msg_seq ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->handshake->in_msg_seq++; + } + else +#endif + { + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + ssl->handshake->out_msg_seq = cli_msg_seq; + ssl->handshake->in_msg_seq = cli_msg_seq + 1; + } + + /* + * For now we don't support fragmentation, so make sure + * fragment_offset == 0 and fragment_length == length + */ + if( ssl->in_msg[6] != 0 || ssl->in_msg[7] != 0 || ssl->in_msg[8] != 0 || + memcmp( ssl->in_msg + 1, ssl->in_msg + 9, 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ClientHello fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + buf += mbedtls_ssl_hs_hdr_len( ssl ); + msg_len -= mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * ClientHello layer: + * 0 . 1 protocol version + * 2 . 33 random bytes (starting with 4 bytes of Unix time) + * 34 . 35 session id length (1 byte) + * 35 . 34+x session id + * 35+x . 35+x DTLS only: cookie length (1 byte) + * 36+x . .. DTLS only: cookie + * .. . .. ciphersuite list length (2 bytes) + * .. . .. ciphersuite list + * .. . .. compression alg. list length (1 byte) + * .. . .. compression alg. list + * .. . .. extensions length (2 bytes, optional) + * .. . .. extensions (optional) + */ + + /* + * Minimal length (with everything empty and extensions ommitted) is + * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can + * read at least up to session id length without worrying. + */ + if( msg_len < 38 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check and save the protocol version + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, version", buf, 2 ); + + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf ); + + ssl->handshake->max_major_ver = ssl->major_ver; + ssl->handshake->max_minor_ver = ssl->minor_ver; + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + if( ssl->major_ver > ssl->conf->max_major_ver ) + { + ssl->major_ver = ssl->conf->max_major_ver; + ssl->minor_ver = ssl->conf->max_minor_ver; + } + else if( ssl->minor_ver > ssl->conf->max_minor_ver ) + ssl->minor_ver = ssl->conf->max_minor_ver; + + /* + * Save client random (inc. Unix time) + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 2, 32 ); + + memcpy( ssl->handshake->randbytes, buf + 2, 32 ); + + /* + * Check the session ID length and save session ID + */ + sess_len = buf[34]; + + if( sess_len > sizeof( ssl->session_negotiate->id ) || + sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 35, sess_len ); + + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, buf + 35, + ssl->session_negotiate->id_len ); + + /* + * Check the cookie length and content + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + cookie_offset = 35 + sess_len; + cookie_len = buf[cookie_offset]; + + if( cookie_offset + 1 + cookie_len + 2 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + buf + cookie_offset + 1, cookie_len ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->f_cookie_check != NULL +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + if( ssl->conf->f_cookie_check( ssl->conf->p_cookie, + buf + cookie_offset + 1, cookie_len, + ssl->cli_id, ssl->cli_id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) ); + ssl->handshake->verify_cookie_len = 1; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) ); + ssl->handshake->verify_cookie_len = 0; + } + } + else +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + { + /* We know we didn't send a cookie, so it should be empty */ + if( cookie_len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) ); + } + + /* + * Check the ciphersuitelist length (will be parsed later) + */ + ciph_offset = cookie_offset + 1 + cookie_len; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + ciph_offset = 35 + sess_len; + + ciph_len = ( buf[ciph_offset + 0] << 8 ) + | ( buf[ciph_offset + 1] ); + + if( ciph_len < 2 || + ciph_len + 2 + ciph_offset + 1 > msg_len || /* 1 for comp. alg. len */ + ( ciph_len % 2 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + ciph_offset + 2, ciph_len ); + + /* + * Check the compression algorithms length and pick one + */ + comp_offset = ciph_offset + 2 + ciph_len; + + comp_len = buf[comp_offset]; + + if( comp_len < 1 || + comp_len > 16 || + comp_len + comp_offset + 1 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, compression", + buf + comp_offset + 1, comp_len ); + + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#if defined(MBEDTLS_ZLIB_SUPPORT) + for( i = 0; i < comp_len; ++i ) + { + if( buf[comp_offset + 1 + i] == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_DEFLATE; + break; + } + } +#endif + + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#endif + + /* + * Check the extension length + */ + ext_offset = comp_offset + 1 + comp_len; + if( msg_len > ext_offset ) + { + if( msg_len < ext_offset + 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_len = ( buf[ext_offset + 0] << 8 ) + | ( buf[ext_offset + 1] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + msg_len != ext_offset + 2 + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else + ext_len = 0; + + ext = buf + ext_offset + 2; + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", ext, ext_len ); + + while( ext_len != 0 ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + if( ssl->conf->f_sni == NULL ) + break; + + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + break; +#endif + + ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported elliptic curves extension" ) ); + + ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported point formats extension" ) ); + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT; + + ret = ssl_parse_supported_point_formats( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake kkpp extension" ) ); + + ret = ssl_parse_ecjpake_kkpp( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated hmac extension" ) ); + + ret = ssl_parse_truncated_hmac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt then mac extension" ) ); + + ret = ssl_parse_encrypt_then_mac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended master secret extension" ) ); + + ret = ssl_parse_extended_ms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session ticket extension" ) ); + + ret = ssl_parse_session_ticket_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + ciph_offset + 2; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == 0 && p[1] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Search for a matching ciphersuite + * (At the end because we need information from the EC-based extensions + * and certificate from the SNI callback triggered by the SNI extension.) + */ + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) + { + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + { + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) +#endif + { + if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[1] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite; + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + mbedtls_ssl_send_fatal_handshake_failure( ssl ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + mbedtls_ssl_send_fatal_handshake_failure( ssl ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; + mbedtls_ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding truncated hmac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const mbedtls_ssl_ciphersuite_t *suite = NULL; + const mbedtls_cipher_info_t *cipher = NULL; + + if( ssl->session_negotiate->encrypt_then_mac == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + /* + * RFC 7366: "If a server receives an encrypt-then-MAC request extension + * from a client and then selects a stream or Authenticated Encryption + * with Associated Data (AEAD) ciphersuite, it MUST NOT send an + * encrypt-then-MAC response extension back to the client." + */ + if( ( suite = mbedtls_ssl_ciphersuite_from_id( + ssl->session_negotiate->ciphersuite ) ) == NULL || + ( cipher = mbedtls_cipher_info_from_type( suite->cipher ) ) == NULL || + cipher->mode != MBEDTLS_MODE_CBC ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding encrypt then mac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding extended master secret " + "extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->new_session_ticket == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding session ticket extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, secure renegotiation extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + *p++ = 0x00; + *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; + *p++ = ssl->verify_data_len * 2 & 0xFF; + + memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + *p++ = 0x00; + *p++ = 0x01; + *p++ = 0x00; + } + + *olen = p - buf; +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + ((void) ssl); + + if( ( ssl->handshake->cli_exts & + MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT ) == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, supported_point_formats extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly computation if not needed */ + if( ssl->transform_negotiate->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, ecjpake kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN ) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + if( ssl->alpn_chosen == NULL ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) ); + + /* + * 0 . 1 ext identifier + * 2 . 3 ext length + * 4 . 5 protocol list length + * 6 . 6 protocol name length + * 7 . 7+n protocol name + */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + *olen = 7 + strlen( ssl->alpn_chosen ); + + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); + + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + buf[6] = (unsigned char)( ( ( *olen - 7 ) ) & 0xFF ); + + memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->out_msg + 4; + unsigned char *cookie_len_byte; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + + /* The RFC is not clear on this point, but sending the actual negotiated + * version looks like the most interoperable thing to do. */ + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + p += 2; + + /* If we get here, f_cookie_check is not null */ + if( ssl->conf->f_cookie_write == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Skip length byte until we know the length */ + cookie_len_byte = p++; + + if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, + &p, ssl->out_buf + MBEDTLS_SSL_BUFFER_LEN, + ssl->cli_id, ssl->cli_id_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); + return( ret ); + } + + *cookie_len_byte = (unsigned char)( p - ( cookie_len_byte + 1 ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie sent", cookie_len_byte + 1, *cookie_len_byte ); + + ssl->out_msglen = p - ssl->out_msg; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + + ssl->state = MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +static int ssl_write_server_hello( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_HAVE_TIME) + time_t t; +#endif + int ret; + size_t olen, ext_len = 0, n; + unsigned char *buf, *p; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie_len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ssl_write_hello_verify_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", + buf[4], buf[5] ) ); + +#if defined(MBEDTLS_HAVE_TIME) + t = time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + p += 28; + + memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); + + /* + * Resume is 0 by default, see ssl_handshake_init(). + * It may be already set to 1 by ssl_parse_session_ticket_ext(). + * If not, try looking up session ID in our cache. + */ + if( ssl->handshake->resume == 0 && +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE && +#endif + ssl->session_negotiate->id_len != 0 && + ssl->conf->f_get_cache != NULL && + ssl->conf->f_get_cache( ssl->conf->p_cache, ssl->session_negotiate ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from cache" ) ); + ssl->handshake->resume = 1; + } + + if( ssl->handshake->resume == 0 ) + { + /* + * New session, create a new session id, + * unless we're about to issue a session ticket + */ + ssl->state++; + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + { + ssl->session_negotiate->id_len = n = 0; + memset( ssl->session_negotiate->id, 0, 32 ); + } + else +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + { + ssl->session_negotiate->id_len = n = 32; + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, + n ) ) != 0 ) + return( ret ); + } + } + else + { + /* + * Resuming a session + */ + n = ssl->session_negotiate->id_len; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + } + + /* + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + * 42+n . 43+n extensions length + * 44+n . 43+n+m extensions + */ + *p++ = (unsigned char) ssl->session_negotiate->id_len; + memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->id_len ); + p += ssl->session_negotiate->id_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + *p++ = (unsigned char)( ssl->session_negotiate->compression ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", + mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: 0x%02X", + ssl->session_negotiate->compression ) ); + + /* + * First write extensions, then the total length + */ + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + + ret = mbedtls_ssl_write_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ret ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + size_t dn_size, total_dn_size; /* excluding length bytes */ + size_t ct_len, sa_len; /* including length bytes */ + unsigned char *buf, *p; + const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const mbedtls_x509_crt *crt; + int authmode; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + ssl->state++; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; + else +#endif + authmode = ssl->conf->authmode; + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + return( 0 ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 4 cert type count + * 5 .. m-1 cert types + * m .. m+1 sig alg length (TLS 1.2 only) + * m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only) + * n .. n+1 length of all DNs + * n+2 .. n+3 length of DN 1 + * n+4 .. ... Distinguished Name #1 + * ... .. ... length of DN 2, etc. + */ + buf = ssl->out_msg; + p = buf + 4; + + /* + * Supported certificate types + * + * ClientCertificateType certificate_types<1..2^8-1>; + * enum { (255) } ClientCertificateType; + */ + ct_len = 0; + +#if defined(MBEDTLS_RSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_RSA_SIGN; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN; +#endif + + p[0] = (unsigned char) ct_len++; + p += ct_len; + + sa_len = 0; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Add signature_algorithms for verify (TLS 1.2) + * + * SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * enum { (255) } HashAlgorithm; + * enum { (255) } SignatureAlgorithm; + */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * Only use current running hash algorithm that is already required + * for requested ciphersuite. + */ + ssl->handshake->verify_sig_alg = MBEDTLS_SSL_HASH_SHA256; + + if( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + ssl->handshake->verify_sig_alg = MBEDTLS_SSL_HASH_SHA384; + } + + /* + * Supported signature algorithms + */ +#if defined(MBEDTLS_RSA_C) + p[2 + sa_len++] = ssl->handshake->verify_sig_alg; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_RSA; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[2 + sa_len++] = ssl->handshake->verify_sig_alg; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif + + p[0] = (unsigned char)( sa_len >> 8 ); + p[1] = (unsigned char)( sa_len ); + sa_len += 2; + p += sa_len; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* + * DistinguishedName certificate_authorities<0..2^16-1>; + * opaque DistinguishedName<1..2^16-1>; + */ + p += 2; +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + crt = ssl->handshake->sni_ca_chain; + else +#endif + crt = ssl->conf->ca_chain; + + total_dn_size = 0; + while( crt != NULL && crt->version != 0 ) + { + dn_size = crt->subject_raw.len; + + if( end < p || + (size_t)( end - p ) < dn_size || + (size_t)( end - p ) < 2 + dn_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); + break; + } + + *p++ = (unsigned char)( dn_size >> 8 ); + *p++ = (unsigned char)( dn_size ); + memcpy( p, crt->subject_raw.p, dn_size ); + p += dn_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size ); + + total_dn_size += 2 + dn_size; + crt = crt->next; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 ); + ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size ); + + ret = mbedtls_ssl_write_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, + mbedtls_pk_ec( *mbedtls_ssl_own_key( ssl ) ), + MBEDTLS_ECDH_OURS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t n = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + unsigned char *p = ssl->out_msg + 4; + unsigned char *dig_signed = p; + size_t dig_signed_len = 0, len; + ((void) dig_signed); + ((void) dig_signed_len); + ((void) len); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + ssl_get_ecdh_params_from_cert( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + size_t jlen; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p, &jlen, ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + p += jlen; + n += jlen; + } +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* TODO: Support identity hints */ + *(p++) = 0x00; + *(p++) = 0x00; + + n += 2; + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->conf->dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->conf->dhm_G ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_mpi_copy", ret ); + return( ret ); + } + + if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + p, &len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret ); + return( ret ); + } + + dig_signed = p; + dig_signed_len = len; + + p += len; + n += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + const mbedtls_ecp_curve_info **curve = NULL; + const mbedtls_ecp_group_id *gid; + + /* Match our preference list against the offered curves */ + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + for( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + if( (*curve)->grp_id == *gid ) + goto curve_matching_done; + +curve_matching_done: + if( curve == NULL || *curve == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); + + if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, + (*curve)->grp_id ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len, + p, MBEDTLS_SSL_MAX_CONTENT_LEN - n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret ); + return( ret ); + } + + dig_signed = p; + dig_signed_len = len; + + p += len; + n += len; + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + size_t signature_len = 0; + unsigned int hashlen = 0; + unsigned char hash[64]; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + + /* + * Choose hash algorithm. NONE means MD5 + SHA1 here. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + md_alg = mbedtls_ssl_md_alg_from_hash( ssl->handshake->sig_alg ); + + if( md_alg == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ciphersuite_info->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif + { + md_alg = MBEDTLS_MD_NONE; + } + + /* + * Compute the hash to be signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, dig_signed, dig_signed_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, dig_signed, dig_signed_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + hashlen = 36; + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, dig_signed, dig_signed_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + /* + * Make the signature + */ + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + *(p++) = ssl->handshake->sig_alg; + *(p++) = mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ); + + n += 2; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen, + p + 2 , &signature_len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( signature_len >> 8 ); + *(p++) = (unsigned char)( signature_len ); + n += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len ); + + n += signature_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + + ssl->out_msglen = 4 + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); + + return( 0 ); +} + +static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello done" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO_DONE; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t n; + + /* + * Receive G^Y mod P, premaster = (G^Y)^X mod P + */ + if( *p + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( *p + n > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_read_public( &ssl->handshake->dhm_ctx, *p, n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + *p += n; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + size_t pms_offset ) +{ + int ret; + size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) ); + unsigned char *pms = ssl->handshake->premaster + pms_offset; + unsigned char ver[2]; + unsigned char fake_pms[48], peer_pms[48]; + unsigned char mask; + size_t i, peer_pmslen; + unsigned int diff; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Decrypt the premaster using own private RSA key + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( *p++ != ( ( len >> 8 ) & 0xFF ) || + *p++ != ( ( len ) & 0xFF ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + } +#endif + + if( p + len != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + mbedtls_ssl_write_version( ssl->handshake->max_major_ver, + ssl->handshake->max_minor_ver, + ssl->conf->transport, ver ); + + /* + * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding + * must not cause the connection to end immediately; instead, send a + * bad_record_mac later in the handshake. + * Also, avoid data-dependant branches here to protect against + * timing-based variants. + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len, + peer_pms, &peer_pmslen, + sizeof( peer_pms ), + ssl->conf->f_rng, ssl->conf->p_rng ); + + diff = (unsigned int) ret; + diff |= peer_pmslen ^ 48; + diff |= peer_pms[0] ^ ver[0]; + diff |= peer_pms[1] ^ ver[1]; + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( diff != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); +#endif + + if( sizeof( ssl->handshake->premaster ) < pms_offset || + sizeof( ssl->handshake->premaster ) - pms_offset < 48 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + ssl->handshake->pmslen = 48; + + /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + for( i = 0; i < ssl->handshake->pmslen; i++ ) + pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = 0; + size_t n; + + if( ssl->conf->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no pre-shared key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Receive client pre-shared key identity name + */ + if( *p + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( n < 1 || n > 65535 || *p + n > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->conf->f_psk != NULL ) + { + if( ssl->conf->f_psk( ssl->conf->p_psk, ssl, *p, n ) != 0 ) + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* Identity is not a big secret since clients send it in the clear, + * but treat it carefully anyway, just in case */ + if( n != ssl->conf->psk_identity_len || + mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) + { + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + } + + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", *p, n ); + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ); + } + + *p += n; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + unsigned char *p, *end; + + ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 2 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_encrypted_pms" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_parse_encrypted_pms_secret" ), ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, sig_len; + unsigned char hash[48]; + unsigned char *hash_start = hash; + size_t hashlen; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + mbedtls_pk_type_t pk_alg; +#endif + mbedtls_md_type_t md_alg; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + /* Needs to be done before read_record() to exclude current message */ + ssl->handshake->calc_verify( ssl, hash ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + ssl->state++; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * struct { + * SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only + * opaque signature<0..2^16-1>; + * } DigitallySigned; + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + md_alg = MBEDTLS_MD_NONE; + hashlen = 36; + + /* For ECDSA, use SHA-1, not MD-5 + SHA-1 */ + if( mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Hash + */ + if( ssl->in_msg[i] != ssl->handshake->verify_sig_alg ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + md_alg = mbedtls_ssl_md_alg_from_hash( ssl->handshake->verify_sig_alg ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + i++; + + /* + * Signature + */ + if( ( pk_alg = mbedtls_ssl_pk_alg_from_sig( ssl->in_msg[i] ) ) + == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Check the certificate's key type matches the signature alg + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i++; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1]; + i += 2; + + if( i + sig_len != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, + md_alg, hash_start, hashlen, + ssl->in_msg + i, sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t tlen; + uint32_t lifetime; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write new session ticket" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 4 . 7 ticket_lifetime_hint (0 = unspecified) + * 8 . 9 ticket_len (n) + * 10 . 9+n ticket content + */ + + if( ( ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, + ssl->session_negotiate, + ssl->out_msg + 10, + ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN, + &tlen, &lifetime ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_write", ret ); + tlen = 0; + } + + ssl->out_msg[4] = ( lifetime >> 24 ) & 0xFF; + ssl->out_msg[5] = ( lifetime >> 16 ) & 0xFF; + ssl->out_msg[6] = ( lifetime >> 8 ) & 0xFF; + ssl->out_msg[7] = ( lifetime ) & 0xFF; + + ssl->out_msg[8] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + ssl->out_msg[9] = (unsigned char)( ( tlen ) & 0xFF ); + + ssl->out_msglen = 10 + tlen; + + /* + * Morally equivalent to updating ssl->state, but NewSessionTicket and + * ChangeCipherSpec share the same state. + */ + ssl->handshake->new_session_ticket = 0; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- server side -- single step + */ +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * <== ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_parse_client_hello( ssl ); + break; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +#endif + + /* + * ==> ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_write_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_write_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_write_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_write_server_hello_done( ssl ); + break; + + /* + * <== ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_parse_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_parse_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + /* + * ==> ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + ret = ssl_write_new_session_ticket( ssl ); + else +#endif + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); +#if defined(ESP8266_PLATFORM) + mbedtls_write_finished(ssl); +#endif + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_SRV_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ticket.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ticket.c new file mode 100644 index 0000000000..0e27900b55 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_ticket.c @@ -0,0 +1,489 @@ +/* + * TLS server tickets callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) + +#include "mbedtls/ssl_ticket.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialze context + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +#define MAX_KEY_BYTES 32 /* 256 bits */ + +/* + * Generate/update a key + */ +static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, + unsigned char index ) +{ + int ret; + unsigned char buf[MAX_KEY_BYTES]; + mbedtls_ssl_ticket_key *key = ctx->keys + index; + +#if defined(MBEDTLS_HAVE_TIME) + key->generation_time = (uint32_t) time( NULL ); +#endif + + if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 ) + return( ret ); + + if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 ) + return( ret ); + + /* With GCM and CCM, same context can encrypt & decrypt */ + ret = mbedtls_cipher_setkey( &key->ctx, buf, + mbedtls_cipher_get_key_bitlen( &key->ctx ), + MBEDTLS_ENCRYPT ); + + mbedtls_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +/* + * Rotate/generate keys if necessary + */ +static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx ) +{ +#if !defined(MBEDTLS_HAVE_TIME) + ((void) ctx); +#else + if( ctx->ticket_lifetime != 0 ) + { + uint32_t current_time = (uint32_t) time( NULL ); + uint32_t key_time = ctx->keys[ctx->active].generation_time; + + if( current_time > key_time && + current_time - key_time < ctx->ticket_lifetime ) + { + return( 0 ); + } + + ctx->active = 1 - ctx->active; + + return( ssl_ticket_gen_key( ctx, ctx->active ) ); + } + else +#endif /* MBEDTLS_HAVE_TIME */ + return( 0 ); +} + +/* + * Setup context for actual use + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + ctx->f_rng = f_rng; + ctx->p_rng = p_rng; + + ctx->ticket_lifetime = lifetime; + + cipher_info = mbedtls_cipher_info_from_type( cipher); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cipher_info->mode != MBEDTLS_MODE_GCM && + cipher_info->mode != MBEDTLS_MODE_CCM ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 || + ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || + ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Serialize a session in the following format: + * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) + * n . n+2 peer_cert length = m (0 if no certificate) + * n+3 . n+2+m peer cert ASN.1 + */ +static int ssl_save_session( const mbedtls_ssl_session *session, + unsigned char *buf, size_t buf_len, + size_t *olen ) +{ + unsigned char *p = buf; + size_t left = buf_len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( left < sizeof( mbedtls_ssl_session ) ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + memcpy( p, session, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + left -= sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( session->peer_cert == NULL ) + cert_len = 0; + else + cert_len = session->peer_cert->raw.len; + + if( left < 3 + cert_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( cert_len >> 16 & 0xFF ); + *p++ = (unsigned char)( cert_len >> 8 & 0xFF ); + *p++ = (unsigned char)( cert_len & 0xFF ); + + if( session->peer_cert != NULL ) + memcpy( p, session->peer_cert->raw.p, cert_len ); + + p += cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + *olen = p - buf; + + return( 0 ); +} + +/* + * Unserialise session, see ssl_save_session() + */ +static int ssl_load_session( mbedtls_ssl_session *session, + const unsigned char *buf, size_t len ) +{ + const unsigned char *p = buf; + const unsigned char * const end = buf + len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p + sizeof( mbedtls_ssl_session ) > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session, p, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( p + 3 > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; + + if( cert_len == 0 ) + { + session->peer_cert = NULL; + } + else + { + int ret; + + if( p + cert_len > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( session->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( session->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, + p, cert_len ) ) != 0 ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + return( ret ); + } + + p += cert_len; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p != end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Create session ticket, with the following structure: + * + * struct { + * opaque key_name[4]; + * opaque iv[12]; + * opaque encrypted_state<0..2^16-1>; + * opaque tag[16]; + * } ticket; + * + * The key_name, iv, and length of encrypted_state are the additional + * authenticated data. + */ +int mbedtls_ssl_ticket_write( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *ticket_lifetime ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = start; + unsigned char *iv = start + 4; + unsigned char *state_len_bytes = iv + 12; + unsigned char *state = state_len_bytes + 2; + unsigned char *tag; + size_t clear_len, ciph_len; + + *tlen = 0; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, + * in addition to session itself, that will be checked when writing it. */ + if( end - start < 4 + 12 + 2 + 16 ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + key = &ctx->keys[ctx->active]; + + *ticket_lifetime = ctx->ticket_lifetime; + + memcpy( key_name, key->name, 4 ); + + if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 ) + goto cleanup; + + /* Dump session state */ + if( ( ret = ssl_save_session( session, + state, end - state, &clear_len ) ) != 0 || + (unsigned long) clear_len > 65535 ) + { + goto cleanup; + } + state_len_bytes[0] = ( clear_len >> 8 ) & 0xff; + state_len_bytes[1] = ( clear_len ) & 0xff; + + /* Encrypt and authenticate */ + tag = state + clear_len; + if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx, + iv, 12, key_name, 4 + 12 + 2, + state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 ) + { + goto cleanup; + } + if( ciph_len != clear_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + *tlen = 4 + 12 + 2 + 16 + ciph_len; + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Select key based on name + */ +static mbedtls_ssl_ticket_key *ssl_ticket_select_key( + mbedtls_ssl_ticket_context *ctx, + const unsigned char name[4] ) +{ + unsigned char i; + + for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ ) + if( memcmp( name, ctx->keys[i].name, 4 ) == 0 ) + return( &ctx->keys[i] ); + + return( NULL ); +} + +/* + * Load session ticket (see mbedtls_ssl_ticket_write for structure) + */ +int mbedtls_ssl_ticket_parse( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = buf; + unsigned char *iv = buf + 4; + unsigned char *enc_len_p = iv + 12; + unsigned char *ticket = enc_len_p + 2; + unsigned char *tag; + size_t enc_len, clear_len; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* See mbedtls_ssl_ticket_write() */ + if( len < 4 + 12 + 2 + 16 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1]; + tag = ticket + enc_len; + + if( len != 4 + 12 + 2 + enc_len + 16 ) + { + ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + goto cleanup; + } + + /* Select key */ + if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL ) + { + /* We can't know for sure but this is a likely option unless we're + * under attack - this is only informative anyway */ + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + + /* Decrypt and authenticate */ + if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, iv, 12, + key_name, 4 + 12 + 2, ticket, enc_len, + ticket, &clear_len, tag, 16 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + ret = MBEDTLS_ERR_SSL_INVALID_MAC; + + goto cleanup; + } + if( clear_len != enc_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + /* Actually load session */ + if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 ) + goto cleanup; + +#if defined(MBEDTLS_HAVE_TIME) + { + /* Check for expiration */ + time_t current_time = time( NULL ); + + if( current_time < session->start || + (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime ) + { + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + } +#endif + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free context + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) +{ + mbedtls_cipher_free( &ctx->keys[0].ctx ); + mbedtls_cipher_free( &ctx->keys[1].ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + + mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); +} + +#endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_tls.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_tls.c new file mode 100644 index 0000000000..8a8e789836 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/ssl_tls.c @@ -0,0 +1,7625 @@ +/* + * SSLv3/TLSv1 shared functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SSL 3.0 specification was drafted by Netscape in 1996, + * and became an IETF standard in 1999. + * + * http://wp.netscape.com/eng/ssl3/ + * http://www.ietf.org/rfc/rfc2246.txt + * http://www.ietf.org/rfc/rfc4346.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* Length of the "epoch" field in the record header */ +static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 2 ); +#else + ((void) ssl); +#endif + return( 0 ); +} + +/* + * Start a timer. + * Passing millisecs = 0 cancels a running timer. + */ +static void ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs ) +{ + if( ssl->f_set_timer == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "set_timer to %d ms", (int) millisecs ) ); + ssl->f_set_timer( ssl->p_timer, millisecs / 4, millisecs ); +} + +/* + * Return -1 is timer is expired, 0 if it isn't. + */ +static int ssl_check_timer( mbedtls_ssl_context *ssl ) +{ + if( ssl->f_get_timer == NULL ) + return( 0 ); + + if( ssl->f_get_timer( ssl->p_timer ) == 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "timer expired" ) ); + return( -1 ); + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Double the retransmit timeout value, within the allowed range, + * returning -1 if the maximum value has already been reached. + */ +static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + uint32_t new_timeout; + + if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max ) + return( -1 ); + + new_timeout = 2 * ssl->handshake->retransmit_timeout; + + /* Avoid arithmetic overflow and range overflow */ + if( new_timeout < ssl->handshake->retransmit_timeout || + new_timeout > ssl->conf->hs_timeout_max ) + { + new_timeout = ssl->conf->hs_timeout_max; + } + + ssl->handshake->retransmit_timeout = new_timeout; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); + + return( 0 ); +} + +static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/* + * Convert max_fragment_length codes to length. + * RFC 6066 says: + * enum{ + * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255) + * } MaxFragmentLength; + * and we add 0 -> extension unused + */ +static unsigned int mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] = +{ + MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */ + 512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */ + 1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */ + 2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */ + 4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */ +}; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_CLI_C) +static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ) +{ + mbedtls_ssl_session_free( dst ); + memcpy( dst, src, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( src->peer_cert != NULL ) + { + int ret; + + dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); + if( dst->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( dst->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p, + src->peer_cert->raw.len ) ) != 0 ) + { + mbedtls_free( dst->peer_cert ); + dst->peer_cert = NULL; + return( ret ); + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + if( src->ticket != NULL ) + { + dst->ticket = mbedtls_calloc( 1, src->ticket_len ); + if( dst->ticket == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->ticket, src->ticket, src->ticket_len ); + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) +int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen ) = NULL; +int (*mbedtls_ssl_hw_record_activate)( mbedtls_ssl_context *ssl, int direction) = NULL; +int (*mbedtls_ssl_hw_record_reset)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_write)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_read)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_finish)( mbedtls_ssl_context *ssl ) = NULL; +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/* + * Key material generation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static int ssl3_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t i; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padding[16]; + unsigned char sha1sum[20]; + ((void)label); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + /* + * SSLv3: + * block = + * MD5( secret + SHA1( 'A' + secret + random ) ) + + * MD5( secret + SHA1( 'BB' + secret + random ) ) + + * MD5( secret + SHA1( 'CCC' + secret + random ) ) + + * ... + */ + for( i = 0; i < dlen / 16; i++ ) + { + memset( padding, (unsigned char) ('A' + i), 1 + i ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, padding, 1 + i ); + mbedtls_sha1_update( &sha1, secret, slen ); + mbedtls_sha1_update( &sha1, random, rlen ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, secret, slen ); + mbedtls_md5_update( &md5, sha1sum, 20 ); + mbedtls_md5_finish( &md5, dstbuf + i * 16 ); + } + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padding, sizeof( padding ) ); + mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static int tls1_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb, hs; + size_t i, j, k; + const unsigned char *S1, *S2; + unsigned char tmp[128]; + unsigned char h_i[20]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + hs = ( slen + 1 ) / 2; + S1 = secret; + S2 = secret + slen - hs; + + nb = strlen( label ); + memcpy( tmp + 20, label, nb ); + memcpy( tmp + 20 + nb, random, rlen ); + nb += rlen; + + /* + * First compute P_md5(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, S1, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + for( i = 0; i < dlen; i += 16 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + k = ( i + 16 > dlen ) ? dlen % 16 : 16; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + mbedtls_md_free( &md_ctx ); + + /* + * XOR out with P_sha1(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, S2, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += 20 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + 20 > dlen ) ? dlen % 20 : 20; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +static int tls_prf_generic( mbedtls_md_type_t md_type, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k, md_len; + unsigned char tmp[128]; + unsigned char h_i[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + if( ( md_info = mbedtls_md_info_from_type( md_type ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + md_len = mbedtls_md_get_size( md_info ); + + if( sizeof( tmp ) < md_len + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + nb = strlen( label ); + memcpy( tmp + md_len, label, nb ); + memcpy( tmp + md_len + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, secret, slen ); + mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += md_len ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + md_len > dlen ) ? dlen % md_len : md_len; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SHA256_C) +static int tls_prf_sha256( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA256, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int tls_prf_sha384( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA384, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_verify_ssl( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_ssl( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_verify_tls( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * ); +static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + unsigned char tmp[64]; + unsigned char keyblk[256]; + unsigned char *key1; + unsigned char *key2; + unsigned char *mac_enc; + unsigned char *mac_dec; + size_t iv_copy_len; + const mbedtls_cipher_info_t *cipher_info; + const mbedtls_md_info_t *md_info; + + mbedtls_ssl_session *session = ssl->session_negotiate; + mbedtls_ssl_transform *transform = ssl->transform_negotiate; + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( transform->ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", + transform->ciphersuite_info->cipher ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + md_info = mbedtls_md_info_from_type( transform->ciphersuite_info->mac ); + if( md_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", + transform->ciphersuite_info->mac ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + handshake->tls_prf = ssl3_prf; + handshake->calc_verify = ssl_calc_verify_ssl; + handshake->calc_finished = ssl_calc_finished_ssl; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls1_prf; + handshake->calc_verify = ssl_calc_verify_tls; + handshake->calc_finished = ssl_calc_finished_tls; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && + transform->ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + { + handshake->tls_prf = tls_prf_sha384; + handshake->calc_verify = ssl_calc_verify_tls_sha384; + handshake->calc_finished = ssl_calc_finished_tls_sha384; + } + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls_prf_sha256; + handshake->calc_verify = ssl_calc_verify_tls_sha256; + handshake->calc_finished = ssl_calc_finished_tls_sha256; + } + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * SSLv3: + * master = + * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) + * + * TLSv1+: + * master = PRF( premaster, "master secret", randbytes )[0..47] + */ + if( handshake->resume == 0 ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret", handshake->premaster, + handshake->pmslen ); + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) + { + unsigned char session_hash[48]; + size_t hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); + + ssl->handshake->calc_verify( ssl, session_hash ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { +#if defined(MBEDTLS_SHA512_C) + if( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + hash_len = 48; + } + else +#endif + hash_len = 32; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + hash_len = 36; + + MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, hash_len ); + + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "extended master secret", + session_hash, hash_len, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + } + else +#endif + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "master secret", + handshake->randbytes, 64, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) ); + } + else + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); + + /* + * Swap the client and server random values. + */ + memcpy( tmp, handshake->randbytes, 64 ); + memcpy( handshake->randbytes, tmp + 32, 32 ); + memcpy( handshake->randbytes + 32, tmp, 32 ); + mbedtls_zeroize( tmp, sizeof( tmp ) ); + + /* + * SSLv3: + * key block = + * MD5( master + SHA1( 'A' + master + randbytes ) ) + + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + + * ... + * + * TLSv1: + * key block = PRF( master, "key expansion", randbytes ) + */ + ret = handshake->tls_prf( session->master, 48, "key expansion", + handshake->randbytes, 64, keyblk, 256 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", + mbedtls_ssl_get_ciphersuite_name( session->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", session->master, 48 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); + + mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) ); + + /* + * Determine the appropriate key, IV and MAC length. + */ + + transform->keylen = cipher_info->key_bitlen / 8; + + if( cipher_info->mode == MBEDTLS_MODE_GCM || + cipher_info->mode == MBEDTLS_MODE_CCM ) + { + transform->maclen = 0; + + transform->ivlen = 12; + transform->fixed_ivlen = 4; + + /* Minimum length is expicit IV + tag */ + transform->minlen = transform->ivlen - transform->fixed_ivlen + + ( transform->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 ); + } + else + { + /* Initialize HMAC contexts */ + if( ( ret = mbedtls_md_setup( &transform->md_ctx_enc, md_info, 1 ) ) != 0 || + ( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + /* Get MAC length */ + transform->maclen = mbedtls_md_get_size( md_info ); + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + /* + * If HMAC is to be truncated, we shall keep the leftmost bytes, + * (rfc 6066 page 13 or rfc 2104 section 4), + * so we only need to adjust the length here. + */ + if( session->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + + /* IV length */ + transform->ivlen = cipher_info->iv_size; + + /* Minimum length */ + if( cipher_info->mode == MBEDTLS_MODE_STREAM ) + transform->minlen = transform->maclen; + else + { + /* + * GenericBlockCipher: + * 1. if EtM is in use: one block plus MAC + * otherwise: * first multiple of blocklen greater than maclen + * 2. IV except for SSL3 and TLS 1.0 + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( session->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + transform->minlen = transform->maclen + + cipher_info->block_size; + } + else +#endif + { + transform->minlen = transform->maclen + + cipher_info->block_size + - transform->maclen % cipher_info->block_size; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 ) + ; /* No need to adjust minlen */ + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + transform->minlen += transform->ivlen; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d", + transform->keylen, transform->minlen, transform->ivlen, + transform->maclen ) ); + + /* + * Finally setup the cipher contexts, IVs and MAC secrets. + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + key1 = keyblk + transform->maclen * 2; + key2 = keyblk + transform->maclen * 2 + transform->keylen; + + mac_enc = keyblk; + mac_dec = keyblk + transform->maclen; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_enc, key2 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_dec, key2 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + key1 = keyblk + transform->maclen * 2 + transform->keylen; + key2 = keyblk + transform->maclen * 2; + + mac_enc = keyblk + transform->maclen; + mac_dec = keyblk; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_dec, key1 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_enc, key1 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( transform->maclen > sizeof transform->mac_enc ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( transform->mac_enc, mac_enc, transform->maclen ); + memcpy( transform->mac_dec, mac_dec, transform->maclen ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, transform->maclen ); + mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, transform->maclen ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_init != NULL ) + { + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_init()" ) ); + + if( ( ret = mbedtls_ssl_hw_record_init( ssl, key1, key2, transform->keylen, + transform->iv_enc, transform->iv_dec, + iv_copy_len, + mac_enc, mac_dec, + transform->maclen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_keys != NULL ) + { + ssl->conf->f_export_keys( ssl->conf->p_export_keys, + session->master, keyblk, + transform->maclen, transform->keylen, + iv_copy_len ); + } +#endif + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( cipher_info->mode == MBEDTLS_MODE_CBC ) + { + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_enc, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + mbedtls_zeroize( keyblk, sizeof( keyblk ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + // Initialize compression + // + if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) ); + ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_BUFFER_LEN ); + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + MBEDTLS_SSL_BUFFER_LEN ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); + + memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) ); + memset( &transform->ctx_inflate, 0, sizeof( transform->ctx_inflate ) ); + + if( deflateInit( &transform->ctx_deflate, + Z_DEFAULT_COMPRESSION ) != Z_OK || + inflateInit( &transform->ctx_inflate ) != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char pad_1[48]; + unsigned char pad_2[48]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + memset( pad_1, 0x36, 48 ); + memset( pad_2, 0x5C, 48 ); + + mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_1, 48 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_2, 48 ); + mbedtls_md5_update( &md5, hash, 16 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_1, 40 ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_2, 40 ); + mbedtls_sha1_update( &sha1, hash + 16, 20 ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + mbedtls_md5_finish( &md5, hash ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] ) +{ + mbedtls_sha256_context sha256; + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + mbedtls_sha256_finish( &sha256, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha256_free( &sha256 ); + + return; +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] ) +{ + mbedtls_sha512_context sha512; + + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + mbedtls_sha512_finish( &sha512, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha512_free( &sha512 ); + + return; +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ) +{ + unsigned char *p = ssl->handshake->premaster; + unsigned char *end = p + sizeof( ssl->handshake->premaster ); + const unsigned char *psk = ssl->conf->psk; + size_t psk_len = ssl->conf->psk_len; + + /* If the psk callback was called, use its result */ + if( ssl->handshake->psk != NULL ) + { + psk = ssl->handshake->psk; + psk_len = ssl->handshake->psk_len; + } + + /* + * PMS = struct { + * opaque other_secret<0..2^16-1>; + * opaque psk<0..2^16-1>; + * }; + * with "other_secret" depending on the particular key exchange + */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memset( p, 0, psk_len ); + p += psk_len; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + /* + * other_secret already set by the ClientKeyExchange message, + * and is 48 bytes long + */ + *p++ = 0; + *p++ = 48; + p += 48; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + int ret; + size_t len; + + /* Write length only when we know the actual value */ + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + p + 2, end - ( p + 2 ), &len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + *(p++) = (unsigned char)( len >> 8 ); + *(p++) = (unsigned char)( len ); + p += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + int ret; + size_t zlen; + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen, + p + 2, end - ( p + 2 ), + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( zlen >> 8 ); + *(p++) = (unsigned char)( zlen ); + p += zlen; + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* opaque psk<0..2^16-1>; */ + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( p, psk, psk_len ); + p += psk_len; + + ssl->handshake->pmslen = p - ssl->handshake->premaster; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +/* + * SSLv3.0 MAC functions + */ +static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + unsigned char header[11]; + unsigned char padding[48]; + int padlen; + int md_size = mbedtls_md_get_size( md_ctx->md_info ); + int md_type = mbedtls_md_get_type( md_ctx->md_info ); + + /* Only MD5 and SHA-1 supported */ + if( md_type == MBEDTLS_MD_MD5 ) + padlen = 48; + else + padlen = 40; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, header, 11 ); + mbedtls_md_update( md_ctx, buf, len ); + mbedtls_md_finish( md_ctx, buf + len ); + + memset( padding, 0x5C, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, buf + len, md_size ); + mbedtls_md_finish( md_ctx, buf + len ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) ) +#define SSL_SOME_MODES_USE_MAC +#endif + +/* + * Encryption/decryption functions + */ +static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) +{ + mbedtls_cipher_mode_t mode; + int auth_done = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); + + if( ssl->session_out == NULL || ssl->transform_out == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + + /* + * Add MAC before if needed + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( mode == MBEDTLS_MODE_STREAM || + ( mode == MBEDTLS_MODE_CBC +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + && ssl->session_out->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED +#endif + ) ) + { +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_out->md_ctx_enc, + ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_msg, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_msg + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", + ssl->out_msg + ssl->out_msglen, + ssl->transform_out->maclen ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* AEAD not the only option */ + + /* + * Encrypt + */ +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + ssl->out_msg, ssl->out_msglen, + ssl->out_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->out_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t enc_msglen, olen; + unsigned char *enc_msg; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_out->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + + memcpy( add_data, ssl->out_ctr, 8 ); + add_data[8] = ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->out_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + /* + * Generate IV + */ +#if defined(MBEDTLS_SSL_AEAD_RANDOM_IV) + ret = ssl->conf->f_rng( ssl->conf->p_rng, + ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + if( ret != 0 ) + return( ret ); + + memcpy( ssl->out_iv, + ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); +#else + if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 ) + { + /* Reminder if we ever add an AEAD mode with a different size */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->out_ctr, 8 ); + memcpy( ssl->out_iv, ssl->out_ctr, 8 ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + /* + * Encrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + add_data, 13, + enc_msg, enc_msglen, + enc_msg, &olen, + enc_msg + enc_msglen, taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); + return( ret ); + } + + if( olen != enc_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen += taglen; + auth_done++; + + MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", enc_msg + enc_msglen, taglen ); + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + int ret; + unsigned char *enc_msg; + size_t enc_msglen, padlen, olen = 0, i; + + padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % + ssl->transform_out->ivlen; + if( padlen == ssl->transform_out->ivlen ) + padlen = 0; + + for( i = 0; i <= padlen; i++ ) + ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; + + ssl->out_msglen += padlen + 1; + + enc_msglen = ssl->out_msglen; + enc_msg = ssl->out_msg; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Prepend per-record IV for block cipher in TLS v1.1 and up as per + * Method 1 (6.2.3.2. in RFC4346 and RFC5246) + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Generate IV + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + if( ret != 0 ) + return( ret ); + + memcpy( ssl->out_iv, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of IV and %d bytes of padding", + ssl->out_msglen, ssl->transform_out->ivlen, + padlen + 1 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + enc_msg, enc_msglen, + enc_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( enc_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_out->iv_enc, + ssl->transform_out->cipher_ctx_enc.iv, + ssl->transform_out->ivlen ); + } +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( auth_done == 0 ) + { + /* + * MAC(MAC_write_key, seq_num + + * TLSCipherText.type + + * TLSCipherText.version + + * length_of( (IV +) ENC(...) ) + + * IV + // except for TLS 1.0 + * ENC(content + padding + padding_length)); + */ + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + memcpy( pseudo_hdr + 0, ssl->out_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->out_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->out_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->out_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_iv, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_iv + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) ); + + return( 0 ); +} + +#define SSL_MAX_MAC_SIZE 48 + +static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) +{ + size_t i; + mbedtls_cipher_mode_t mode; + int auth_done = 0; +#if defined(SSL_SOME_MODES_USE_MAC) + size_t padlen = 0, correct = 1; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); + + if( ssl->session_in == NULL || ssl->transform_in == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_in->cipher_ctx_dec ); + + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)", + ssl->in_msglen, ssl->transform_in->minlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + padlen = 0; + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + ssl->in_msg, ssl->in_msglen, + ssl->in_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->in_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t dec_msglen, olen; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_in->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + size_t explicit_iv_len = ssl->transform_in->ivlen - + ssl->transform_in->fixed_ivlen; + + if( ssl->in_msglen < explicit_iv_len + taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " + "+ taglen (%d)", ssl->in_msglen, + explicit_iv_len, taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + dec_msglen = ssl->in_msglen - explicit_iv_len - taglen; + + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + ssl->in_msglen = dec_msglen; + + memcpy( add_data, ssl->in_ctr, 8 ); + add_data[8] = ssl->in_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->in_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, + ssl->in_iv, + ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, + ssl->transform_in->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen ); + + /* + * Decrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + add_data, 13, + dec_msg, dec_msglen, + dec_msg_result, &olen, + dec_msg + dec_msglen, taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret ); + + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + + return( ret ); + } + auth_done++; + + if( olen != dec_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + /* + * Decrypt and check the padding + */ + int ret; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + size_t dec_msglen; + size_t minlen = 0; + size_t olen = 0; + + /* + * Check immediate ciphertext sanity + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + minlen += ssl->transform_in->ivlen; +#endif + + if( ssl->in_msglen < minlen + ssl->transform_in->ivlen || + ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " + "+ 1 ) ( + expl IV )", ssl->in_msglen, + ssl->transform_in->ivlen, + ssl->transform_in->maclen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + dec_msglen = ssl->in_msglen; + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + + /* + * Authenticate before decrypt if enabled + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( ssl->session_in->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + unsigned char computed_mac[SSL_MAX_MAC_SIZE]; + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + dec_msglen -= ssl->transform_in->maclen; + ssl->in_msglen -= ssl->transform_in->maclen; + + memcpy( pseudo_hdr + 0, ssl->in_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->in_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->in_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->in_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, + ssl->in_iv, ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, computed_mac ); + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_iv + ssl->in_msglen, + ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", computed_mac, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, computed_mac, + ssl->transform_in->maclen ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); + + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + + /* + * Check length sanity + */ + if( ssl->in_msglen % ssl->transform_in->ivlen != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", + ssl->in_msglen, ssl->transform_in->ivlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Initialize for prepended IV for block cipher in TLS v1.1 and up + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + dec_msglen -= ssl->transform_in->ivlen; + ssl->in_msglen -= ssl->transform_in->ivlen; + + for( i = 0; i < ssl->transform_in->ivlen; i++ ) + ssl->transform_in->iv_dec[i] = ssl->in_iv[i]; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + dec_msg, dec_msglen, + dec_msg_result, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( dec_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_in->iv_dec, + ssl->transform_in->cipher_ctx_dec.iv, + ssl->transform_in->ivlen ); + } +#endif + + padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; + + if( ssl->in_msglen < ssl->transform_in->maclen + padlen && + auth_done == 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", + ssl->in_msglen, ssl->transform_in->maclen, padlen ) ); +#endif + padlen = 0; + correct = 0; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( padlen > ssl->transform_in->ivlen ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " + "should be no more than %d", + padlen, ssl->transform_in->ivlen ) ); +#endif + correct = 0; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * TLSv1+: always check the padding up to the first failure + * and fake check up to 256 bytes of padding + */ + size_t pad_count = 0, real_count = 1; + size_t padding_idx = ssl->in_msglen - padlen - 1; + + /* + * Padding is guaranteed to be incorrect if: + * 1. padlen >= ssl->in_msglen + * + * 2. padding_idx >= MBEDTLS_SSL_MAX_CONTENT_LEN + + * ssl->transform_in->maclen + * + * In both cases we reset padding_idx to a safe value (0) to + * prevent out-of-buffer reads. + */ + correct &= ( ssl->in_msglen >= padlen + 1 ); + correct &= ( padding_idx < MBEDTLS_SSL_MAX_CONTENT_LEN + + ssl->transform_in->maclen ); + + padding_idx *= correct; + + for( i = 1; i <= 256; i++ ) + { + real_count &= ( i <= padlen ); + pad_count += real_count * + ( ssl->in_msg[padding_idx + i] == padlen - 1 ); + } + + correct &= ( pad_count == padlen ); /* Only 1 on correct padding */ + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( padlen > 0 && correct == 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); +#endif + padlen &= correct * 0x1FF; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_msglen -= padlen; + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "raw buffer after decryption", + ssl->in_msg, ssl->in_msglen ); + + /* + * Authenticate if not done yet. + * Compute the MAC regardless of the padding result (RFC4346, CBCTIME). + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( auth_done == 0 ) + { + unsigned char tmp[SSL_MAX_MAC_SIZE]; + + ssl->in_msglen -= ssl->transform_in->maclen; + + ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); + + memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_in->md_ctx_dec, + ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * Process MAC and always update for padlen afterwards to make + * total time independent of padlen + * + * extra_run compensates MAC check for padlen + * + * Known timing attacks: + * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + * + * We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values + * correctly. (We round down instead of up, so -56 is the correct + * value for our calculations instead of -55) + */ + size_t j, extra_run = 0; + extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 - + ( 13 + ssl->in_msglen + 8 ) / 64; + + extra_run &= correct * 0xFF; + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg, + ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, + ssl->in_msg + ssl->in_msglen ); + /* Call mbedtls_md_process at least once due to cache attacks */ + for( j = 0; j < extra_run + 1; j++ ) + mbedtls_md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg ); + + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", tmp, ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( tmp, ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ) != 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); +#endif + correct = 0; + } + auth_done++; + + /* + * Finally check the correct flag + */ + if( correct == 0 ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } +#endif /* SSL_SOME_MODES_USE_MAC */ + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ssl->in_msglen == 0 ) + { + ssl->nb_zero++; + + /* + * Three or more empty messages may be a DoS attack + * (excessive CPU consumption). + */ + if( ssl->nb_zero > 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received four consecutive empty " + "messages, possible DoS attack" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + } + else + ssl->nb_zero = 0; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ; /* in_ctr read from peer, not maintained internally */ + } + else +#endif + { + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->in_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) ); + + return( 0 ); +} + +#undef MAC_NONE +#undef MAC_PLAINTEXT +#undef MAC_CIPHERTEXT + +#if defined(MBEDTLS_ZLIB_SUPPORT) +/* + * Compression/decompression functions + */ +static int ssl_compress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->out_msg; + size_t len_pre = ssl->out_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->out_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + ssl->transform_out->ctx_deflate.next_in = msg_pre; + ssl->transform_out->ctx_deflate.avail_in = len_pre; + ssl->transform_out->ctx_deflate.next_out = msg_post; + ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_BUFFER_LEN; + + ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->out_msglen = MBEDTLS_SSL_BUFFER_LEN - + ssl->transform_out->ctx_deflate.avail_out; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); + + return( 0 ); +} + +static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->in_msg; + size_t len_pre = ssl->in_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->in_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + ssl->transform_in->ctx_inflate.next_in = msg_pre; + ssl->transform_in->ctx_inflate.avail_in = len_pre; + ssl->transform_in->ctx_inflate.next_out = msg_post; + ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_MAX_CONTENT_LEN; + + ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->in_msglen = MBEDTLS_SSL_MAX_CONTENT_LEN - + ssl->transform_in->ctx_inflate.avail_out; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_resend_hello_request( mbedtls_ssl_context *ssl ) +{ + /* If renegotiation is not enforced, retransmit until we would reach max + * timeout if we were using the usual handshake doubling scheme */ + if( ssl->conf->renego_max_records < 0 ) + { + uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1; + unsigned char doublings = 1; + + while( ratio != 0 ) + { + ++doublings; + ratio >>= 1; + } + + if( ++ssl->renego_records_seen > doublings ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "no longer retransmitting hello request" ) ); + return( 0 ); + } + } + + return( ssl_write_hello_request( ssl ) ); +} +#endif +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Fill the input message buffer by appending data to it. + * The amount of data already fetched is in ssl->in_left. + * + * If we return 0, is it guaranteed that (at least) nb_want bytes are + * available (from this read and/or a previous one). Otherwise, an error code + * is returned (possibly EOF or WANT_READ). + * + * With stream transport (TLS) on success ssl->in_left == nb_want, but + * with datagram transport (DTLS) on success ssl->in_left >= nb_want, + * since we always read a whole datagram at once. + * + * For DTLS, it is up to the caller to set ssl->next_record_offset when + * they're done reading a record. + */ +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) +{ + int ret; + size_t len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); + + if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( nb_want > MBEDTLS_SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + uint32_t timeout; + + /* Just to be sure */ + if( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use " + "mbedtls_ssl_set_timer_cb() for DTLS" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * The point is, we need to always read a full datagram at once, so we + * sometimes read more then requested, and handle the additional data. + * It could be the rest of the current record (while fetching the + * header) and/or some other records in the same datagram. + */ + + /* + * Move to the next record in the already read datagram if applicable + */ + if( ssl->next_record_offset != 0 ) + { + if( ssl->in_left < ssl->next_record_offset ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_left -= ssl->next_record_offset; + + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d", + ssl->next_record_offset ) ); + memmove( ssl->in_hdr, + ssl->in_hdr + ssl->next_record_offset, + ssl->in_left ); + } + + ssl->next_record_offset = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + /* + * Done if we already have enough data. + */ + if( nb_want <= ssl->in_left) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + return( 0 ); + } + + /* + * A record can't be split accross datagrams. If we need to read but + * are not at the beginning of a new record, the caller did something + * wrong. + */ + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Don't even try to read if time's out already. + * This avoids by-passing the timer when repeatedly receiving messages + * that will end up being dropped. + */ + if( ssl_check_timer( ssl ) != 0 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + len = MBEDTLS_SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + timeout = ssl->handshake->retransmit_timeout; + else + timeout = ssl->conf->read_timeout; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) ); + + if( ssl->f_recv_timeout != NULL ) + ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len, + timeout ); + else + ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + } + + if( ret == MBEDTLS_ERR_SSL_TIMEOUT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "timeout" ) ); + ssl_set_timer( ssl, 0 ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl_double_retransmit_timeout( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); + return( MBEDTLS_ERR_SSL_TIMEOUT ); + } + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + } + + if( ret < 0 ) + return( ret ); + + ssl->in_left = ret; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + while( ssl->in_left < nb_want ) + { + len = nb_want - ssl->in_left; + + if( ssl_check_timer( ssl ) != 0 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + if( ssl->f_recv_timeout != NULL ) + { + ret = ssl->f_recv_timeout( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len, + ssl->conf->read_timeout ); + } + else + { + ret = ssl->f_recv( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + + if( ret < 0 ) + return( ret ); + + ssl->in_left += ret; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + + return( 0 ); +} + +/* + * Flush any data not yet written + */ +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf, i; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); + + if( ssl->f_send == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Avoid incrementing counter if data is flushed */ + if( ssl->out_left == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + return( 0 ); + } + + while( ssl->out_left > 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", + mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); + + buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) + + ssl->out_msglen - ssl->out_left; + ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret ); + + if( ret <= 0 ) + return( ret ); + + ssl->out_left -= ret; + } + + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + + return( 0 ); +} + +/* + * Functions to handle the DTLS retransmission state machine + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Append current handshake message to current outgoing flight + */ +static int ssl_flight_append( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_flight_item *msg; + + /* Allocate space for current message */ + if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", + sizeof( mbedtls_ssl_flight_item ) ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + if( ( msg->p = mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", ssl->out_msglen ) ); + mbedtls_free( msg ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Copy current handshake message with headers */ + memcpy( msg->p, ssl->out_msg, ssl->out_msglen ); + msg->len = ssl->out_msglen; + msg->type = ssl->out_msgtype; + msg->next = NULL; + + /* Append to the current flight */ + if( ssl->handshake->flight == NULL ) + ssl->handshake->flight = msg; + else + { + mbedtls_ssl_flight_item *cur = ssl->handshake->flight; + while( cur->next != NULL ) + cur = cur->next; + cur->next = msg; + } + + return( 0 ); +} + +/* + * Free the current flight of handshake messages + */ +static void ssl_flight_free( mbedtls_ssl_flight_item *flight ) +{ + mbedtls_ssl_flight_item *cur = flight; + mbedtls_ssl_flight_item *next; + + while( cur != NULL ) + { + next = cur->next; + + mbedtls_free( cur->p ); + mbedtls_free( cur ); + + cur = next; + } +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ); +#endif + +/* + * Swap transform_out and out_ctr with the alternative ones + */ +static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_transform *tmp_transform; + unsigned char tmp_out_ctr[8]; + + if( ssl->transform_out == ssl->handshake->alt_transform_out ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip swap epochs" ) ); + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "swap epochs" ) ); + + /* Swap transforms */ + tmp_transform = ssl->transform_out; + ssl->transform_out = ssl->handshake->alt_transform_out; + ssl->handshake->alt_transform_out = tmp_transform; + + /* Swap epoch + sequence_number */ + memcpy( tmp_out_ctr, ssl->out_ctr, 8 ); + memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 ); + memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); + + /* Adjust to the newly activated transform */ + if( ssl->transform_out != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif +} + +/* + * Retransmit the current flight of messages. + * + * Need to remember the current message in case flush_output returns + * WANT_WRITE, causing us to exit this function and come back later. + * This function must be called until state is no longer SENDING. + */ +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + + if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) ); + + ssl->handshake->cur_msg = ssl->handshake->flight; + ssl_swap_epochs( ssl ); + + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; + } + + while( ssl->handshake->cur_msg != NULL ) + { + int ret; + mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg; + + /* Swap epochs before sending Finished: we can't do it after + * sending ChangeCipherSpec, in case write returns WANT_READ. + * Must be done before copying, may change out_msg pointer */ + if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && + cur->p[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl_swap_epochs( ssl ); + } + + memcpy( ssl->out_msg, cur->p, cur->len ); + ssl->out_msglen = cur->len; + ssl->out_msgtype = cur->type; + + ssl->handshake->cur_msg = cur->next; + + MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + else + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); + + return( 0 ); +} + +/* + * To be called when the last message of an incoming flight is received. + */ +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) +{ + /* We won't need to resend that one any more */ + ssl_flight_free( ssl->handshake->flight ); + ssl->handshake->flight = NULL; + ssl->handshake->cur_msg = NULL; + + /* The next incoming flight will start with this msg_seq */ + ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq; + + /* Cancel timer */ + ssl_set_timer( ssl, 0 ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; +} + +/* + * To be called when the last message of an outgoing flight is send. + */ +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) +{ + ssl_reset_retransmit_timeout( ssl ); + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +/* + * Record layer functions + */ + +/* + * Write current record. + * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. + */ +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0; + size_t len = ssl->out_msglen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + ; /* Skip special handshake treatment when resending */ + } + else +#endif + if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST && + ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); + ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); + ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); + + /* + * DTLS has additional fields in the Handshake layer, + * between the length field and the actual payload: + * uint16 message_seq; + * uint24 fragment_offset; + * uint24 fragment_length; + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Make room for the additional DTLS fields */ + memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); + ssl->out_msglen += 8; + len += 8; + + /* Write message_seq and update it, except for HelloRequest */ + if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ) + { + ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF; + ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF; + ++( ssl->handshake->out_msg_seq ); + } + else + { + ssl->out_msg[4] = 0; + ssl->out_msg[5] = 0; + } + + /* We don't fragment, so frag_offset = 0 and frag_len = len */ + memset( ssl->out_msg + 6, 0x00, 3 ); + memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ssl->out_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST ) + ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); + } + + /* Save handshake and CCS messages for resending */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING && + ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC || + ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) ) + { + if( ( ret = ssl_flight_append( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); + return( ret ); + } + } +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_out != NULL && + ssl->session_out->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + } +#endif /*MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_write != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_write()" ) ); + + ret = mbedtls_ssl_hw_record_write( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_write", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done ) + { + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, ssl->out_hdr + 1 ); + + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + + if( ssl->transform_out != NULL ) + { + if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + } + + ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2], + ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", + ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen ); + } + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Mark bits in bitmask (used for DTLS HS reassembly) + */ +static void ssl_bitmask_set( unsigned char *mask, size_t offset, size_t len ) +{ + unsigned int start_bits, end_bits; + + start_bits = 8 - ( offset % 8 ); + if( start_bits != 8 ) + { + size_t first_byte_idx = offset / 8; + + /* Special case */ + if( len <= start_bits ) + { + for( ; len != 0; len-- ) + mask[first_byte_idx] |= 1 << ( start_bits - len ); + + /* Avoid potential issues with offset or len becoming invalid */ + return; + } + + offset += start_bits; /* Now offset % 8 == 0 */ + len -= start_bits; + + for( ; start_bits != 0; start_bits-- ) + mask[first_byte_idx] |= 1 << ( start_bits - 1 ); + } + + end_bits = len % 8; + if( end_bits != 0 ) + { + size_t last_byte_idx = ( offset + len ) / 8; + + len -= end_bits; /* Now len % 8 == 0 */ + + for( ; end_bits != 0; end_bits-- ) + mask[last_byte_idx] |= 1 << ( 8 - end_bits ); + } + + memset( mask + offset / 8, 0xFF, len / 8 ); +} + +/* + * Check that bitmask is full + */ +static int ssl_bitmask_check( unsigned char *mask, size_t len ) +{ + size_t i; + + for( i = 0; i < len / 8; i++ ) + if( mask[i] != 0xFF ) + return( -1 ); + + for( i = 0; i < len % 8; i++ ) + if( ( mask[len / 8] & ( 1 << ( 7 - i ) ) ) == 0 ) + return( -1 ); + + return( 0 ); +} + +/* + * Reassemble fragmented DTLS handshake messages. + * + * Use a temporary buffer for reassembly, divided in two parts: + * - the first holds the reassembled message (including handshake header), + * - the second holds a bitmask indicating which parts of the message + * (excluding headers) have been received so far. + */ +static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) +{ + unsigned char *msg, *bitmask; + size_t frag_len, frag_off; + size_t msg_len = ssl->in_hslen - 12; /* Without headers */ + + if( ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * For first fragment, check size and allocate buffer + */ + if( ssl->handshake->hs_msg == NULL ) + { + size_t alloc_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", + msg_len ) ); + + if( ssl->in_hslen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* The bitmask needs one bit per byte of message excluding header */ + alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 ); + + ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len ); + if( ssl->handshake->hs_msg == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Prepare final header: copy msg_type, length and message_seq, + * then add standardised fragment_offset and fragment_length */ + memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 ); + memset( ssl->handshake->hs_msg + 6, 0, 3 ); + memcpy( ssl->handshake->hs_msg + 9, + ssl->handshake->hs_msg + 1, 3 ); + } + else + { + /* Make sure msg_type and length are consistent */ + if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + + msg = ssl->handshake->hs_msg + 12; + bitmask = msg + msg_len; + + /* + * Check and copy current fragment + */ + frag_off = ( ssl->in_msg[6] << 16 ) | + ( ssl->in_msg[7] << 8 ) | + ssl->in_msg[8]; + frag_len = ( ssl->in_msg[9] << 16 ) | + ( ssl->in_msg[10] << 8 ) | + ssl->in_msg[11]; + + if( frag_off + frag_len > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d", + frag_off, frag_len, msg_len ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( frag_len + 12 > ssl->in_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d", + frag_len, ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d", + frag_off, frag_len ) ); + + memcpy( msg + frag_off, ssl->in_msg + 12, frag_len ); + ssl_bitmask_set( bitmask, frag_off, frag_len ); + + /* + * Do we have the complete message by now? + * If yes, finalize it, else ask to read the next record. + */ + if( ssl_bitmask_check( bitmask, msg_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) ); + + if( frag_len + 12 < ssl->in_msglen ) + { + /* + * We'got more handshake messages in the same record. + * This case is not handled now because no know implementation does + * that and it's hard to test, so we prefer to fail cleanly for now. + */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( ssl->in_left > ssl->next_record_offset ) + { + /* + * We've got more data in the buffer after the current record, + * that we don't want to overwrite. Move it before writing the + * reassembled message, and adjust in_left and next_record_offset. + */ + unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset; + unsigned char *new_remain = ssl->in_msg + ssl->in_hslen; + size_t remain_len = ssl->in_left - ssl->next_record_offset; + + /* First compute and check new lengths */ + ssl->next_record_offset = new_remain - ssl->in_hdr; + ssl->in_left = ssl->next_record_offset + remain_len; + + if( ssl->in_left > MBEDTLS_SSL_BUFFER_LEN - + (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + memmove( new_remain, cur_remain, remain_len ); + } + + memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen ); + + mbedtls_free( ssl->handshake->hs_msg ); + ssl->handshake->hs_msg = NULL; + + MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message", + ssl->in_msg, ssl->in_hslen ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too short: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ( + ( ssl->in_msg[1] << 16 ) | + ( ssl->in_msg[2] << 8 ) | + ssl->in_msg[3] ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" + " %d, type = %d, hslen = %d", + ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + int ret; + unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + + /* ssl->handshake is NULL when receiving ClientHello for renego */ + if( ssl->handshake != NULL && + recv_msg_seq != ssl->handshake->in_msg_seq ) + { + /* Retransmit only on last message from previous flight, to avoid + * too many retransmissions. + * Besides, No sane server ever retransmits HelloVerifyRequest */ + if( recv_msg_seq == ssl->handshake->in_flight_start_seq - 1 && + ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received message from last flight, " + "message_seq = %d, start_of_flight = %d", + recv_msg_seq, + ssl->handshake->in_flight_start_seq ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "dropping out-of-sequence message: " + "message_seq = %d, expected = %d", + recv_msg_seq, + ssl->handshake->in_msg_seq ) ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + /* Wait until message completion to increment in_msg_seq */ + + /* Reassemble if current message is fragmented or reassembly is + * already in progress */ + if( ssl->in_msglen < ssl->in_hslen || + memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 || + memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 || + ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) ); + + if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret ); + return( ret ); + } + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + /* With TLS we don't handle fragmentation (for now) */ + if( ssl->in_msglen < ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->handshake != NULL ) + { + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + + /* Handshake message is complete, increment counter */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL ) + { + ssl->handshake->in_msg_seq++; + } +#endif + + return( 0 ); +} + +/* + * DTLS anti-replay: RFC 6347 4.1.2.6 + * + * in_window is a field of bits numbered from 0 (lsb) to 63 (msb). + * Bit n is set iff record number in_window_top - n has been seen. + * + * Usually, in_window_top is the last record number seen and the lsb of + * in_window is set. The only exception is the initial state (record number 0 + * not seen yet). + */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ) +{ + ssl->in_window_top = 0; + ssl->in_window = 0; +} + +static inline uint64_t ssl_load_six_bytes( unsigned char *buf ) +{ + return( ( (uint64_t) buf[0] << 40 ) | + ( (uint64_t) buf[1] << 32 ) | + ( (uint64_t) buf[2] << 24 ) | + ( (uint64_t) buf[3] << 16 ) | + ( (uint64_t) buf[4] << 8 ) | + ( (uint64_t) buf[5] ) ); +} + +/* + * Return 0 if sequence number is acceptable, -1 otherwise + */ +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + uint64_t bit; + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return( 0 ); + + if( rec_seqnum > ssl->in_window_top ) + return( 0 ); + + bit = ssl->in_window_top - rec_seqnum; + + if( bit >= 64 ) + return( -1 ); + + if( ( ssl->in_window & ( (uint64_t) 1 << bit ) ) != 0 ) + return( -1 ); + + return( 0 ); +} + +/* + * Update replay window on new validated record + */ +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return; + + if( rec_seqnum > ssl->in_window_top ) + { + /* Update window_top and the contents of the window */ + uint64_t shift = rec_seqnum - ssl->in_window_top; + + if( shift >= 64 ) + ssl->in_window = 1; + else + { + ssl->in_window <<= shift; + ssl->in_window |= 1; + } + + ssl->in_window_top = rec_seqnum; + } + else + { + /* Mark that number as seen in the current window */ + uint64_t bit = ssl->in_window_top - rec_seqnum; + + if( bit < 64 ) /* Always true, but be extra sure */ + ssl->in_window |= (uint64_t) 1 << bit; + } +} +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) +/* Forward declaration */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ); + +/* + * Without any SSL context, check if a datagram looks like a ClientHello with + * a valid cookie, and if it doesn't, generate a HelloVerifyRequest message. + * Both input and output include full DTLS headers. + * + * - if cookie is valid, return 0 + * - if ClientHello looks superficially valid but cookie is not, + * fill obuf and set olen, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - otherwise return a specific error code + */ +static int ssl_check_dtls_clihlo_cookie( + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie, + const unsigned char *cli_id, size_t cli_id_len, + const unsigned char *in, size_t in_len, + unsigned char *obuf, size_t buf_len, size_t *olen ) +{ + size_t sid_len, cookie_len; + unsigned char *p; + + if( f_cookie_write == NULL || f_cookie_check == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* + * Structure of ClientHello with record and handshake headers, + * and expected values. We don't need to check a lot, more checks will be + * done when actually parsing the ClientHello - skipping those checks + * avoids code duplication and does not make cookie forging any easier. + * + * 0-0 ContentType type; copied, must be handshake + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied, must be 0 + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; (ignored) + * + * 13-13 HandshakeType msg_type; (ignored) + * 14-16 uint24 length; (ignored) + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied, must be 0 + * 22-24 uint24 fragment_length; (ignored) + * + * 25-26 ProtocolVersion client_version; (ignored) + * 27-58 Random random; (ignored) + * 59-xx SessionID session_id; 1 byte len + sid_len content + * 60+ opaque cookie<0..2^8-1>; 1 byte len + content + * ... + * + * Minimum length is 61 bytes. + */ + if( in_len < 61 || + in[0] != MBEDTLS_SSL_MSG_HANDSHAKE || + in[3] != 0 || in[4] != 0 || + in[19] != 0 || in[20] != 0 || in[21] != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + sid_len = in[59]; + if( sid_len > in_len - 61 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cookie_len = in[60 + sid_len]; + if( cookie_len > in_len - 60 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( f_cookie_check( p_cookie, in + sid_len + 61, cookie_len, + cli_id, cli_id_len ) == 0 ) + { + /* Valid cookie */ + return( 0 ); + } + + /* + * If we get here, we've got an invalid cookie, let's prepare HVR. + * + * 0-0 ContentType type; copied + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; olen - 13 + * + * 13-13 HandshakeType msg_type; hello_verify_request + * 14-16 uint24 length; olen - 25 + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied + * 22-24 uint24 fragment_length; olen - 25 + * + * 25-26 ProtocolVersion server_version; 0xfe 0xff + * 27-27 opaque cookie<0..2^8-1>; cookie_len = olen - 27, cookie + * + * Minimum length is 28. + */ + if( buf_len < 28 ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + /* Copy most fields and adapt others */ + memcpy( obuf, in, 25 ); + obuf[13] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + obuf[25] = 0xfe; + obuf[26] = 0xff; + + /* Generate and write actual cookie */ + p = obuf + 28; + if( f_cookie_write( p_cookie, + &p, obuf + buf_len, cli_id, cli_id_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + *olen = p - obuf; + + /* Go back and fill length fields */ + obuf[27] = (unsigned char)( *olen - 28 ); + + obuf[14] = obuf[22] = (unsigned char)( ( *olen - 25 ) >> 16 ); + obuf[15] = obuf[23] = (unsigned char)( ( *olen - 25 ) >> 8 ); + obuf[16] = obuf[24] = (unsigned char)( ( *olen - 25 ) ); + + obuf[11] = (unsigned char)( ( *olen - 13 ) >> 8 ); + obuf[12] = (unsigned char)( ( *olen - 13 ) ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +} + +/* + * Handle possible client reconnect with the same UDP quadruplet + * (RFC 6347 Section 4.2.8). + * + * Called by ssl_parse_record_header() in case we receive an epoch 0 record + * that looks like a ClientHello. + * + * - if the input looks like a ClientHello without cookies, + * send back HelloVerifyRequest, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - if the input looks like a ClientHello with a valid cookie, + * reset the session of the current context, and + * return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * - if anything goes wrong, return a specific error code + * + * mbedtls_ssl_read_record() will ignore the record if anything else than + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT or 0 is returned, although this function + * cannot not return 0. + */ +static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t len; + + ret = ssl_check_dtls_clihlo_cookie( + ssl->conf->f_cookie_write, + ssl->conf->f_cookie_check, + ssl->conf->p_cookie, + ssl->cli_id, ssl->cli_id_len, + ssl->in_buf, ssl->in_left, + ssl->out_buf, MBEDTLS_SSL_MAX_CONTENT_LEN, &len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret ); + + if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ) + { + /* Dont check write errors as we can't do anything here. + * If the error is permanent we'll catch it later, + * if it's not, then hopefully it'll work next time. */ + (void) ssl->f_send( ssl->p_bio, ssl->out_buf, len ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); + } + + if( ret == 0 ) + { + /* Got a valid cookie, partially reset context */ + if( ( ret = ssl_session_reset_int( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "reset", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_CLIENT_RECONNECT ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + +/* + * ContentType type; + * ProtocolVersion version; + * uint16 epoch; // DTLS only + * uint48 sequence_number; // DTLS only + * uint16 length; + * + * Return 0 if header looks sane (and, for DTLS, the record is expected) + * MBEDTLS_ERR_SSL_INVALID_RECORD if the header looks bad, + * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD (DTLS only) if sane but unexpected. + * + * With DTLS, mbedtls_ssl_read_record() will: + * 1. proceed with the record if this function returns 0 + * 2. drop only the current record if this function returns UNEXPECTED_RECORD + * 3. return CLIENT_RECONNECT if this function return that value + * 4. drop the whole datagram if this function returns anything else. + * Point 2 is needed when the peer is resending, and we have already received + * the first record from a datagram but are still waiting for the others. + */ +static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) +{ + int ret; + int major_ver, minor_ver; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record header", ssl->in_hdr, mbedtls_ssl_hdr_len( ssl ) ); + + ssl->in_msgtype = ssl->in_hdr[0]; + ssl->in_msglen = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, ssl->in_hdr + 1 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->in_msgtype, + major_ver, minor_ver, ssl->in_msglen ) ); + + /* Check record type */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msgtype != MBEDTLS_SSL_MSG_ALERT && + ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check version */ + if( major_ver != ssl->major_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check length against the size of our buffer */ + if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN + - (size_t)( ssl->in_msg - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check length against bounds of the current transform and version */ + if( ssl->transform_in == NULL ) + { + if( ssl->in_msglen < 1 || + ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + else + { + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * TLS encrypted messages can have up to 256 bytes of padding + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 && + ssl->in_msglen > ssl->transform_in->minlen + + MBEDTLS_SSL_MAX_CONTENT_LEN + 256 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif + } + + /* + * DTLS-related tests done last, because most of them may result in + * silently dropping the record (but not the whole datagram), and we only + * want to consider that after ensuring that the "basic" fields (type, + * version, length) are sane. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1]; + + /* Drop unexpected ChangeCipherSpec messages */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + /* Drop unexpected ApplicationData records, + * except at the beginning of renegotiations */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA && + ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + /* Check epoch (and sequence number) with DTLS */ + if( rec_epoch != ssl->in_epoch ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: " + "expected %d, received %d", + ssl->in_epoch, rec_epoch ) ); + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) + /* + * Check for an epoch 0 ClientHello. We can't use in_msg here to + * access the first byte of record content (handshake type), as we + * have an active transform (possibly iv_len != 0), so use the + * fact that the record header len is 13 instead. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER && + rec_epoch == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_left > 13 && + ssl->in_buf[13] == MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "possible client reconnect " + "from the same port" ) ); + return( ssl_handle_possible_reconnect( ssl ) ); + } + else +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + /* Replay detection only works for the current epoch */ + if( rec_epoch == ssl->in_epoch && + mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + return( 0 ); +} + +/* + * If applicable, decrypt (and decompress) record content + */ +static int ssl_prepare_record_content( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record from network", + ssl->in_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->in_msglen ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_read != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_read()" ) ); + + ret = mbedtls_ssl_hw_record_read( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_read", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done && ssl->transform_in != NULL ) + { + if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", + ssl->in_msg, ssl->in_msglen ); + + if( ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_in != NULL && + ssl->session_in->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_decompress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decompress_buf", ret ); + return( ret ); + } + + // TODO: what's the purpose of these lines? is in_len used? + ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + mbedtls_ssl_dtls_replay_update( ssl ); + } +#endif + + return( 0 ); +} + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ); + +/* + * Read a record. + * + * Silently ignore non-fatal alert (and for DTLS, invalid records as well, + * RFC 6347 4.1.2.7) and continue reading until a valid record is found. + * + */ +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); + + if( ssl->in_hslen != 0 && ssl->in_hslen < ssl->in_msglen ) + { + /* + * Get next Handshake message in the current record + */ + ssl->in_msglen -= ssl->in_hslen; + + memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen, + ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record", + ssl->in_msg, ssl->in_msglen ); + + if( ( ret = ssl_prepare_handshake_record( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); + } + + ssl->in_hslen = 0; + + /* + * Read the record header and parse it + */ +read_record_header: + if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + if( ( ret = ssl_parse_record_header( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT ) + { + if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ) + { + /* Skip unexpected record (but not whole datagram) */ + ssl->next_record_offset = ssl->in_msglen + + mbedtls_ssl_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding unexpected record " + "(header)" ) ); + } + else + { + /* Skip invalid record and the rest of the datagram */ + ssl->next_record_offset = 0; + ssl->in_left = 0; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record " + "(header)" ) ); + } + + /* Get next record */ + goto read_record_header; + } +#endif + return( ret ); + } + + /* + * Read and optionally decrypt the message contents + */ + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + ssl->in_msglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_hdr_len( ssl ); + else +#endif + ssl->in_left = 0; + + if( ( ret = ssl_prepare_record_content( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Silently discard invalid records */ + if( ret == MBEDTLS_ERR_SSL_INVALID_RECORD || + ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + /* Except when waiting for Finished as a bad mac here + * probably means something went wrong in the handshake + * (eg wrong psk used, mitm downgrade attempt, etc.) */ + if( ssl->state == MBEDTLS_SSL_CLIENT_FINISHED || + ssl->state == MBEDTLS_SSL_SERVER_FINISHED ) + { +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + if( ssl->conf->badmac_limit != 0 && + ++ssl->badmac_seen >= ssl->conf->badmac_limit ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "too many records with bad MAC" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } +#endif + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) ); + goto read_record_header; + } + + return( ret ); + } + else +#endif + { + /* Error out (and send alert) on invalid records */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + } + + /* + * When we sent the last flight of the handshake, we MUST respond to a + * retransmit of the peer's previous flight with a retransmit. (In + * practice, only the Finished message will make it, other messages + * including CCS use the old transform so they're dropped as invalid.) + * + * If the record we received is not a handshake message, however, it + * means the peer received our last flight so we can clean up + * handshake info. + * + * This check needs to be done before prepare_handshake() due to an edge + * case: if the client immediately requests renegotiation, this + * finishes the current handshake first, avoiding the new ClientHello + * being mistaken for an ancient message in the current handshake. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + else + { + ssl_handshake_wrapup_free_hs_transform( ssl ); + } + } +#endif + + /* + * Handle particular types of records + */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + if( ( ret = ssl_prepare_handshake_record( ssl ) ) != 0 ) + return( ret ); + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got an alert message, type: [%d:%d]", + ssl->in_msg[0], ssl->in_msg[1] ) ); + + /* + * Ignore non-fatal alerts, except close_notify and no_renegotiation + */ + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_FATAL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "is a fatal alert message (msg %d)", + ssl->in_msg[1] ) ); + return( MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE ); + } + + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a close notify message" ) ); + return( MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION_ENABLED) + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + /* Will be handled when trying to parse ServerHello */ + return( 0 ); + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_SRV_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + /* Will be handled in mbedtls_ssl_parse_certificate() */ + return( 0 ); + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */ + + /* Silently ignore: fetch new message */ + goto read_record_header; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read record" ) ); + + return( 0 ); +} + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msglen = 2; + ssl->out_msg[0] = level; + ssl->out_msg[1] = message; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + + return( 0 ); +} + +/* + * Handshake functions + */ +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_x509_crt *crt; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * If using SSLv3 and got no cert, send an Alert message + * (otherwise an empty Certificate message will be sent). + */ + if( mbedtls_ssl_own_cert( ssl ) == NULL && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->out_msglen = 2; + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msg[0] = MBEDTLS_SSL_ALERT_LEVEL_WARNING; + ssl->out_msg[1] = MBEDTLS_SSL_ALERT_MSG_NO_CERT; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got no certificate to send" ) ); + goto write_msg; + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + } +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } +#endif + + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 6 length of all certs + * 7 . 9 length of cert. 1 + * 10 . n-1 peer certificate + * n . n+2 length of cert. 2 + * n+3 . ... upper level cert, etc. + */ + i = 7; + crt = mbedtls_ssl_own_cert( ssl ); + + while( crt != NULL ) + { + n = crt->raw.len; + if( n > MBEDTLS_SSL_MAX_CONTENT_LEN - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + ssl->out_msg[i ] = (unsigned char)( n >> 16 ); + ssl->out_msg[i + 1] = (unsigned char)( n >> 8 ); + ssl->out_msg[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n ); + i += n; crt = crt->next; + } + + ssl->out_msg[4] = (unsigned char)( ( i - 7 ) >> 16 ); + ssl->out_msg[5] = (unsigned char)( ( i - 7 ) >> 8 ); + ssl->out_msg[6] = (unsigned char)( ( i - 7 ) ); + + ssl->out_msglen = i; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C) +write_msg: +#endif + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + + return( ret ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + int authmode = ssl->conf->authmode; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * Check if the client sent an empty certificate + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_msglen == 2 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_SRV_C */ + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE || + ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * Same message structure as in mbedtls_ssl_write_certificate() + */ + n = ( ssl->in_msg[i+1] << 8 ) | ssl->in_msg[i+2]; + + if( ssl->in_msg[i] != 0 || + ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* In case we tried to reuse a session but it failed */ + if( ssl->session_negotiate->peer_cert != NULL ) + { + mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); + mbedtls_free( ssl->session_negotiate->peer_cert ); + } + + if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + sizeof( mbedtls_x509_crt ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( mbedtls_x509_crt ) ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + + i += 3; + + while( i < ssl->in_hslen ) + { + if( ssl->in_msg[i] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + n = ( (unsigned int) ssl->in_msg[i + 1] << 8 ) + | (unsigned int) ssl->in_msg[i + 2]; + i += 3; + + if( n < 128 || i + n > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, + ssl->in_msg + i, n ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + } + + i += n; + } + + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + + /* + * On client, make sure the server cert doesn't change during renego to + * avoid "triple handshake" attack: https://secure-resumption.com/ + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->session->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + if( ssl->session->peer_cert->raw.len != + ssl->session_negotiate->peer_cert->raw.len || + memcmp( ssl->session->peer_cert->raw.p, + ssl->session_negotiate->peer_cert->raw.p, + ssl->session->peer_cert->raw.len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + + if( authmode != MBEDTLS_SSL_VERIFY_NONE ) + { + mbedtls_x509_crt *ca_chain; + mbedtls_x509_crl *ca_crl; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + if( ca_chain == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + return( MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED ); + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_with_profile( + ssl->session_negotiate->peer_cert, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, + ciphersuite_info, + ! ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + ret = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->out_msglen = 1; + ssl->out_msg[0] = 1; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + + return( 0 ); +} + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + /* + * Switch to our negotiated transform and session parameters for inbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) ); + ssl->transform_in = ssl->transform_negotiate; + ssl->session_in = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + /* Increment epoch */ + if( ++ssl->in_epoch == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->in_ctr, 0, 8 ); + + /* + * Set the in_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->in_msg = ssl->in_iv; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) ); + + return( 0 ); +} + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) +{ + ((void) ciphersuite_info); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha384; + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha256; + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return; + } +} + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_starts( &ssl->handshake->fin_md5 ); + mbedtls_sha1_starts( &ssl->handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_starts( &ssl->handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_starts( &ssl->handshake->fin_sha512, 1 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_update( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &ssl->handshake->fin_sha1, buf, len ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_md5_update( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &ssl->handshake->fin_sha1, buf, len ); +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +} +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +} +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_finished_ssl( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + unsigned char padbuf[48]; + unsigned char md5sum[16]; + unsigned char sha1sum[20]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * SSLv3: + * hash = + * MD5( master + pad2 + + * MD5( handshake + sender + master + pad1 ) ) + * + SHA1( master + pad2 + + * SHA1( handshake + sender + master + pad1 ) ) + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) ? "CLNT" + : "SRVR"; + + memset( padbuf, 0x36, 48 ); + + mbedtls_md5_update( &md5, (const unsigned char *) sender, 4 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_finish( &md5, md5sum ); + + mbedtls_sha1_update( &sha1, (const unsigned char *) sender, 4 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf, 40 ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + memset( padbuf, 0x5C, 48 ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_update( &md5, md5sum, 16 ); + mbedtls_md5_finish( &md5, buf ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf , 40 ); + mbedtls_sha1_update( &sha1, sha1sum, 20 ); + mbedtls_sha1_finish( &sha1, buf + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_zeroize( md5sum, sizeof( md5sum ) ); + mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_finished_tls( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padbuf[36]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * TLSv1: + * hash = PRF( master, finished_label, + * MD5( handshake ) + SHA1( handshake ) )[0..11] + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_md5_finish( &md5, padbuf ); + mbedtls_sha1_finish( &sha1, padbuf + 16 ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 36, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_calc_finished_tls_sha256( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_sha256_context sha256; + unsigned char padbuf[32]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA256_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *) + sha256.state, sizeof( sha256.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha256_finish( &sha256, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 32, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha256_free( &sha256 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static void ssl_calc_finished_tls_sha384( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_sha512_context sha512; + unsigned char padbuf[48]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA512_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha512 state", (unsigned char *) + sha512.state, sizeof( sha512.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha512_finish( &sha512, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 48, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha512_free( &sha512 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) ); + + /* + * Free our handshake params + */ + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_free( ssl->handshake ); + ssl->handshake = NULL; + + /* + * Free the previous transform and swith in the current one + */ + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + ssl->transform = ssl->transform_negotiate; + ssl->transform_negotiate = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) ); +} + +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ) +{ + int resume = ssl->handshake->resume; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_DONE; + ssl->renego_records_seen = 0; + } +#endif + + /* + * Free the previous session and switch in the current one + */ + if( ssl->session ) + { +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + /* RFC 7366 3.1: keep the EtM state */ + ssl->session_negotiate->encrypt_then_mac = + ssl->session->encrypt_then_mac; +#endif + + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + /* + * Add cache entry + */ + if( ssl->conf->f_set_cache != NULL && + ssl->session->id_len != 0 && + resume == 0 ) + { + if( ssl->conf->f_set_cache( ssl->conf->p_cache, ssl->session ) != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->flight != NULL ) + { + /* Cancel handshake timer */ + ssl_set_timer( ssl, 0 ); + + /* Keep last flight around in case we need to resend it: + * we need the handshake and transform structures for that */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) ); + } + else +#endif + ssl_handshake_wrapup_free_hs_transform( ssl ); + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) +{ + int ret, hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + /* + * Set the out_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + + ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint ); + + // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) + hash_len = ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) ? 36 : 12; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->own_verify_data, ssl->out_msg + 4, hash_len ); +#endif + + ssl->out_msglen = 4 + hash_len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_FINISHED; + + /* + * In case of session resuming, invert the client and server + * ChangeCipherSpec messages order. + */ + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif + } + else + ssl->state++; + + /* + * Switch to our negotiated transform and session parameters for outbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned char i; + + /* Remember current epoch settings for resending */ + ssl->handshake->alt_transform_out = ssl->transform_out; + memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 ); + + /* Set sequence_number to zero */ + memset( ssl->out_ctr + 2, 0, 6 ); + + /* Increment epoch */ + for( i = 2; i > 0; i-- ) + if( ++ssl->out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->out_ctr, 0, 8 ); + + ssl->transform_out = ssl->transform_negotiate; + ssl->session_out = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define SSL_MAX_HASH_LEN 36 +#else +#define SSL_MAX_HASH_LEN 12 +#endif + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned int hash_len; + unsigned char buf[SSL_MAX_HASH_LEN]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* There is currently no ciphersuite using another length with TLS 1.2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + hash_len = 36; + else +#endif + hash_len = 12; + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + + if( mbedtls_ssl_safer_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), + buf, hash_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->peer_verify_data, buf, hash_len ); +#endif + + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif + } + else + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + + return( 0 ); +} + +static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) +{ + memset( handshake, 0, sizeof( mbedtls_ssl_handshake_params ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_init( &handshake->fin_md5 ); + mbedtls_sha1_init( &handshake->fin_sha1 ); + mbedtls_md5_starts( &handshake->fin_md5 ); + mbedtls_sha1_starts( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_init( &handshake->fin_sha256 ); + mbedtls_sha256_starts( &handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_init( &handshake->fin_sha512 ); + mbedtls_sha512_starts( &handshake->fin_sha512, 1 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + handshake->update_checksum = ssl_update_checksum_start; + handshake->sig_alg = MBEDTLS_SSL_HASH_SHA1; + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_init( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_init( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_init( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; +#endif +} + +static void ssl_transform_init( mbedtls_ssl_transform *transform ) +{ + memset( transform, 0, sizeof(mbedtls_ssl_transform) ); + + mbedtls_cipher_init( &transform->cipher_ctx_enc ); + mbedtls_cipher_init( &transform->cipher_ctx_dec ); + + mbedtls_md_init( &transform->md_ctx_enc ); + mbedtls_md_init( &transform->md_ctx_dec ); +} + +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ) +{ + memset( session, 0, sizeof(mbedtls_ssl_session) ); +} + +static int ssl_handshake_init( mbedtls_ssl_context *ssl ) +{ + /* Clear old handshake information if present */ + if( ssl->transform_negotiate ) + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + if( ssl->session_negotiate ) + mbedtls_ssl_session_free( ssl->session_negotiate ); + if( ssl->handshake ) + mbedtls_ssl_handshake_free( ssl->handshake ); + + /* + * Either the pointers are now NULL or cleared properly and can be freed. + * Now allocate missing structures. + */ + if( ssl->transform_negotiate == NULL ) + { + ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + } + + if( ssl->session_negotiate == NULL ) + { + ssl->session_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); + } + + if( ssl->handshake == NULL ) + { + ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); + } + + /* All pointers should exist and can be directly freed without issue */ + if( ssl->handshake == NULL || + ssl->transform_negotiate == NULL || + ssl->session_negotiate == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + + ssl->handshake = NULL; + ssl->transform_negotiate = NULL; + ssl->session_negotiate = NULL; + + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Initialize structures */ + mbedtls_ssl_session_init( ssl->session_negotiate ); + ssl_transform_init( ssl->transform_negotiate ); + ssl_handshake_params_init( ssl->handshake ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->handshake->alt_transform_out = ssl->transform_out; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + + ssl_set_timer( ssl, 0 ); + } +#endif + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/* Dummy cookie callbacks for defaults */ +static int ssl_cookie_write_dummy( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) p); + ((void) end); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} + +static int ssl_cookie_check_dummy( void *ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) cookie); + ((void) cookie_len); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +/* + * Initialize an SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) +{ + memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Setup an SSL context + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret; + const size_t len = MBEDTLS_SSL_BUFFER_LEN; + + ssl->conf = conf; + + /* + * Prepare base structures + */ +#if !defined(ESP8266_PLATFORM) + if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL || + ( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); + mbedtls_free( ssl->in_buf ); + ssl->in_buf = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } +#else + if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); + mbedtls_free( ssl->in_buf ); + ssl->in_buf = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + ssl->out_buf = ssl->in_buf; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->out_ctr = ssl->out_buf + 3; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_hdr = ssl->in_buf; + ssl->in_ctr = ssl->in_buf + 3; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + else +#endif + { + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_ctr = ssl->in_buf; + ssl->in_hdr = ssl->in_buf + 8; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + * + * If partial is non-zero, keep data in the input buffer and client ID. + * (Use when a DTLS client reconnects from the same port.) + */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) +{ + int ret; + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + + /* Cancel any possibly running timer */ + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status = MBEDTLS_SSL_INITIAL_HANDSHAKE; + ssl->renego_records_seen = 0; + + ssl->verify_data_len = 0; + memset( ssl->own_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); + memset( ssl->peer_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; + + ssl->in_offt = NULL; + + ssl->in_msg = ssl->in_buf + 13; + ssl->in_msgtype = 0; + ssl->in_msglen = 0; + if( partial == 0 ) + ssl->in_left = 0; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + ssl->next_record_offset = 0; + ssl->in_epoch = 0; +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + ssl->in_hslen = 0; + ssl->nb_zero = 0; + ssl->record_read = 0; + + ssl->out_msg = ssl->out_buf + 13; + ssl->out_msgtype = 0; + ssl->out_msglen = 0; + ssl->out_left = 0; +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + if( ssl->split_done != MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ) + ssl->split_done = 0; +#endif + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + if( partial == 0 ) + memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_reset != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_reset()" ) ); + if( ( ret = mbedtls_ssl_hw_record_reset( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_reset", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + ssl->transform = NULL; + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + ssl->session = NULL; + } + +#if defined(MBEDTLS_SSL_ALPN) + ssl->alpn_chosen = NULL; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + if( partial == 0 ) + { + mbedtls_free( ssl->cli_id ); + ssl->cli_id = NULL; + ssl->cli_id_len = 0; + } +#endif + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ) +{ + return( ssl_session_reset_int( ssl, 0 ) ); +} + +/* + * SSL set accessors + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ) +{ + conf->endpoint = endpoint; +} + +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ) +{ + conf->transport = transport; +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ) +{ + conf->anti_replay = mode; +} +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ) +{ + conf->badmac_limit = limit; +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ) +{ + conf->hs_timeout_min = min; + conf->hs_timeout_max = max; +} +#endif + +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ) +{ + conf->authmode = authmode; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + conf->f_vrfy = f_vrfy; + conf->p_vrfy = p_vrfy; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + conf->f_rng = f_rng; + conf->p_rng = p_rng; +} + +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ) +{ + conf->f_dbg = f_dbg; + conf->p_dbg = p_dbg; +} + +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + int (*f_send)(void *, const unsigned char *, size_t), + int (*f_recv)(void *, unsigned char *, size_t), + int (*f_recv_timeout)(void *, unsigned char *, size_t, uint32_t) ) +{ + ssl->p_bio = p_bio; + ssl->f_send = f_send; + ssl->f_recv = f_recv; + ssl->f_recv_timeout = f_recv_timeout; +} + +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ) +{ + conf->read_timeout = timeout; +} + +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + void (*f_set_timer)(void *, uint32_t int_ms, uint32_t fin_ms), + int (*f_get_timer)(void *) ) +{ + ssl->p_timer = p_timer; + ssl->f_set_timer = f_set_timer; + ssl->f_get_timer = f_get_timer; + + /* Make sure we start with no timer running */ + ssl_set_timer( ssl, 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ) +{ + conf->p_cache = p_cache; + conf->f_get_cache = f_get_cache; + conf->f_set_cache = f_set_cache; +} +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) +{ + int ret; + + if( ssl == NULL || + session == NULL || + ssl->session_negotiate == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 ) + return( ret ); + + ssl->handshake->resume = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ) +{ + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = ciphersuites; +} + +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ) +{ + if( major != MBEDTLS_SSL_MAJOR_VERSION_3 ) + return; + + if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + conf->ciphersuite_list[minor] = ciphersuites; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ) +{ + conf->cert_profile = profile; +} + +/* Append a new keycert entry to a (possibly empty) list */ +static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, + mbedtls_x509_crt *cert, + mbedtls_pk_context *key ) +{ + mbedtls_ssl_key_cert *new; + + new = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + if( new == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + new->cert = cert; + new->key = key; + new->next = NULL; + + /* Update head is the list was null, else add to the end */ + if( *head == NULL ) + { + *head = new; + } + else + { + mbedtls_ssl_key_cert *cur = *head; + while( cur->next != NULL ) + cur = cur->next; + cur->next = new; + } + + return( 0 ); +} + +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &conf->key_cert, own_cert, pk_key ) ); +} + +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + conf->ca_chain = ca_chain; + conf->ca_crl = ca_crl; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &ssl->handshake->sni_key_cert, + own_cert, pk_key ) ); +} + +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + ssl->handshake->sni_ca_chain = ca_chain; + ssl->handshake->sni_ca_crl = ca_crl; +} + +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ) +{ + ssl->handshake->sni_authmode = authmode; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/* + * Set EC J-PAKE password for current handshake + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ) +{ + mbedtls_ecjpake_role role; + + if( ssl->handshake == NULL && ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + role = MBEDTLS_ECJPAKE_SERVER; + else + role = MBEDTLS_ECJPAKE_CLIENT; + + return( mbedtls_ecjpake_setup( &ssl->handshake->ecjpake_ctx, + role, + MBEDTLS_MD_SHA256, + MBEDTLS_ECP_DP_SECP256R1, + pw, pw_len ) ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ) +{ + if( psk == NULL || psk_identity == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* Identity len will be encoded on two bytes */ + if( ( psk_identity_len >> 16 ) != 0 || + psk_identity_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( conf->psk != NULL || conf->psk_identity != NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + } + + if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL || + ( conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ) ) == NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + conf->psk_len = psk_len; + conf->psk_identity_len = psk_identity_len; + + memcpy( conf->psk, psk, conf->psk_len ); + memcpy( conf->psk_identity, psk_identity, conf->psk_identity_len ); + + return( 0 ); +} + +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ) +{ + if( psk == NULL || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->handshake->psk != NULL ) + mbedtls_free( ssl->handshake->psk ); + + if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ssl->handshake->psk_len = psk_len; + memcpy( ssl->handshake->psk, psk, ssl->handshake->psk_len ); + + return( 0 ); +} + +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ) +{ + conf->f_psk = f_psk; + conf->p_psk = p_psk; +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ) +{ + int ret; + + if( ( ret = mbedtls_mpi_read_string( &conf->dhm_P, 16, dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_read_string( &conf->dhm_G, 16, dhm_G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &conf->dhm_P, &dhm_ctx->P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &conf->dhm_G, &dhm_ctx->G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/* + * Set the minimum length for Diffie-Hellman parameters + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ) +{ + conf->dhm_min_bitlen = bitlen; +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Set allowed/preferred hashes for handshake signatures + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ) +{ + conf->sig_hashes = hashes; +} +#endif + +#if defined(MBEDTLS_ECP_C) +/* + * Set the allowed elliptic curves + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curve_list ) +{ + conf->curve_list = curve_list; +} +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) +{ + size_t hostname_len; + + if( hostname == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + hostname_len = strlen( hostname ); + + if( hostname_len + 1 == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->hostname = mbedtls_calloc( 1, hostname_len + 1 ); + + if( ssl->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->hostname, hostname, hostname_len ); + + ssl->hostname[hostname_len] = '\0'; + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, + const unsigned char *, size_t), + void *p_sni ) +{ + conf->f_sni = f_sni; + conf->p_sni = p_sni; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_ALPN) +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ) +{ + size_t cur_len, tot_len; + const char **p; + + /* + * "Empty strings MUST NOT be included and byte strings MUST NOT be + * truncated". Check lengths now rather than later. + */ + tot_len = 0; + for( p = protos; *p != NULL; p++ ) + { + cur_len = strlen( *p ); + tot_len += cur_len; + + if( cur_len == 0 || cur_len > 255 || tot_len > 65535 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->alpn_list = protos; + + return( 0 ); +} + +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ) +{ + return( ssl->alpn_chosen ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->max_major_ver = major; + conf->max_minor_ver = minor; +} + +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->min_major_ver = major; + conf->min_minor_ver = minor; +} + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ) +{ + conf->fallback = fallback; +} +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ) +{ + conf->encrypt_then_mac = etm; +} +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ) +{ + conf->extended_ms = ems; +} +#endif + +#if defined(MBEDTLS_ARC4_C) +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ) +{ + conf->arc4_disabled = arc4; +} +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ) +{ + if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID || + mfl_code_to_length[mfl_code] > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->mfl_code = mfl_code; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ) +{ + conf->trunc_hmac = truncate; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ) +{ + conf->cbc_record_splitting = split; +} +#endif + +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ) +{ + conf->allow_legacy_renegotiation = allow_legacy; +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ) +{ + conf->disable_renegotiation = renegotiation; +} + +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ) +{ + conf->renego_max_records = max_records; +} + +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ) +{ + memcpy( conf->renego_period, period, 8 ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) +{ + conf->session_tickets = use_tickets; +} +#endif + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ) +{ + conf->f_ticket_write = f_ticket_write; + conf->f_ticket_parse = f_ticket_parse; + conf->p_ticket = p_ticket; +} +#endif +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ) +{ + conf->f_export_keys = f_export_keys; + conf->p_export_keys = p_export_keys; +} +#endif + +/* + * SSL get accessors + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); +} + +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ) +{ + if( ssl->session != NULL ) + return( ssl->session->verify_result ); + + if( ssl->session_negotiate != NULL ) + return( ssl->session_negotiate->verify_result ); + + return( 0xFFFFFFFF ); +} + +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + + return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite ); +} + +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "DTLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "DTLSv1.2" ); + + default: + return( "unknown (DTLS)" ); + } + } +#endif + + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_0: + return( "SSLv3.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_1: + return( "TLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "TLSv1.1" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "TLSv1.2" ); + + default: + return( "unknown" ); + } +} + +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) +{ + size_t transform_expansion; + const mbedtls_ssl_transform *transform = ssl->transform_out; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->session_out->compression != MBEDTLS_SSL_COMPRESS_NULL ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + if( transform == NULL ) + return( (int) mbedtls_ssl_hdr_len( ssl ) ); + + switch( mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_STREAM: + transform_expansion = transform->minlen; + break; + + case MBEDTLS_MODE_CBC: + transform_expansion = transform->maclen + + mbedtls_cipher_get_block_size( &transform->cipher_ctx_enc ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( (int)( mbedtls_ssl_hdr_len( ssl ) + transform_expansion ) ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) +{ + size_t max_len; + + /* + * Assume mfl_code is correct since it was checked when set + */ + max_len = mfl_code_to_length[ssl->conf->mfl_code]; + + /* + * Check if a smaller max length was negotiated + */ + if( ssl->session_out != NULL && + mfl_code_to_length[ssl->session_out->mfl_code] < max_len ) + { + max_len = mfl_code_to_length[ssl->session_out->mfl_code]; + } + + return max_len; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + + return( ssl->session->peer_cert ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *dst ) +{ + if( ssl == NULL || + dst == NULL || + ssl->session == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ssl_session_copy( dst, ssl->session ) ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +/* + * Perform a single step of the SSL handshake + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ret = mbedtls_ssl_handshake_client_step( ssl ); +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ret = mbedtls_ssl_handshake_server_step( ssl ); +#endif + + return( ret ); +} +void mbedtls_handshake_heap(mbedtls_ssl_context *ssl); + +/* + * Perform the SSL handshake + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); + + while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + //mbedtls_handshake_heap(ssl); + ret = mbedtls_ssl_handshake_step( ssl ); + + if( ret != 0 ) + break; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); + + return( ret ); +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +#if defined(MBEDTLS_SSL_SRV_C) +/* + * Write HelloRequest to request renegotiation on server + */ +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello request" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_C */ + +/* + * Actually renegotiate current connection, triggered by either: + * - any side: calling mbedtls_ssl_renegotiate(), + * - client: receiving a HelloRequest during mbedtls_ssl_read(), + * - server: receiving any handshake message on server during mbedtls_ssl_read() after + * the initial handshake is completed. + * If the handshake doesn't complete due to waiting for I/O, it will continue + * during the next calls to mbedtls_ssl_renegotiate() or mbedtls_ssl_read() respectively. + */ +static int ssl_start_renegotiation( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> renegotiate" ) ); + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and + * the ServerHello will have message_seq = 1" */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->handshake->out_msg_seq = 1; + else + ssl->handshake->in_msg_seq = 1; + } +#endif + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS; + + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= renegotiate" ) ); + + return( 0 ); +} + +/* + * Renegotiate current connection on client, + * or request renegotiation on server + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_SRV_C) + /* On server, just send the request */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + + /* Did we already try/start sending HelloRequest? */ + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + return( ssl_write_hello_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + /* + * On client, either start the renegotiation process or, + * if already in progress, continue the handshake + */ + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ( ret = ssl_start_renegotiation( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + else + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( ret ); +} + +/* + * Check record counters and renegotiate if they're above the limit. + */ +static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) +{ + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER || + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING || + ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED ) + { + return( 0 ); + } + + if( memcmp( ssl->in_ctr, ssl->conf->renego_period, 8 ) <= 0 && + memcmp( ssl->out_ctr, ssl->conf->renego_period, 8 ) <= 0 ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record counter limit reached: renegotiate" ) ); + return( mbedtls_ssl_renegotiate( ssl ) ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Receive application data decrypted from the SSL layer + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret, record_read = 0; + size_t n; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + if( ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } + } +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret == MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ) + { + record_read = 1; + } + else if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + + if( ssl->in_offt == NULL ) + { + /* Start timer if not already running */ + if( ssl->f_get_timer != NULL && + ssl->f_get_timer( ssl->p_timer ) == -1 ) + { + ssl_set_timer( ssl, ssl->conf->read_timeout ); + } + + if( ! record_read ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + + if( ssl->in_msglen == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + /* + * OpenSSL sends empty messages to randomize the IV + */ + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif + + if( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == + MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * SSLv3 does not have a "no_renegotiation" alert + */ + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else + { + /* DTLS clients need to know renego is server-initiated */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + } +#endif + ret = ssl_start_renegotiation( ssl ); + if( ret == MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ) + { + record_read = 1; + } + else if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + + /* If a non-handshake record was read during renego, fallthrough, + * else tell the user they should call mbedtls_ssl_read() again */ + if( ! record_read ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + + if( ssl->conf->renego_max_records >= 0 ) + { + if( ++ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by client" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* Fatal and closure alerts handled by mbedtls_ssl_read_record() */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ignoring non-fatal non-closure alert" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad application data message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->in_offt = ssl->in_msg; + + /* We're going to return something now, cancel timer, + * except if handshake (renegotiation) is in progress */ + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* If we requested renego but received AppData, resend HelloRequest. + * Do it now, after setting in_offt, to avoid taking this branch + * again if ssl_write_hello_request() returns WANT_WRITE */ +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ +#endif + } + + n = ( len < ssl->in_msglen ) + ? len : ssl->in_msglen; + + memcpy( buf, ssl->in_offt, n ); + ssl->in_msglen -= n; + + if( ssl->in_msglen == 0 ) + /* all bytes consumed */ + ssl->in_offt = NULL; + else + /* more data available */ + ssl->in_offt += n; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read" ) ); + + return( (int) n ); +} + +/* + * Send application data to be encrypted by the SSL layer, + * taking care of max fragment length and buffer size + */ +static int ssl_write_real( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + size_t max_len = mbedtls_ssl_get_max_frag_len( ssl ); + + if( len > max_len ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment larger than the (negotiated) " + "maximum fragment length: %d > %d", + len, max_len ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + else +#endif + len = max_len; + } +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + if( ssl->out_left != 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + } + else + { + ssl->out_msglen = len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + memcpy( ssl->out_msg, buf, len ); + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + return( (int) len ); +} + +/* + * Write application data, doing 1/n-1 splitting if necessary. + * + * With non-blocking I/O, ssl_write_real() may return WANT_WRITE, + * then the caller will call us again with the same arguments, so + * remember wether we already did the split or not. + */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +static int ssl_write_split( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; + + if( ssl->conf->cbc_record_splitting == + MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED || + len <= 1 || + ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_1 || + mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ) + != MBEDTLS_MODE_CBC ) + { + return( ssl_write_real( ssl, buf, len ) ); + } + + if( ssl->split_done == 0 ) + { + if( ( ret = ssl_write_real( ssl, buf, 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 1; + } + + if( ( ret = ssl_write_real( ssl, buf + 1, len - 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 0; + + return( ret + 1 ); +} +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +/* + * Write application data (public-facing wrapper) + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write" ) ); + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + ret = ssl_write_split( ssl, buf, len ); +#else + ret = ssl_write_real( ssl, buf, len ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write" ) ); + + return( ret ); +} + +/* + * Notify the peer that the connection is being closed + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_send_alert_message", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( 0 ); +} + +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) +{ + if( transform == NULL ) + return; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + mbedtls_cipher_free( &transform->cipher_ctx_enc ); + mbedtls_cipher_free( &transform->cipher_ctx_dec ); + + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); + + mbedtls_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) +{ + mbedtls_ssl_key_cert *cur = key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) +{ + if( handshake == NULL ) + return; + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_free( &handshake->fin_md5 ); + mbedtls_sha1_free( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_free( &handshake->fin_sha256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_free( &handshake->fin_sha512 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_free( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_free( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_free( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( handshake->ecjpake_cache ); + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + /* explicit void pointer cast for buggy MS compiler */ + mbedtls_free( (void *) handshake->curves ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( handshake->psk != NULL ) + { + mbedtls_zeroize( handshake->psk, handshake->psk_len ); + mbedtls_free( handshake->psk ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /* + * Free only the linked list wrapper, not the keys themselves + * since the belong to the SNI callback + */ + if( handshake->sni_key_cert != NULL ) + { + mbedtls_ssl_key_cert *cur = handshake->sni_key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + mbedtls_free( handshake->verify_cookie ); + mbedtls_free( handshake->hs_msg ); + ssl_flight_free( handshake->flight ); +#endif + + mbedtls_zeroize( handshake, sizeof( mbedtls_ssl_handshake_params ) ); +} + +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) +{ + if( session == NULL ) + return; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( session->peer_cert != NULL ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + } +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( session->ticket ); +#endif + + mbedtls_zeroize( session, sizeof( mbedtls_ssl_session ) ); +} + +/* + * Free an SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> free" ) ); + +#if !defined(ESP8266_PLATFORM) + + if( ssl->out_buf != NULL ) + { + mbedtls_zeroize( ssl->out_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->out_buf ); + } + + if( ssl->in_buf != NULL ) + { + mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->in_buf ); + } +#else + if( ssl->in_buf != NULL ) + { + mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->in_buf ); + } + +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->compress_buf != NULL ) + { + mbedtls_zeroize( ssl->compress_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->compress_buf ); + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + + if( ssl->handshake ) + { + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ssl->hostname != NULL ) + { + mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_free( ssl->hostname ); + } +#endif + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_finish != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_finish()" ) ); + mbedtls_ssl_hw_record_finish( ssl ); + } +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + mbedtls_free( ssl->cli_id ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); + + /* Actually clear after last debug message */ + mbedtls_zeroize( ssl, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Initialze mbedtls_ssl_config + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) +{ + memset( conf, 0, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_default_hashes[] = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + MBEDTLS_MD_NONE +}; +#endif + +static int ssl_preset_suiteb_ciphersuites[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + 0 +}; + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_suiteb_hashes[] = { + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_NONE +}; +#endif + +#if defined(MBEDTLS_ECP_C) +static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { + MBEDTLS_ECP_DP_SECP256R1, + MBEDTLS_ECP_DP_SECP384R1, + MBEDTLS_ECP_DP_NONE +}; +#endif + +/* + * Load default in mbedtls_ssl_config + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ) +{ +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + int ret; +#endif + + /* Use the functions here so that they are covered in tests, + * but otherwise access member directly for efficiency */ + mbedtls_ssl_conf_endpoint( conf, endpoint ); + mbedtls_ssl_conf_transport( conf, transport ); + + /* + * Things that are common to all presets + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + conf->authmode = MBEDTLS_SSL_VERIFY_REQUIRED; +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + conf->session_tickets = MBEDTLS_SSL_SESSION_TICKETS_ENABLED; +#endif + } +#endif + +#if defined(MBEDTLS_ARC4_C) + conf->arc4_disabled = MBEDTLS_SSL_ARC4_DISABLED; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + conf->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + conf->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + conf->cbc_record_splitting = MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + conf->f_cookie_write = ssl_cookie_write_dummy; + conf->f_cookie_check = ssl_cookie_check_dummy; +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + conf->anti_replay = MBEDTLS_SSL_ANTI_REPLAY_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + conf->hs_timeout_min = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN; + conf->hs_timeout_max = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX; +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + conf->renego_max_records = MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT; + memset( conf->renego_period, 0xFF, 7 ); + conf->renego_period[7] = 0x00; +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + if( endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ( ret = mbedtls_ssl_conf_dh_param( conf, + MBEDTLS_DHM_RFC5114_MODP_2048_P, + MBEDTLS_DHM_RFC5114_MODP_2048_G ) ) != 0 ) + { + return( ret ); + } + } +#endif + + /* + * Preset-specific defaults + */ + switch( preset ) + { + /* + * NSA Suite B + */ + case MBEDTLS_SSL_PRESET_SUITEB: + conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + ssl_preset_suiteb_ciphersuites; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_suiteb; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_suiteb_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = ssl_preset_suiteb_curves; +#endif + break; + + /* + * Default + */ + default: + conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_1; /* TLS 1.0 */ + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#endif + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + mbedtls_ssl_list_ciphersuites(); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_default; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_default_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = mbedtls_ecp_grp_id_list(); +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + conf->dhm_min_bitlen = 1024; +#endif + } + + return( 0 ); +} + +/* + * Free mbedtls_ssl_config + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ) +{ +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( conf->psk != NULL ) + { + mbedtls_zeroize( conf->psk, conf->psk_len ); + mbedtls_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk_len = 0; + conf->psk_identity_len = 0; + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + ssl_key_cert_free( conf->key_cert ); +#endif + + mbedtls_zeroize( conf, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_PK_C) && \ + ( defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) ) +/* + * Convert between MBEDTLS_PK_XXX and SSL_SIG_XXX + */ +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ) +{ +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_RSA ) ) + return( MBEDTLS_SSL_SIG_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECDSA ) ) + return( MBEDTLS_SSL_SIG_ECDSA ); +#endif + return( MBEDTLS_SSL_SIG_ANON ); +} + +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ) +{ + switch( sig ) + { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_SSL_SIG_RSA: + return( MBEDTLS_PK_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_SSL_SIG_ECDSA: + return( MBEDTLS_PK_ECDSA ); +#endif + default: + return( MBEDTLS_PK_NONE ); + } +} +#endif /* MBEDTLS_PK_C && ( MBEDTLS_RSA_C || MBEDTLS_ECDSA_C ) */ + +/* + * Convert from MBEDTLS_SSL_HASH_XXX to MBEDTLS_MD_XXX + */ +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ) +{ + switch( hash ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_SSL_HASH_MD5: + return( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_SSL_HASH_SHA1: + return( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_HASH_SHA224: + return( MBEDTLS_MD_SHA224 ); + case MBEDTLS_SSL_HASH_SHA256: + return( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_HASH_SHA384: + return( MBEDTLS_MD_SHA384 ); + case MBEDTLS_SSL_HASH_SHA512: + return( MBEDTLS_MD_SHA512 ); +#endif + default: + return( MBEDTLS_MD_NONE ); + } +} + +/* + * Convert from MBEDTLS_MD_XXX to MBEDTLS_SSL_HASH_XXX + */ +unsigned char mbedtls_ssl_hash_from_md_alg( int md ) +{ + switch( md ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( MBEDTLS_SSL_HASH_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( MBEDTLS_SSL_HASH_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( MBEDTLS_SSL_HASH_SHA224 ); + case MBEDTLS_MD_SHA256: + return( MBEDTLS_SSL_HASH_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( MBEDTLS_SSL_HASH_SHA384 ); + case MBEDTLS_MD_SHA512: + return( MBEDTLS_SSL_HASH_SHA512 ); +#endif + default: + return( MBEDTLS_SSL_HASH_NONE ); + } +} + +#if defined(MBEDTLS_ECP_C) +/* + * Check if a curve proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_group_id *gid; + + if( ssl->conf->curve_list == NULL ) + return( -1 ); + + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + if( *gid == grp_id ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Check if a hash proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ) +{ + const int *cur; + + if( ssl->conf->sig_hashes == NULL ) + return( -1 ); + + for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) + if( *cur == (int) md ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ) +{ + int ret = 0; +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + int usage = 0; +#endif +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + const char *ext_oid; + size_t ext_len; +#endif + +#if !defined(MBEDTLS_X509_CHECK_KEY_USAGE) && \ + !defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + ((void) cert); + ((void) cert_endpoint); + ((void) flags); +#endif + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* Server part of the key exchange */ + switch( ciphersuite->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + usage = MBEDTLS_X509_KU_KEY_ENCIPHERMENT; + break; + + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + break; + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + usage = MBEDTLS_X509_KU_KEY_AGREEMENT; + break; + + /* Don't use default: we want warnings when adding new values */ + case MBEDTLS_KEY_EXCHANGE_NONE: + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECJPAKE: + usage = 0; + } + } + else + { + /* Client auth: we only implement rsa_sign and mbedtls_ecdsa_sign for now */ + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + } + + if( mbedtls_x509_crt_check_key_usage( cert, usage ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE; + ret = -1; + } +#else + ((void) ciphersuite); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + ext_oid = MBEDTLS_OID_SERVER_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); + } + else + { + ext_oid = MBEDTLS_OID_CLIENT_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); + } + + if( mbedtls_x509_crt_check_extended_key_usage( cert, ext_oid, ext_len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; + ret = -1; + } +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + + return( ret ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Convert version numbers to/from wire format + * and, for DTLS, to/from TLS equivalent. + * + * For TLS this is the identity. + * For DTLS, use one complement (v -> 255 - v, and then map as follows: + * 1.0 <-> 3.2 (DTLS 1.0 is based on TLS 1.1) + * 1.x <-> 3.x+1 for x != 0 (DTLS 1.2 based on TLS 1.2) + */ +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( minor == MBEDTLS_SSL_MINOR_VERSION_2 ) + --minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + + ver[0] = (unsigned char)( 255 - ( major - 2 ) ); + ver[1] = (unsigned char)( 255 - ( minor - 1 ) ); + } + else +#else + ((void) transport); +#endif + { + ver[0] = (unsigned char) major; + ver[1] = (unsigned char) minor; + } +} + +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + *major = 255 - ver[0] + 2; + *minor = 255 - ver[1] + 1; + + if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 ) + ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + } + else +#else + ((void) transport); +#endif + { + *major = ver[0]; + *minor = ver[1]; + } +} + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/threading.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/threading.c new file mode 100644 index 0000000000..1b6d9cd445 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/threading.c @@ -0,0 +1,136 @@ +/* + * Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_THREADING_C) + +#include "mbedtls/threading.h" + +#if defined(MBEDTLS_THREADING_PTHREAD) +static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL ) + return; + + mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0; +} + +static void threading_mutex_free_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL ) + return; + + (void) pthread_mutex_destroy( &mutex->mutex ); +} + +static int threading_mutex_lock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_lock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +static int threading_mutex_unlock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_unlock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_init_pthread; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_free_pthread; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_lock_pthread; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_unlock_pthread; + +/* + * With phtreads we can statically initialize mutexes + */ +#define MUTEX_INIT = { PTHREAD_MUTEX_INITIALIZER, 1 } + +#endif /* MBEDTLS_THREADING_PTHREAD */ + +#if defined(MBEDTLS_THREADING_ALT) +static int threading_mutex_fail( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); +} +static void threading_mutex_dummy( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return; +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; + +/* + * Set functions pointers and initialize global mutexes + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ) +{ + mbedtls_mutex_init = mutex_init; + mbedtls_mutex_free = mutex_free; + mbedtls_mutex_lock = mutex_lock; + mbedtls_mutex_unlock = mutex_unlock; + + mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex ); +} + +/* + * Free global mutexes + */ +void mbedtls_threading_free_alt( void ) +{ + mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex ); +} +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * Define global mutexes + */ +#ifndef MUTEX_INIT +#define MUTEX_INIT +#endif +mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; +mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT; + +#endif /* MBEDTLS_THREADING_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/timing.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/timing.c new file mode 100644 index 0000000000..5d8b25b997 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/timing.c @@ -0,0 +1,520 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_TIMING_C) + +#include "mbedtls/timing.h" + +#if !defined(MBEDTLS_TIMING_ALT) + +#ifndef asm +#define asm __asm +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#include +#include + +struct _hr_time +{ + LARGE_INTEGER start; +}; + +#else + +#include +#include +#include +#include +#include + +struct _hr_time +{ + struct timeval start; +}; + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tsc; + __asm rdtsc + __asm mov [tsc], eax + return( tsc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ + +/* some versions of mingw-64 have 32-bit longs even on x84_64 */ +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__i386__) || ( \ + ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __i386__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo | ( hi << 32 ) ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __amd64__ || __x86_64__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tbl, tbu0, tbu1; + + do + { + asm volatile( "mftbu %0" : "=r" (tbu0) ); + asm volatile( "mftb %0" : "=r" (tbl ) ); + asm volatile( "mftbu %0" : "=r" (tbu1) ); + } + while( tbu0 != tbu1 ); + + return( tbl ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __powerpc__ || __ppc__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc64__) + +#if defined(__OpenBSD__) +#warning OpenBSD does not allow access to tick register using software version instead +#else +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); + return( tick ); +} +#endif /* __OpenBSD__ */ +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); + asm volatile( "mov %%g1, %0" : "=r" (tick) ); + return( tick ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc__ && !__sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__alpha__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long cc; + asm volatile( "rpcc %0" : "=r" (cc) ); + return( cc & 0xFFFFFFFF ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __alpha__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__ia64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long itc; + asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); + return( itc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __ia64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ + !defined(EFIX64) && !defined(EFI32) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + LARGE_INTEGER offset; + + QueryPerformanceCounter( &offset ); + + return( (unsigned long)( offset.QuadPart ) ); +} +#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) + +#define HAVE_HARDCLOCK + +static int hardclock_init = 0; +static struct timeval tv_init; + +unsigned long mbedtls_timing_hardclock( void ) +{ + struct timeval tv_cur; + + if( hardclock_init == 0 ) + { + gettimeofday( &tv_init, NULL ); + hardclock_init = 1; + } + + gettimeofday( &tv_cur, NULL ); + return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 + + ( tv_cur.tv_usec - tv_init.tv_usec ) ); +} +#endif /* !HAVE_HARDCLOCK */ + +volatile int mbedtls_timing_alarmed = 0; + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + unsigned long delta; + LARGE_INTEGER offset, hfreq; + struct _hr_time *t = (struct _hr_time *) val; + + QueryPerformanceCounter( &offset ); + QueryPerformanceFrequency( &hfreq ); + + delta = (unsigned long)( ( 1000 * + ( offset.QuadPart - t->start.QuadPart ) ) / + hfreq.QuadPart ); + + if( reset ) + QueryPerformanceCounter( &t->start ); + + return( delta ); +} + +/* It's OK to use a global because alarm() is supposed to be global anyway */ +static DWORD alarmMs; + +static DWORD WINAPI TimerProc( LPVOID TimerContext ) +{ + ((void) TimerContext); + Sleep( alarmMs ); + mbedtls_timing_alarmed = 1; + return( TRUE ); +} + +void mbedtls_set_alarm( int seconds ) +{ + DWORD ThreadId; + + mbedtls_timing_alarmed = 0; + alarmMs = seconds * 1000; + CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); +} + +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + unsigned long delta; + struct timeval offset; + struct _hr_time *t = (struct _hr_time *) val; + + gettimeofday( &offset, NULL ); + + if( reset ) + { + t->start.tv_sec = offset.tv_sec; + t->start.tv_usec = offset.tv_usec; + return( 0 ); + } + + delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 + + ( offset.tv_usec - t->start.tv_usec ) / 1000; + + return( delta ); +} + +static void sighandler( int signum ) +{ + mbedtls_timing_alarmed = 1; + signal( signum, sighandler ); +} + +void mbedtls_set_alarm( int seconds ) +{ + mbedtls_timing_alarmed = 0; + signal( SIGALRM, sighandler ); + alarm( seconds ); +} + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Set delays to watch + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + + ctx->int_ms = int_ms; + ctx->fin_ms = fin_ms; + + if( fin_ms != 0 ) + (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); +} + +/* + * Get number of delays expired + */ +int mbedtls_timing_get_delay( void *data ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + unsigned long elapsed_ms; + + if( ctx->fin_ms == 0 ) + return( -1 ); + + elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + return( 2 ); + + if( elapsed_ms >= ctx->int_ms ) + return( 1 ); + + return( 0 ); +} + +#endif /* !MBEDTLS_TIMING_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Busy-waits for the given number of milliseconds. + * Used for testing mbedtls_timing_hardclock. + */ +static void busy_msleep( unsigned long msec ) +{ + struct mbedtls_timing_hr_time hires; + unsigned long i = 0; /* for busy-waiting */ + volatile unsigned long j; /* to prevent optimisation */ + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) + i++; + + j = i; + (void) j; +} + +#define FAIL do \ +{ \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + \ + return( 1 ); \ +} while( 0 ) + +/* + * Checkup routine + * + * Warning: this is work in progress, some tests may not be reliable enough + * yet! False positives may happen. + */ +int mbedtls_timing_self_test( int verbose ) +{ + unsigned long cycles, ratio; + unsigned long millisecs, secs; + int hardfail; + struct mbedtls_timing_hr_time hires; + uint32_t a, b; + mbedtls_timing_delay_context ctx; + + if( verbose != 0 ) + mbedtls_printf( " TIMING tests note: will take some time!\n" ); + + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); + + for( secs = 1; secs <= 3; secs++ ) + { + (void) mbedtls_timing_get_timer( &hires, 1 ); + + mbedtls_set_alarm( (int) secs ); + while( !mbedtls_timing_alarmed ) + ; + + millisecs = mbedtls_timing_get_timer( &hires, 0 ); + + /* For some reason on Windows it looks like alarm has an extra delay + * (maybe related to creating a new thread). Allow some room here. */ + if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); + + for( a = 200; a <= 400; a += 200 ) + { + for( b = 200; b <= 400; b += 200 ) + { + mbedtls_timing_set_delay( &ctx, a, a + b ); + + busy_msleep( a - a / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 0 ) + FAIL; + + busy_msleep( a / 4 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b - a / 8 - b / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b / 4 ); + if( mbedtls_timing_get_delay( &ctx ) != 2 ) + FAIL; + } + } + + mbedtls_timing_set_delay( &ctx, 0, 0 ); + busy_msleep( 200 ); + if( mbedtls_timing_get_delay( &ctx ) != -1 ) + FAIL; + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); + + /* + * Allow one failure for possible counter wrapping. + * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; + * since the whole test is about 10ms, it shouldn't happen twice in a row. + */ + hardfail = 0; + +hard_test: + if( hardfail > 1 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (ignored)\n" ); + + goto hard_test_done; + } + + /* Get a reference ratio cycles/ms */ + millisecs = 1; + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + ratio = cycles / millisecs; + + /* Check that the ratio is mostly constant */ + for( millisecs = 2; millisecs <= 4; millisecs++ ) + { + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + + /* Allow variation up to 20% */ + if( cycles / millisecs < ratio - ratio / 5 || + cycles / millisecs > ratio + ratio / 5 ) + { + hardfail++; + goto hard_test; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +hard_test_done: + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_TIMING_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version.c new file mode 100644 index 0000000000..6ca80d4695 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version.c @@ -0,0 +1,50 @@ +/* + * Version information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" +#include + +unsigned int mbedtls_version_get_number() +{ + return( MBEDTLS_VERSION_NUMBER ); +} + +void mbedtls_version_get_string( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING, + sizeof( MBEDTLS_VERSION_STRING ) ); +} + +void mbedtls_version_get_string_full( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING_FULL, + sizeof( MBEDTLS_VERSION_STRING_FULL ) ); +} + +#endif /* MBEDTLS_VERSION_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version_features.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version_features.c new file mode 100644 index 0000000000..1575e093e3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/version_features.c @@ -0,0 +1,635 @@ +/* + * Version feature information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" + +#include + +static const char *features[] = { +#if defined(MBEDTLS_VERSION_FEATURES) +#if defined(MBEDTLS_HAVE_ASM) + "MBEDTLS_HAVE_ASM", +#endif /* MBEDTLS_HAVE_ASM */ +#if defined(MBEDTLS_HAVE_SSE2) + "MBEDTLS_HAVE_SSE2", +#endif /* MBEDTLS_HAVE_SSE2 */ +#if defined(MBEDTLS_HAVE_TIME) + "MBEDTLS_HAVE_TIME", +#endif /* MBEDTLS_HAVE_TIME */ +#if defined(MBEDTLS_HAVE_TIME_DATE) + "MBEDTLS_HAVE_TIME_DATE", +#endif /* MBEDTLS_HAVE_TIME_DATE */ +#if defined(MBEDTLS_PLATFORM_MEMORY) + "MBEDTLS_PLATFORM_MEMORY", +#endif /* MBEDTLS_PLATFORM_MEMORY */ +#if defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) + "MBEDTLS_PLATFORM_NO_STD_FUNCTIONS", +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) + "MBEDTLS_PLATFORM_EXIT_ALT", +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) + "MBEDTLS_PLATFORM_FPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) + "MBEDTLS_PLATFORM_PRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) + "MBEDTLS_PLATFORM_SNPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_DEPRECATED_WARNING) + "MBEDTLS_DEPRECATED_WARNING", +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#if defined(MBEDTLS_DEPRECATED_REMOVED) + "MBEDTLS_DEPRECATED_REMOVED", +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_TIMING_ALT) + "MBEDTLS_TIMING_ALT", +#endif /* MBEDTLS_TIMING_ALT */ +#if defined(MBEDTLS_AES_ALT) + "MBEDTLS_AES_ALT", +#endif /* MBEDTLS_AES_ALT */ +#if defined(MBEDTLS_ARC4_ALT) + "MBEDTLS_ARC4_ALT", +#endif /* MBEDTLS_ARC4_ALT */ +#if defined(MBEDTLS_BLOWFISH_ALT) + "MBEDTLS_BLOWFISH_ALT", +#endif /* MBEDTLS_BLOWFISH_ALT */ +#if defined(MBEDTLS_CAMELLIA_ALT) + "MBEDTLS_CAMELLIA_ALT", +#endif /* MBEDTLS_CAMELLIA_ALT */ +#if defined(MBEDTLS_DES_ALT) + "MBEDTLS_DES_ALT", +#endif /* MBEDTLS_DES_ALT */ +#if defined(MBEDTLS_XTEA_ALT) + "MBEDTLS_XTEA_ALT", +#endif /* MBEDTLS_XTEA_ALT */ +#if defined(MBEDTLS_MD2_ALT) + "MBEDTLS_MD2_ALT", +#endif /* MBEDTLS_MD2_ALT */ +#if defined(MBEDTLS_MD4_ALT) + "MBEDTLS_MD4_ALT", +#endif /* MBEDTLS_MD4_ALT */ +#if defined(MBEDTLS_MD5_ALT) + "MBEDTLS_MD5_ALT", +#endif /* MBEDTLS_MD5_ALT */ +#if defined(MBEDTLS_RIPEMD160_ALT) + "MBEDTLS_RIPEMD160_ALT", +#endif /* MBEDTLS_RIPEMD160_ALT */ +#if defined(MBEDTLS_SHA1_ALT) + "MBEDTLS_SHA1_ALT", +#endif /* MBEDTLS_SHA1_ALT */ +#if defined(MBEDTLS_SHA256_ALT) + "MBEDTLS_SHA256_ALT", +#endif /* MBEDTLS_SHA256_ALT */ +#if defined(MBEDTLS_SHA512_ALT) + "MBEDTLS_SHA512_ALT", +#endif /* MBEDTLS_SHA512_ALT */ +#if defined(MBEDTLS_MD2_PROCESS_ALT) + "MBEDTLS_MD2_PROCESS_ALT", +#endif /* MBEDTLS_MD2_PROCESS_ALT */ +#if defined(MBEDTLS_MD4_PROCESS_ALT) + "MBEDTLS_MD4_PROCESS_ALT", +#endif /* MBEDTLS_MD4_PROCESS_ALT */ +#if defined(MBEDTLS_MD5_PROCESS_ALT) + "MBEDTLS_MD5_PROCESS_ALT", +#endif /* MBEDTLS_MD5_PROCESS_ALT */ +#if defined(MBEDTLS_RIPEMD160_PROCESS_ALT) + "MBEDTLS_RIPEMD160_PROCESS_ALT", +#endif /* MBEDTLS_RIPEMD160_PROCESS_ALT */ +#if defined(MBEDTLS_SHA1_PROCESS_ALT) + "MBEDTLS_SHA1_PROCESS_ALT", +#endif /* MBEDTLS_SHA1_PROCESS_ALT */ +#if defined(MBEDTLS_SHA256_PROCESS_ALT) + "MBEDTLS_SHA256_PROCESS_ALT", +#endif /* MBEDTLS_SHA256_PROCESS_ALT */ +#if defined(MBEDTLS_SHA512_PROCESS_ALT) + "MBEDTLS_SHA512_PROCESS_ALT", +#endif /* MBEDTLS_SHA512_PROCESS_ALT */ +#if defined(MBEDTLS_DES_SETKEY_ALT) + "MBEDTLS_DES_SETKEY_ALT", +#endif /* MBEDTLS_DES_SETKEY_ALT */ +#if defined(MBEDTLS_DES_CRYPT_ECB_ALT) + "MBEDTLS_DES_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_DES3_CRYPT_ECB_ALT) + "MBEDTLS_DES3_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES3_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) + "MBEDTLS_AES_SETKEY_ENC_ALT", +#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */ +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) + "MBEDTLS_AES_SETKEY_DEC_ALT", +#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */ +#if defined(MBEDTLS_AES_ENCRYPT_ALT) + "MBEDTLS_AES_ENCRYPT_ALT", +#endif /* MBEDTLS_AES_ENCRYPT_ALT */ +#if defined(MBEDTLS_AES_DECRYPT_ALT) + "MBEDTLS_AES_DECRYPT_ALT", +#endif /* MBEDTLS_AES_DECRYPT_ALT */ +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + "MBEDTLS_ENTROPY_HARDWARE_ALT", +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#if defined(MBEDTLS_AES_ROM_TABLES) + "MBEDTLS_AES_ROM_TABLES", +#endif /* MBEDTLS_AES_ROM_TABLES */ +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + "MBEDTLS_CAMELLIA_SMALL_MEMORY", +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + "MBEDTLS_CIPHER_MODE_CBC", +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CIPHER_MODE_CFB) + "MBEDTLS_CIPHER_MODE_CFB", +#endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_CTR) + "MBEDTLS_CIPHER_MODE_CTR", +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + "MBEDTLS_CIPHER_NULL_CIPHER", +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + "MBEDTLS_CIPHER_PADDING_PKCS7", +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + "MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + "MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + "MBEDTLS_CIPHER_PADDING_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) + "MBEDTLS_ENABLE_WEAK_CIPHERSUITES", +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + "MBEDTLS_REMOVE_ARC4_CIPHERSUITES", +#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + "MBEDTLS_ECP_DP_SECP192R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + "MBEDTLS_ECP_DP_SECP224R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + "MBEDTLS_ECP_DP_SECP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + "MBEDTLS_ECP_DP_SECP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + "MBEDTLS_ECP_DP_SECP521R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + "MBEDTLS_ECP_DP_SECP192K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + "MBEDTLS_ECP_DP_SECP224K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + "MBEDTLS_ECP_DP_SECP256K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + "MBEDTLS_ECP_DP_BP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + "MBEDTLS_ECP_DP_BP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + "MBEDTLS_ECP_DP_BP512R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + "MBEDTLS_ECP_DP_CURVE25519_ENABLED", +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_NIST_OPTIM) + "MBEDTLS_ECP_NIST_OPTIM", +#endif /* MBEDTLS_ECP_NIST_OPTIM */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + "MBEDTLS_ECDSA_DETERMINISTIC", +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + "MBEDTLS_PK_PARSE_EC_EXTENDED", +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + "MBEDTLS_ERROR_STRERROR_DUMMY", +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ +#if defined(MBEDTLS_GENPRIME) + "MBEDTLS_GENPRIME", +#endif /* MBEDTLS_GENPRIME */ +#if defined(MBEDTLS_FS_IO) + "MBEDTLS_FS_IO", +#endif /* MBEDTLS_FS_IO */ +#if defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) + "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES", +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +#if defined(MBEDTLS_NO_PLATFORM_ENTROPY) + "MBEDTLS_NO_PLATFORM_ENTROPY", +#endif /* MBEDTLS_NO_PLATFORM_ENTROPY */ +#if defined(MBEDTLS_ENTROPY_FORCE_SHA256) + "MBEDTLS_ENTROPY_FORCE_SHA256", +#endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */ +#if defined(MBEDTLS_MEMORY_DEBUG) + "MBEDTLS_MEMORY_DEBUG", +#endif /* MBEDTLS_MEMORY_DEBUG */ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + "MBEDTLS_MEMORY_BACKTRACE", +#endif /* MBEDTLS_MEMORY_BACKTRACE */ +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) + "MBEDTLS_PK_RSA_ALT_SUPPORT", +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ +#if defined(MBEDTLS_PKCS1_V15) + "MBEDTLS_PKCS1_V15", +#endif /* MBEDTLS_PKCS1_V15 */ +#if defined(MBEDTLS_PKCS1_V21) + "MBEDTLS_PKCS1_V21", +#endif /* MBEDTLS_PKCS1_V21 */ +#if defined(MBEDTLS_RSA_NO_CRT) + "MBEDTLS_RSA_NO_CRT", +#endif /* MBEDTLS_RSA_NO_CRT */ +#if defined(MBEDTLS_SELF_TEST) + "MBEDTLS_SELF_TEST", +#endif /* MBEDTLS_SELF_TEST */ +#if defined(MBEDTLS_SHA256_SMALLER) + "MBEDTLS_SHA256_SMALLER", +#endif /* MBEDTLS_SHA256_SMALLER */ +#if defined(MBEDTLS_SSL_AEAD_RANDOM_IV) + "MBEDTLS_SSL_AEAD_RANDOM_IV", +#endif /* MBEDTLS_SSL_AEAD_RANDOM_IV */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + "MBEDTLS_SSL_ALL_ALERT_MESSAGES", +#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ +#if defined(MBEDTLS_SSL_DEBUG_ALL) + "MBEDTLS_SSL_DEBUG_ALL", +#endif /* MBEDTLS_SSL_DEBUG_ALL */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + "MBEDTLS_SSL_ENCRYPT_THEN_MAC", +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + "MBEDTLS_SSL_EXTENDED_MASTER_SECRET", +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + "MBEDTLS_SSL_FALLBACK_SCSV", +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + "MBEDTLS_SSL_HW_RECORD_ACCEL", +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + "MBEDTLS_SSL_CBC_RECORD_SPLITTING", +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + "MBEDTLS_SSL_RENEGOTIATION", +#endif /* MBEDTLS_SSL_RENEGOTIATION */ +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) + "MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO", +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + "MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE", +#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */ +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + "MBEDTLS_SSL_PROTO_SSL3", +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) + "MBEDTLS_SSL_PROTO_TLS1", +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) + "MBEDTLS_SSL_PROTO_TLS1_1", +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + "MBEDTLS_SSL_PROTO_TLS1_2", +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + "MBEDTLS_SSL_PROTO_DTLS", +#endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if defined(MBEDTLS_SSL_ALPN) + "MBEDTLS_SSL_ALPN", +#endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + "MBEDTLS_SSL_DTLS_ANTI_REPLAY", +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + "MBEDTLS_SSL_DTLS_HELLO_VERIFY", +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) + "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE", +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE */ +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + "MBEDTLS_SSL_SESSION_TICKETS", +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + "MBEDTLS_SSL_EXPORT_KEYS", +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + "MBEDTLS_SSL_SERVER_NAME_INDICATION", +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + "MBEDTLS_SSL_TRUNCATED_HMAC", +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ +#if defined(MBEDTLS_THREADING_ALT) + "MBEDTLS_THREADING_ALT", +#endif /* MBEDTLS_THREADING_ALT */ +#if defined(MBEDTLS_THREADING_PTHREAD) + "MBEDTLS_THREADING_PTHREAD", +#endif /* MBEDTLS_THREADING_PTHREAD */ +#if defined(MBEDTLS_VERSION_FEATURES) + "MBEDTLS_VERSION_FEATURES", +#endif /* MBEDTLS_VERSION_FEATURES */ +#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", +#endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */ +#if defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + "MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION", +#endif /* MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + "MBEDTLS_X509_CHECK_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + "MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + "MBEDTLS_X509_RSASSA_PSS_SUPPORT", +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + "MBEDTLS_ZLIB_SUPPORT", +#endif /* MBEDTLS_ZLIB_SUPPORT */ +#if defined(MBEDTLS_AESNI_C) + "MBEDTLS_AESNI_C", +#endif /* MBEDTLS_AESNI_C */ +#if defined(MBEDTLS_AES_C) + "MBEDTLS_AES_C", +#endif /* MBEDTLS_AES_C */ +#if defined(MBEDTLS_ARC4_C) + "MBEDTLS_ARC4_C", +#endif /* MBEDTLS_ARC4_C */ +#if defined(MBEDTLS_ASN1_PARSE_C) + "MBEDTLS_ASN1_PARSE_C", +#endif /* MBEDTLS_ASN1_PARSE_C */ +#if defined(MBEDTLS_ASN1_WRITE_C) + "MBEDTLS_ASN1_WRITE_C", +#endif /* MBEDTLS_ASN1_WRITE_C */ +#if defined(MBEDTLS_BASE64_C) + "MBEDTLS_BASE64_C", +#endif /* MBEDTLS_BASE64_C */ +#if defined(MBEDTLS_BIGNUM_C) + "MBEDTLS_BIGNUM_C", +#endif /* MBEDTLS_BIGNUM_C */ +#if defined(MBEDTLS_BLOWFISH_C) + "MBEDTLS_BLOWFISH_C", +#endif /* MBEDTLS_BLOWFISH_C */ +#if defined(MBEDTLS_CAMELLIA_C) + "MBEDTLS_CAMELLIA_C", +#endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_CCM_C) + "MBEDTLS_CCM_C", +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CERTS_C) + "MBEDTLS_CERTS_C", +#endif /* MBEDTLS_CERTS_C */ +#if defined(MBEDTLS_CIPHER_C) + "MBEDTLS_CIPHER_C", +#endif /* MBEDTLS_CIPHER_C */ +#if defined(MBEDTLS_CTR_DRBG_C) + "MBEDTLS_CTR_DRBG_C", +#endif /* MBEDTLS_CTR_DRBG_C */ +#if defined(MBEDTLS_DEBUG_C) + "MBEDTLS_DEBUG_C", +#endif /* MBEDTLS_DEBUG_C */ +#if defined(MBEDTLS_DES_C) + "MBEDTLS_DES_C", +#endif /* MBEDTLS_DES_C */ +#if defined(MBEDTLS_DHM_C) + "MBEDTLS_DHM_C", +#endif /* MBEDTLS_DHM_C */ +#if defined(MBEDTLS_ECDH_C) + "MBEDTLS_ECDH_C", +#endif /* MBEDTLS_ECDH_C */ +#if defined(MBEDTLS_ECDSA_C) + "MBEDTLS_ECDSA_C", +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_ECJPAKE_C) + "MBEDTLS_ECJPAKE_C", +#endif /* MBEDTLS_ECJPAKE_C */ +#if defined(MBEDTLS_ECP_C) + "MBEDTLS_ECP_C", +#endif /* MBEDTLS_ECP_C */ +#if defined(MBEDTLS_ENTROPY_C) + "MBEDTLS_ENTROPY_C", +#endif /* MBEDTLS_ENTROPY_C */ +#if defined(MBEDTLS_ERROR_C) + "MBEDTLS_ERROR_C", +#endif /* MBEDTLS_ERROR_C */ +#if defined(MBEDTLS_GCM_C) + "MBEDTLS_GCM_C", +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_HAVEGE_C) + "MBEDTLS_HAVEGE_C", +#endif /* MBEDTLS_HAVEGE_C */ +#if defined(MBEDTLS_HMAC_DRBG_C) + "MBEDTLS_HMAC_DRBG_C", +#endif /* MBEDTLS_HMAC_DRBG_C */ +#if defined(MBEDTLS_MD_C) + "MBEDTLS_MD_C", +#endif /* MBEDTLS_MD_C */ +#if defined(MBEDTLS_MD2_C) + "MBEDTLS_MD2_C", +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + "MBEDTLS_MD4_C", +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + "MBEDTLS_MD5_C", +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) + "MBEDTLS_MEMORY_BUFFER_ALLOC_C", +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ +#if defined(MBEDTLS_NET_C) + "MBEDTLS_NET_C", +#endif /* MBEDTLS_NET_C */ +#if defined(MBEDTLS_OID_C) + "MBEDTLS_OID_C", +#endif /* MBEDTLS_OID_C */ +#if defined(MBEDTLS_PADLOCK_C) + "MBEDTLS_PADLOCK_C", +#endif /* MBEDTLS_PADLOCK_C */ +#if defined(MBEDTLS_PEM_PARSE_C) + "MBEDTLS_PEM_PARSE_C", +#endif /* MBEDTLS_PEM_PARSE_C */ +#if defined(MBEDTLS_PEM_WRITE_C) + "MBEDTLS_PEM_WRITE_C", +#endif /* MBEDTLS_PEM_WRITE_C */ +#if defined(MBEDTLS_PK_C) + "MBEDTLS_PK_C", +#endif /* MBEDTLS_PK_C */ +#if defined(MBEDTLS_PK_PARSE_C) + "MBEDTLS_PK_PARSE_C", +#endif /* MBEDTLS_PK_PARSE_C */ +#if defined(MBEDTLS_PK_WRITE_C) + "MBEDTLS_PK_WRITE_C", +#endif /* MBEDTLS_PK_WRITE_C */ +#if defined(MBEDTLS_PKCS5_C) + "MBEDTLS_PKCS5_C", +#endif /* MBEDTLS_PKCS5_C */ +#if defined(MBEDTLS_PKCS11_C) + "MBEDTLS_PKCS11_C", +#endif /* MBEDTLS_PKCS11_C */ +#if defined(MBEDTLS_PKCS12_C) + "MBEDTLS_PKCS12_C", +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PLATFORM_C) + "MBEDTLS_PLATFORM_C", +#endif /* MBEDTLS_PLATFORM_C */ +#if defined(MBEDTLS_RIPEMD160_C) + "MBEDTLS_RIPEMD160_C", +#endif /* MBEDTLS_RIPEMD160_C */ +#if defined(MBEDTLS_RSA_C) + "MBEDTLS_RSA_C", +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_SHA1_C) + "MBEDTLS_SHA1_C", +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + "MBEDTLS_SHA256_C", +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + "MBEDTLS_SHA512_C", +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SSL_CACHE_C) + "MBEDTLS_SSL_CACHE_C", +#endif /* MBEDTLS_SSL_CACHE_C */ +#if defined(MBEDTLS_SSL_COOKIE_C) + "MBEDTLS_SSL_COOKIE_C", +#endif /* MBEDTLS_SSL_COOKIE_C */ +#if defined(MBEDTLS_SSL_TICKET_C) + "MBEDTLS_SSL_TICKET_C", +#endif /* MBEDTLS_SSL_TICKET_C */ +#if defined(MBEDTLS_SSL_CLI_C) + "MBEDTLS_SSL_CLI_C", +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + "MBEDTLS_SSL_SRV_C", +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_TLS_C) + "MBEDTLS_SSL_TLS_C", +#endif /* MBEDTLS_SSL_TLS_C */ +#if defined(MBEDTLS_THREADING_C) + "MBEDTLS_THREADING_C", +#endif /* MBEDTLS_THREADING_C */ +#if defined(MBEDTLS_TIMING_C) + "MBEDTLS_TIMING_C", +#endif /* MBEDTLS_TIMING_C */ +#if defined(MBEDTLS_VERSION_C) + "MBEDTLS_VERSION_C", +#endif /* MBEDTLS_VERSION_C */ +#if defined(MBEDTLS_X509_USE_C) + "MBEDTLS_X509_USE_C", +#endif /* MBEDTLS_X509_USE_C */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + "MBEDTLS_X509_CRT_PARSE_C", +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_X509_CRL_PARSE_C) + "MBEDTLS_X509_CRL_PARSE_C", +#endif /* MBEDTLS_X509_CRL_PARSE_C */ +#if defined(MBEDTLS_X509_CSR_PARSE_C) + "MBEDTLS_X509_CSR_PARSE_C", +#endif /* MBEDTLS_X509_CSR_PARSE_C */ +#if defined(MBEDTLS_X509_CREATE_C) + "MBEDTLS_X509_CREATE_C", +#endif /* MBEDTLS_X509_CREATE_C */ +#if defined(MBEDTLS_X509_CRT_WRITE_C) + "MBEDTLS_X509_CRT_WRITE_C", +#endif /* MBEDTLS_X509_CRT_WRITE_C */ +#if defined(MBEDTLS_X509_CSR_WRITE_C) + "MBEDTLS_X509_CSR_WRITE_C", +#endif /* MBEDTLS_X509_CSR_WRITE_C */ +#if defined(MBEDTLS_XTEA_C) + "MBEDTLS_XTEA_C", +#endif /* MBEDTLS_XTEA_C */ +#endif /* MBEDTLS_VERSION_FEATURES */ + NULL +}; + +int mbedtls_version_check_feature( const char *feature ) +{ + const char **idx = features; + + if( *idx == NULL ) + return( -2 ); + + if( feature == NULL ) + return( -1 ); + + while( *idx != NULL ) + { + if( !strcmp( *idx, feature ) ) + return( 0 ); + idx++; + } + return( -1 ); +} + +#endif /* MBEDTLS_VERSION_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509.c new file mode 100644 index 0000000000..ffc3d6c94b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509.c @@ -0,0 +1,1024 @@ +/* + * X.509 common functions for parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_USE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_printf printf +#define mbedtls_snprintf snprintf +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) +#include +#include +#include +#endif +#endif + +#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } + +/* + * CertificateSerialNumber ::= INTEGER + */ +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_PRIMITIVE | 2 ) && + **p != MBEDTLS_ASN1_INTEGER ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* Get an algorithm identifier without parameters (eg for signatures) + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +/* + * Parse an algorithm identifier with (optional) paramaters + */ +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, params ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +/* + * HashAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * For HashAlgorithm, parameters MUST be NULL or absent. + */ +static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md_alg ) +{ + int ret; + unsigned char *p; + const unsigned char *end; + mbedtls_x509_buf md_oid; + size_t len; + + /* Make sure we got a SEQUENCE and setup bounds */ + if( alg->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) alg->p; + end = p + alg->len; + + if( p >= end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Parse md_oid */ + md_oid.tag = *p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &md_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + md_oid.p = p; + p += md_oid.len; + + /* Get md_alg from md_oid */ + if( ( ret = mbedtls_oid_get_md_alg( &md_oid, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + /* Make sure params is absent of NULL */ + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_NULL ) ) != 0 || len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 } + * -- Note that the tags in this Sequence are explicit. + * + * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value + * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other + * option. Enfore this at parsing time. + */ +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ) +{ + int ret; + unsigned char *p; + const unsigned char *end, *end2; + size_t len; + mbedtls_x509_buf alg_id, alg_params; + + /* First set everything to defaults */ + *md_alg = MBEDTLS_MD_SHA1; + *mgf_md = MBEDTLS_MD_SHA1; + *salt_len = 20; + + /* Make sure params is a SEQUENCE and setup bounds */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) params->p; + end = p + params->len; + + if( p == end ) + return( 0 ); + + /* + * HashAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + end2 = p + len; + + /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ + if( ( ret = mbedtls_x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * MaskGenAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ + if( ( ret = mbedtls_x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) + return( ret ); + + /* Only MFG1 is recognised for now */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_MGF1, &alg_id ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE + + MBEDTLS_ERR_OID_NOT_FOUND ); + + /* Parse HashAlgorithm */ + if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) + return( ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * salt_len + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, salt_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * trailer_field (if present, must be 1) + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 ) ) == 0 ) + { + int trailer_field; + + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( trailer_field != 1 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t len; + mbedtls_x509_buf *oid; + mbedtls_x509_buf *val; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && + **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && + **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && + **p != MBEDTLS_ASN1_BIT_STRING ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * The data structure is optimized for the common case where each RDN has only + * one element, which is represented as a list of AttributeTypeAndValue. + * For the general case we still use a flat list, but we mark elements of the + * same set so that they are "merged" together in the functions that consume + * this list, eg mbedtls_x509_dn_gets(). + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t set_len; + const unsigned char *end_set; + + /* don't use recursion, we'd risk stack overflow if not optimized */ + while( 1 ) + { + /* + * parse SET + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + end_set = *p + set_len; + + while( 1 ) + { + if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) + return( ret ); + + if( *p == end_set ) + break; + + /* Mark this item as being no the only one in a set */ + cur->next_merged = 1; + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } + + /* + * continue until end of SEQUENCE is reached + */ + if( *p == end ) + return( 0 ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } +} + +static int x509_parse_int(unsigned char **p, unsigned n, int *res){ + *res = 0; + for( ; n > 0; --n ){ + if( ( **p < '0') || ( **p > '9' ) ) return MBEDTLS_ERR_X509_INVALID_DATE; + *res *= 10; + *res += (*(*p)++ - '0'); + } + return 0; +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *time ) +{ + int ret; + size_t len; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if( tag == MBEDTLS_ASN1_UTC_TIME ) + { + (*p)++; + ret = mbedtls_asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + CHECK( x509_parse_int( p, 2, &time->year ) ); + CHECK( x509_parse_int( p, 2, &time->mon ) ); + CHECK( x509_parse_int( p, 2, &time->day ) ); + CHECK( x509_parse_int( p, 2, &time->hour ) ); + CHECK( x509_parse_int( p, 2, &time->min ) ); + if( len > 10 ) + CHECK( x509_parse_int( p, 2, &time->sec ) ); + if( len > 12 && *(*p)++ != 'Z' ) + return( MBEDTLS_ERR_X509_INVALID_DATE ); + + time->year += 100 * ( time->year < 50 ); + time->year += 1900; + + return( 0 ); + } + else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) + { + (*p)++; + ret = mbedtls_asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + CHECK( x509_parse_int( p, 4, &time->year ) ); + CHECK( x509_parse_int( p, 2, &time->mon ) ); + CHECK( x509_parse_int( p, 2, &time->day ) ); + CHECK( x509_parse_int( p, 2, &time->hour ) ); + CHECK( x509_parse_int( p, 2, &time->min ) ); + if( len > 12 ) + CHECK( x509_parse_int( p, 2, &time->sec ) ); + if( len > 14 && *(*p)++ != 'Z' ) + return( MBEDTLS_ERR_X509_INVALID_DATE ); + + return( 0 ); + } + else + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); +} + +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) +{ + int ret; + size_t len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + sig->tag = **p; + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); + + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +/* + * Get signature algorithm from alg OID and optional parameters + */ +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ) +{ + int ret; + + if( *sig_opts != NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( *pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + mbedtls_pk_rsassa_pss_options *pss_opts; + + pss_opts = mbedtls_calloc( 1, sizeof( mbedtls_pk_rsassa_pss_options ) ); + if( pss_opts == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + ret = mbedtls_x509_get_rsassa_pss_params( sig_params, + md_alg, + &pss_opts->mgf1_hash_id, + &pss_opts->expected_salt_len ); + if( ret != 0 ) + { + mbedtls_free( pss_opts ); + return( ret ); + } + + *sig_opts = (void *) pss_opts; + } + else +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + { + /* Make sure parameters are absent or NULL */ + if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || + sig_params->len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed! + */ +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c, merge = 0; + const mbedtls_x509_name *name; + const char *short_name = NULL; + char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = mbedtls_snprintf( p, n, merge ? " + " : ", " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name ); + + if( ret == 0 ) + ret = mbedtls_snprintf( p, n, "%s=", short_name ); + else + ret = mbedtls_snprintf( p, n, "\?\?=" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = mbedtls_snprintf( p, n, "%s", s ); + MBEDTLS_X509_SAFE_SNPRINTF; + + merge = name->next_merged; + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + if( nr != serial->len ) + { + ret = mbedtls_snprintf( p, n, "...." ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +/* + * Helper for writing signature algorithms + */ +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ) +{ + int ret; + char *p = buf; + size_t n = size; + const char *desc = NULL; + + ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); + if( ret != 0 ) + ret = mbedtls_snprintf( p, n, "???" ); + else + ret = mbedtls_snprintf( p, n, "%s", desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_pk_rsassa_pss_options *pss_opts; + const mbedtls_md_info_t *md_info, *mgf_md_info; + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) sig_opts; + + md_info = mbedtls_md_info_from_type( md_alg ); + mgf_md_info = mbedtls_md_info_from_type( pss_opts->mgf1_hash_id ); + + ret = mbedtls_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)", + md_info ? mbedtls_md_get_name( md_info ) : "???", + mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???", + pss_opts->expected_salt_len ); + MBEDTLS_X509_SAFE_SNPRINTF; + } +#else + ((void) pk_alg); + ((void) md_alg); + ((void) sig_opts); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + return( (int)( size - n ) ); +} + +/* + * Helper for writing "RSA key size", "EC key size", etc + */ +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) +{ + char *p = buf; + size_t n = buf_size; + int ret; + + ret = mbedtls_snprintf( p, n, "%s key size", name ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( 0 ); +} + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/* + * Set the time structure to the current time. + * Return 0 on success, non-zero on failure. + */ +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + SYSTEMTIME st; + + GetSystemTime( &st ); + + now->year = st.wYear; + now->mon = st.wMonth; + now->day = st.wDay; + now->hour = st.wHour; + now->min = st.wMinute; + now->sec = st.wSecond; + + return( 0 ); +} +#else +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + struct tm *lt; + time_t tt; + int ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + tt = time( NULL ); + lt = gmtime( &tt ); + + if( lt == NULL ) + ret = -1; + else + { + now->year = lt->tm_year + 1900; + now->mon = lt->tm_mon + 1; + now->day = lt->tm_mday; + now->hour = lt->tm_hour; + now->min = lt->tm_min; + now->sec = lt->tm_sec; + } + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Return 0 if before <= after, 1 otherwise + */ +static int x509_check_time( const mbedtls_x509_time *before, const mbedtls_x509_time *after ) +{ + if( before->year > after->year ) + return( 1 ); + + if( before->year == after->year && + before->mon > after->mon ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day > after->day ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour > after->hour ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min > after->min ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min == after->min && + before->sec > after->sec ) + return( 1 ); + + return( 0 ); +} + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( &now, to ) ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( from, &now ) ); +} + +#else /* MBEDTLS_HAVE_TIME_DATE */ + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + ((void) to); + return( 0 ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + ((void) from); + return( 0 ); +} +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/certs.h" + +/* + * Checkup routine + */ +int mbedtls_x509_self_test( int verbose ) +{ +#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA1_C) + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); + + mbedtls_x509_crt_init( &clicert ); + + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, + mbedtls_test_cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + mbedtls_x509_crt_init( &cacert ); + + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, + mbedtls_test_ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n X.509 signature verify: "); + + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n"); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); + + return( 0 ); +#else + ((void) verbose); + return( 0 ); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_X509_USE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_create.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_create.c new file mode 100644 index 0000000000..823747bc52 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_create.c @@ -0,0 +1,340 @@ +/* + * X.509 base functions for creating certificates / CSRs + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CREATE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +#include "c_types.h" +#include + +typedef struct { + const char *name; + size_t name_len; + const char*oid; +} x509_attr_descriptor_t; + +#define ADD_STRLEN( s ) s, sizeof( s ) - 1 + +static const x509_attr_descriptor_t x509_attrs[] ICACHE_RODATA_ATTR STORE_ATTR = +{ + { ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "C" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "countryName" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "O" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "organizationName" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "L" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "locality" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "R" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "OU" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "organizationalUnitName" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "ST" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "stateOrProvinceName" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "emailAddress" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "serialNumber" ), MBEDTLS_OID_AT_SERIAL_NUMBER }, + { ADD_STRLEN( "postalAddress" ), MBEDTLS_OID_AT_POSTAL_ADDRESS }, + { ADD_STRLEN( "postalCode" ), MBEDTLS_OID_AT_POSTAL_CODE }, + { ADD_STRLEN( "dnQualifier" ), MBEDTLS_OID_AT_DN_QUALIFIER }, + { ADD_STRLEN( "title" ), MBEDTLS_OID_AT_TITLE }, + { ADD_STRLEN( "surName" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "SN" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "givenName" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "GN" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "initials" ), MBEDTLS_OID_AT_INITIALS }, + { ADD_STRLEN( "pseudonym" ), MBEDTLS_OID_AT_PSEUDONYM }, + { ADD_STRLEN( "generationQualifier" ), MBEDTLS_OID_AT_GENERATION_QUALIFIER }, + { ADD_STRLEN( "domainComponent" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { ADD_STRLEN( "DC" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { NULL, 0, NULL } +}; + +static const char *x509_at_oid_from_name( const char *name, size_t name_len ) +{ + const x509_attr_descriptor_t *cur; + + for( cur = x509_attrs; cur->name != NULL; cur++ ) + if( cur->name_len == name_len && + strncmp( cur->name, name, name_len ) == 0 ) + break; + + return( cur->oid ); +} + +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ) +{ + int ret = 0; + const char *s = name, *c = s; + const char *end = s + strlen( s ); + const char *oid = NULL; + int in_tag = 1; + char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; + char *d = data; + + /* Clear existing chain if present */ + mbedtls_asn1_free_named_data_list( head ); + + while( c <= end ) + { + if( in_tag && *c == '=' ) + { + if( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL ) + { + ret = MBEDTLS_ERR_X509_UNKNOWN_OID; + goto exit; + } + + s = c + 1; + in_tag = 0; + d = data; + } + + if( !in_tag && *c == '\\' && c != end ) + { + c++; + + /* Check for valid escaped characters */ + if( c == end || *c != ',' ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + else if( !in_tag && ( *c == ',' || c == end ) ) + { + if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) data, + d - data ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + while( c < end && *(c + 1) == ' ' ) + c++; + + s = c + 1; + in_tag = 1; + } + + if( !in_tag && s != c + 1 ) + { + *(d++) = *c; + + if( d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + + c++; + } + +exit: + + return( ret ); +} + +/* The first byte of the value in the mbedtls_asn1_named_data structure is reserved + * to store the critical boolean for us + */ +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_store_named_data( head, oid, oid_len, + NULL, val_len + 1 ) ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + cur->val.p[0] = critical; + memcpy( cur->val.p + 1, val, val_len ); + + return( 0 ); +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_write_name( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + const unsigned char *name, size_t name_len ) +{ + int ret; + size_t len = 0; + + // Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL + // + if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len && + memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start, + (const char *) name, + name_len ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start, + (const char *) name, + name_len ) ); + } + + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur = first; + + while( cur != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p, + cur->oid.len, + cur->val.p, cur->val.len ) ); + cur = cur->next; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ) +{ + int ret; + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, sig, len ); + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( p, start, oid, + oid_len, 0 ) ); + + return( (int) len ); +} + +static int x509_write_extension( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *ext ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->val.p + 1, + ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + if( ext->val.p[0] != 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( p, start, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->oid.p, + ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +/* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * -- contains the DER encoding of an ASN.1 value + * -- corresponding to the extension type identified + * -- by extnID + * } + */ +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur_ext = first; + + while( cur_ext != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) ); + cur_ext = cur_ext->next; + } + + return( (int) len ); +} + +#endif /* MBEDTLS_X509_CREATE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crl.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crl.c new file mode 100644 index 0000000000..125a77399d --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crl.c @@ -0,0 +1,721 @@ +/* + * X.509 Certidicate Revocation List (CRL) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + +#include "mbedtls/x509_crl.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * X.509 CRL v2 extensions (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* Get explicit tag */ + if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if( end <= *p ) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + mbedtls_x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &entry_len, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len2, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = mbedtls_x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end2, + &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, + &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if( *p < end ) + { + cur_entry->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur_entry = cur_entry->next; + } + } + + return( 0 ); +} + +/* + * Parse one CRLs in DER format and append it to the chained list + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + mbedtls_x509_crl *crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Add new CRL on the end of the chain if needed. + */ + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + if( crl->version != 0 && crl->next == NULL ) + { + crl->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl ) ); + + if( crl->next == NULL ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + mbedtls_x509_crl_init( crl->next ); + crl = crl->next; + } + + /* + * Copy raw DER-encoded CRL + */ + if( ( p = mbedtls_calloc( 1, buflen ) ) == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + crl->raw.p = p; + crl->raw.len = buflen; + + end = p + buflen; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crl->sig_oid, &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->version++; + + if( crl->version > 2 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1, + &crl->sig_md, &crl->sig_pk, + &crl->sig_opts ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if( ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ) ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid.len != sig_oid2.len || + memcmp( crl->sig_oid.p, sig_oid2.p, crl->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; + int is_pem = 0; + + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + do + { + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( buflen == 0 || buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + is_pem = 1; + + buflen -= use_len; + buf += use_len; + + if( ( ret = mbedtls_x509_crl_parse_der( chain, + pem.buf, pem.buflen ) ) != 0 ) + { + return( ret ); + } + + mbedtls_pem_free( &pem ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + } + /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte. + * And a valid CRL cannot be less than 1 byte anyway. */ + while( is_pem && buflen > 1 ); + + if( is_pem ) + return( 0 ); + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_crl_parse_der( chain, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crl_parse( chain, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CRL. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const mbedtls_x509_crl_entry *entry; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crl->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = &crl->entry; + + ret = mbedtls_snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = mbedtls_snprintf( p, n, "\n%sserial number: ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &entry->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = entry->next; + } + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md, + crl->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CRL chain + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ) +{ + memset( crl, 0, sizeof(mbedtls_x509_crl) ); +} + +/* + * Unallocate all CRL data + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) +{ + mbedtls_x509_crl *crl_cur = crl; + mbedtls_x509_crl *crl_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_crl_entry *entry_cur; + mbedtls_x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( crl_cur->sig_opts ); +#endif + + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + mbedtls_zeroize( entry_prv, sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + mbedtls_zeroize( crl_cur->raw.p, crl_cur->raw.len ); + mbedtls_free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + mbedtls_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); + if( crl_prv != crl ) + mbedtls_free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRL_PARSE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crt.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crt.c new file mode 100644 index 0000000000..da657453bb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_crt.c @@ -0,0 +1,2412 @@ +/* + * X.509 certificate parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) +#include +#include +#include +#endif /* !_WIN32 || EFIX64 || EFI32 */ +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default ICACHE_RODATA_ATTR = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ +#if defined(ESP8266_PLATFORM) + 512, +#else + 2048, +#endif +}; + +/* + * Next-default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next ICACHE_RODATA_ATTR = +{ + /* Hashes from SHA-256 and above */ +#if defined(ESP8266_PLATFORM) + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | +#endif + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ +#if defined(MBEDTLS_ECP_C) + /* Curves at or above 128-bit security level */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), +#else + 0, +#endif +#if defined(ESP8266_PLATFORM) + 512, +#else + 2048, +#endif +}; + +/* + * NSA Suite B Profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb ICACHE_RODATA_ATTR = +{ + /* Only SHA-256 and 384 */ +#if defined(ESP8266_PLATFORM) + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | +#endif + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), + /* Only ECDSA */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ), +#if defined(MBEDTLS_ECP_C) + /* Only NIST P-256 and P-384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), +#else + 0, +#endif + 0, +}; + +/* + * Check md_alg against profile + * Return 0 if md_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg ) +{ + if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check pk_alg against profile + * Return 0 if pk_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg ) +{ + if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check key against profile + * Return 0 if pk_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg, + const mbedtls_pk_context *pk ) +{ +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) + return( 0 ); + + return( -1 ); + } +#endif + +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECDSA || + pk_alg == MBEDTLS_PK_ECKEY || + pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + + if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) + return( 0 ); + + return( -1 ); + } +#endif + + return( -1 ); +} + +/* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ +static int x509_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( ret ); + } + + end = *p + len; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + const unsigned char *end, + mbedtls_x509_time *from, + mbedtls_x509_time *to ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + end = *p + len; + + if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) + return( ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v2/v3 unique identifier (not parsed) + */ +static int x509_get_uid( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *uid, int n ) +{ + int ret; + + if( *p == end ) + return( 0 ); + + uid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + uid->p = *p; + *p += uid->len; + + return( 0 ); +} + +static int x509_get_basic_constraints( unsigned char **p, + const unsigned char *end, + int *ca_istrue, + int *max_pathlen ) +{ + int ret; + size_t len; + + /* + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + *ca_istrue = 0; /* DEFAULT FALSE */ + *max_pathlen = 0; /* endless */ + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + ret = mbedtls_asn1_get_int( p, end, ca_istrue ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *ca_istrue != 0 ) + *ca_istrue = 1; + } + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + (*max_pathlen)++; + + return( 0 ); +} + +static int x509_get_ns_cert_type( unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) +{ + int ret; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len != 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return( 0 ); +} + +static int x509_get_key_usage( unsigned char **p, + const unsigned char *end, + unsigned int *key_usage) +{ + int ret; + size_t i; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *key_usage = 0; + for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) + { + *key_usage |= (unsigned int) bs.p[i] << (8*i); + } + + return( 0 ); +} + +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *ext_key_usage) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Sequence length must be >= 1 */ + if( ext_key_usage->buf.p == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + return( 0 ); +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: we only parse and use dNSName at this point. + */ +static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name ) +{ + int ret; + size_t len, tag_len; + mbedtls_asn1_buf *buf; + unsigned char tag; + mbedtls_asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + (*p)++; + if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( tag & MBEDTLS_ASN1_CONTEXT_SPECIFIC ) != MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + { + *p += tag_len; + continue; + } + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v3 extensions + * + * TODO: Perform all of the basic constraints tests required by the RFC + * TODO: Set values for undetected extensions to a sane default? + * + */ +static int x509_get_crt_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crt *crt ) +{ + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; + + if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + mbedtls_x509_buf extn_oid = {0, 0, NULL}; + int is_critical = 0; /* DEFAULT FALSE */ + int ext_type = 0; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get extension ID */ + extn_oid.tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + extn_oid.p = *p; + *p += extn_oid.len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_octet = *p + len; + + if( end_ext_octet != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Detect supported extensions + */ + ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); + + if( ret != 0 ) + { + /* No parser found, skip extension */ + *p = end_ext_octet; + +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { + /* Data is marked as critical: fail */ + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } +#endif + continue; + } + + /* Forbid repeated extensions */ + if( ( crt->ext_types & ext_type ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + crt->ext_types |= ext_type; + + switch( ext_type ) + { + case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: + /* Parse basic constraints */ + if( ( ret = x509_get_basic_constraints( p, end_ext_octet, + &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_KEY_USAGE: + /* Parse key usage */ + if( ( ret = x509_get_key_usage( p, end_ext_octet, + &crt->key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: + /* Parse extended key usage */ + if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: + /* Parse subject alt name */ + if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_NS_CERT_TYPE: + /* Parse netscape certificate type */ + if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, + &crt->ns_cert_type ) ) != 0 ) + return( ret ); + break; + + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Parse and fill a single X.509 certificate in DER format + */ +static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf, + size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end, *crt_end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + p = mbedtls_calloc( 1, len = buflen ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + crt->raw.p = p; + crt->raw.len = len; + end = p + len; + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len > (size_t) ( end - p ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + crt_end = p + len; + + /* + * TBSCertificate ::= SEQUENCE { + */ + crt->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crt->tbs.len = end - crt->tbs.p; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || + ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, + &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->version++; + + if( crt->version > 3 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, + &crt->sig_md, &crt->sig_pk, + &crt->sig_opts ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuer Name + */ + crt->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + */ + if( ( ret = x509_get_dates( &p, end, &crt->valid_from, + &crt->valid_to ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * subject Name + */ + crt->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->subject_raw.len = p - crt->subject_raw.p; + + /* + * SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + +#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + if( crt->version == 3 ) +#endif + { + ret = x509_get_crt_ext( &p, end, crt ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crt_end; + + /* + * } + * -- end of TBSCertificate + * + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->sig_oid.len != sig_oid2.len || + memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one X.509 certificate in DER format from a buffer and add them to a + * chained list + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ) +{ + int ret; + mbedtls_x509_crt *crt = chain, *prev = NULL; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + while( crt->version != 0 && crt->next != NULL ) + { + prev = crt; + crt = crt->next; + } + + /* + * Add new certificate on the end of the chain if needed. + */ + if( crt->version != 0 && crt->next == NULL ) + { + crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( crt->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + prev = crt; + mbedtls_x509_crt_init( crt->next ); + crt = crt->next; + } + + if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + mbedtls_free( crt ); + + return( ret ); + } + + return( 0 ); +} + +/* + * Parse one or more PEM certificates from a buffer and add them to the chained + * list + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ) +{ + int success = 0, first_error = 0, total_failed = 0; + int buf_format = MBEDTLS_X509_FORMAT_DER; + + /* + * Check for valid input + */ + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ +#if defined(MBEDTLS_PEM_PARSE_C) + if( buflen != 0 && buf[buflen - 1] == '\0' && + strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) + { + buf_format = MBEDTLS_X509_FORMAT_PEM; + } +#endif + + if( buf_format == MBEDTLS_X509_FORMAT_DER ) + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); + +#if defined(MBEDTLS_PEM_PARSE_C) + if( buf_format == MBEDTLS_X509_FORMAT_PEM ) + { + int ret; + mbedtls_pem_context pem; + + /* 1 rather than 0 since the terminating NULL byte is counted in */ + while( buflen > 1 ) + { + size_t use_len; + mbedtls_pem_init( &pem ); + + /* If we get there, we know the string is null-terminated */ + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + } + else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) + { + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + + /* + * PEM header and footer were found + */ + buflen -= use_len; + buf += use_len; + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + else + break; + + ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); + + mbedtls_pem_free( &pem ); + + if( ret != 0 ) + { + /* + * Quit parsing on a memory error + */ + if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) + return( ret ); + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + + success = 1; + } + } +#endif /* MBEDTLS_PEM_PARSE_C */ + + if( success ) + return( total_failed ); + else if( first_error ) + return( first_error ); + else + return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more certificates and add them to the chained list + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crt_parse( chain, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + int w_ret; + WCHAR szDir[MAX_PATH]; + char filename[MAX_PATH]; + char *p; + size_t len = strlen( path ); + + WIN32_FIND_DATAW file_data; + HANDLE hFind; + + if( len > MAX_PATH - 3 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( szDir, 0, sizeof(szDir) ); + memset( filename, 0, MAX_PATH ); + memcpy( filename, path, len ); + filename[len++] = '\\'; + p = filename + len; + filename[len++] = '*'; + + w_ret = MultiByteToWideChar( CP_ACP, 0, filename, len, szDir, + MAX_PATH - 3 ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + hFind = FindFirstFileW( szDir, &file_data ); + if( hFind == INVALID_HANDLE_VALUE ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + len = MAX_PATH - len; + do + { + memset( p, 0, len ); + + if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, + lstrlenW( file_data.cFileName ), + p, (int) len - 1, + NULL, NULL ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + w_ret = mbedtls_x509_crt_parse_file( chain, filename ); + if( w_ret < 0 ) + ret++; + else + ret += w_ret; + } + while( FindNextFileW( hFind, &file_data ) != 0 ); + + if( GetLastError() != ERROR_NO_MORE_FILES ) + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + + FindClose( hFind ); +#else /* _WIN32 */ + int t_ret; + struct stat sb; + struct dirent *entry; + char entry_name[255]; + DIR *dir = opendir( path ); + + if( dir == NULL ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + +#if defined(MBEDTLS_THREADING_PTHREAD) + if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) + { + closedir( dir ); + return( ret ); + } +#endif + + while( ( entry = readdir( dir ) ) != NULL ) + { + mbedtls_snprintf( entry_name, sizeof entry_name, "%s/%s", path, entry->d_name ); + + if( stat( entry_name, &sb ) == -1 ) + { + closedir( dir ); + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + if( !S_ISREG( sb.st_mode ) ) + continue; + + // Ignore parse errors + // + t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); + if( t_ret < 0 ) + ret++; + else + ret += t_ret; + } + closedir( dir ); + +cleanup: +#if defined(MBEDTLS_THREADING_PTHREAD) + if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) + ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; +#endif + +#endif /* _WIN32 */ + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence *subject_alt_name ) +{ + size_t i; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + const char *sep = ""; + size_t sep_len = 0; + + while( cur != NULL ) + { + if( cur->buf.len + sep_len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + n -= cur->buf.len + sep_len; + for( i = 0; i < sep_len; i++ ) + *p++ = sep[i]; + for( i = 0; i < cur->buf.len; i++ ) + *p++ = cur->buf.p[i]; + + sep = ", "; + sep_len = 2; + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + return( 0 ); +} + +#define PRINT_ITEM(i) \ + { \ + ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ + MBEDTLS_X509_SAFE_SNPRINTF; \ + sep = ", "; \ + } + +#define CERT_TYPE(type,name) \ + if( ns_cert_type & type ) \ + PRINT_ITEM( name ); + +static int x509_info_cert_type( char **buf, size_t *size, + unsigned char ns_cert_type ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +#define KEY_USAGE(code,name) \ + if( key_usage & code ) \ + PRINT_ITEM( name ); + +static int x509_info_key_usage( char **buf, size_t *size, + unsigned int key_usage ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); + KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); + KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +static int x509_info_ext_key_usage( char **buf, size_t *size, + const mbedtls_x509_sequence *extended_key_usage ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = extended_key_usage; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 18 +#define BC "18" +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, + crt->sig_md, crt->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* Key size */ + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &crt->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* + * Optional extensions + */ + + if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) + { + ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, + crt->ca_istrue ? "true" : "false" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( crt->max_pathlen > 0 ) + { + ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + } + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_subject_alt_name( &p, &n, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) + { + ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_ext_key_usage( &p, &n, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +struct x509_crt_verify_string { + int code; + const char *string; +}; + +#if 0 +static const struct x509_crt_verify_string x509_crt_verify_strings[] = { + { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, + { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, + { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, + { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, + { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, + { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, + { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, + { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, + { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, + { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, + { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, + { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, + { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { 0, NULL } +}; +#else +static const struct x509_crt_verify_string x509_crt_verify_strings[] = { + { MBEDTLS_X509_BADCERT_EXPIRED, NULL }, + { MBEDTLS_X509_BADCERT_REVOKED, NULL }, + { MBEDTLS_X509_BADCERT_CN_MISMATCH, NULL }, + { MBEDTLS_X509_BADCERT_NOT_TRUSTED, NULL }, + { MBEDTLS_X509_BADCRL_NOT_TRUSTED, NULL }, + { MBEDTLS_X509_BADCRL_EXPIRED, NULL }, + { MBEDTLS_X509_BADCERT_MISSING, NULL }, + { MBEDTLS_X509_BADCERT_SKIP_VERIFY, NULL }, + { MBEDTLS_X509_BADCERT_OTHER, NULL }, + { MBEDTLS_X509_BADCERT_FUTURE, NULL }, + { MBEDTLS_X509_BADCRL_FUTURE, NULL }, + { MBEDTLS_X509_BADCERT_KEY_USAGE, NULL }, + { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, NULL }, + { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, NULL }, + { MBEDTLS_X509_BADCERT_BAD_MD, NULL }, + { MBEDTLS_X509_BADCERT_BAD_PK, NULL }, + { MBEDTLS_X509_BADCERT_BAD_KEY, NULL }, + { MBEDTLS_X509_BADCRL_BAD_MD, NULL }, + { MBEDTLS_X509_BADCRL_BAD_PK, NULL }, + { MBEDTLS_X509_BADCRL_BAD_KEY, NULL }, + { 0, NULL } +}; +#endif + +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ) +{ + int ret; + const struct x509_crt_verify_string *cur; + char *p = buf; + size_t n = size; + + for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) + { + if( ( flags & cur->code ) == 0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); + MBEDTLS_X509_SAFE_SNPRINTF; + flags ^= cur->code; + } + + if( flags != 0 ) + { + ret = mbedtls_snprintf( p, n, "%sUnknown reason " + "(this should not happen)\n", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ) +{ + unsigned int usage_must, usage_may; + unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY + | MBEDTLS_X509_KU_DECIPHER_ONLY; + + if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) + return( 0 ); + + usage_must = usage & ~may_mask; + + if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + usage_may = usage & may_mask; + + if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ) +{ + const mbedtls_x509_sequence *cur; + + /* Extension is not mandatory, absent means no restriction */ + if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + return( 0 ); + + /* + * Look for the requested usage (or wildcard ANY) in our list + */ + for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) + { + const mbedtls_x509_buf *cur_oid = &cur->buf; + + if( cur_oid->len == usage_len && + memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) + { + return( 0 ); + } + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) + return( 0 ); + } + + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); +} +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/* + * Return 1 if the certificate is revoked, or 0 otherwise. + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) +{ + const mbedtls_x509_crl_entry *cur = &crl->entry; + + while( cur != NULL && cur->serial.len != 0 ) + { + if( crt->serial.len == cur->serial.len && + memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + { + if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) + return( 1 ); + } + + cur = cur->next; + } + + return( 0 ); +} + +/* + * Check that the given certificate is valid according to the CRL. + */ +static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, + mbedtls_x509_crl *crl_list, + const mbedtls_x509_crt_profile *profile ) +{ + int flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + + if( ca == NULL ) + return( flags ); + + /* + * TODO: What happens if no CRL is present? + * Suggestion: Revocation state should be unknown if no CRL is present. + * For backwards compatibility this is not yet implemented. + */ + + while( crl_list != NULL ) + { + if( crl_list->version == 0 || + crl_list->issuer_raw.len != ca->subject_raw.len || + memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, + crl_list->issuer_raw.len ) != 0 ) + { + crl_list = crl_list->next; + continue; + } + + /* + * Check if the CA is configured to sign CRLs + */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( mbedtls_x509_crt_check_key_usage( ca, MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } +#endif + + /* + * Check if CRL is correctly signed by the trusted CA + */ + if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_MD; + + if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_PK; + + md_info = mbedtls_md_info_from_type( crl_list->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ); + + if( x509_profile_check_key( profile, crl_list->sig_pk, &ca->pk ) != 0 ) + flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, + crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), + crl_list->sig.p, crl_list->sig.len ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + /* + * Check for validity of CRL (Do not drop out) + */ + if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) + flags |= MBEDTLS_X509_BADCRL_EXPIRED; + + if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) + flags |= MBEDTLS_X509_BADCRL_FUTURE; + + /* + * Check if certificate is revoked + */ + if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) + { + flags |= MBEDTLS_X509_BADCERT_REVOKED; + break; + } + + crl_list = crl_list->next; + } + + return( flags ); +} +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Return 0 if name matches wildcard, -1 otherwise + */ +static int x509_check_wildcard( const char *cn, mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( 0 ); + + for( i = 0; i < cn_len; ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( -1 ); + + if( cn_len - cn_idx == name->len - 1 && + x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + +/* + * Check if 'parent' is a suitable parent (signing CA) for 'child'. + * Return 0 if yes, -1 if not. + * + * top means parent is a locally-trusted certificate + * bottom means child is the end entity cert + */ +static int x509_crt_check_parent( const mbedtls_x509_crt *child, + const mbedtls_x509_crt *parent, + int top, int bottom ) +{ + int need_ca_bit; + + /* Parent must be the issuer */ + if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + return( -1 ); + + /* Parent must have the basicConstraints CA bit set as a general rule */ + need_ca_bit = 1; + + /* Exception: v1/v2 certificates that are locally trusted. */ + if( top && parent->version < 3 ) + need_ca_bit = 0; + + /* Exception: self-signed end-entity certs that are locally trusted. */ + if( top && bottom && + child->raw.len == parent->raw.len && + memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 ) + { + need_ca_bit = 0; + } + + if( need_ca_bit && ! parent->ca_istrue ) + return( -1 ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( need_ca_bit && + mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) + { + return( -1 ); + } +#endif + + return( 0 ); +} + +static int x509_crt_verify_top( + mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t ca_flags = 0; + int check_path_cnt; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + /* + * Child is the top of the chain. Check against the trust_ca list. + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown', no need to try any CA + */ + trust_ca = NULL; + } + else + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next ) + { + if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 ) + continue; + + check_path_cnt = path_cnt + 1; + + /* + * Reduce check_path_cnt to check against if top of the chain is + * the same as the trusted CA + */ + if( child->subject_raw.len == trust_ca->subject_raw.len && + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) == 0 ) + { + check_path_cnt--; + } + + /* Self signed certificates do not count towards the limit */ + if( trust_ca->max_pathlen > 0 && + trust_ca->max_pathlen < check_path_cnt - self_cnt ) + { + continue; + } + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + continue; + } + + /* + * Top of chain is signed by a trusted CA + */ + *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + break; + } + + /* + * If top of chain is not the same as the trusted CA send a verify request + * to the callback for any issues with validity and CRL presence for the + * trusted CA certificate. + */ + if( trust_ca != NULL && + ( child->subject_raw.len != trust_ca->subject_raw.len || + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) != 0 ) ) + { +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the chain's top crt */ + *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile ); +#else + ((void) ca_crl); +#endif + + if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ) + ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + ca_flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, + &ca_flags ) ) != 0 ) + { + return( ret ); + } + } + } + + /* Call callback on top cert */ + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + } + + *flags |= ca_flags; + + return( 0 ); +} + +static int x509_crt_verify_child( + mbedtls_x509_crt *child, mbedtls_x509_crt *parent, + mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t parent_flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + mbedtls_x509_crt *grandparent; + const mbedtls_md_info_t *md_info; + + /* Counting intermediate self signed certificates */ + if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + self_cnt++; + + /* path_cnt is 0 for the first intermediate CA */ + if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + } + + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + else + { + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + } + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the given crt */ + *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile ); +#endif + + /* Look for a grandparent in trusted CAs */ + for( grandparent = trust_ca; + grandparent != NULL; + grandparent = grandparent->next ) + { + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + if( grandparent != NULL ) + { + ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a grandparent upwards the chain */ + for( grandparent = parent->next; + grandparent != NULL; + grandparent = grandparent->next ) + { + /* +2 because the current step is not yet accounted for + * and because max_pathlen is one higher than it should be. + * Also self signed certificates do not count to the limit. */ + if( grandparent->max_pathlen > 0 && + grandparent->max_pathlen < 2 + path_cnt - self_cnt ) + { + continue; + } + + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + /* Is our parent part of the chain or at the top? */ + if( grandparent != NULL ) + { + ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, + profile, path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + /* child is verified to be a child of the parent, call verify callback */ + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + + *flags |= parent_flags; + + return( 0 ); +} + +/* + * Verify the certificate validity + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, + &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); +} + + +/* + * Verify the certificate validity, with profile + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + size_t cn_len; + int ret; + int pathlen = 0, selfsigned = 0; + mbedtls_x509_crt *parent; + mbedtls_x509_name *name; + mbedtls_x509_sequence *cur = NULL; + mbedtls_pk_type_t pk_type; + + if( profile == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + *flags = 0; + + if( cn != NULL ) + { + name = &crt->subject; + cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + cur = &crt->subject_alt_names; + + while( cur != NULL ) + { + if( cur->buf.len == cn_len && + x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) + break; + + if( cur->buf.len > 2 && + memcmp( cur->buf.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &cur->buf ) == 0 ) + { + break; + } + + cur = cur->next; + } + + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + while( name != NULL ) + { + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) + { + if( name->val.len == cn_len && + x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) + break; + + if( name->val.len > 2 && + memcmp( name->val.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &name->val ) == 0 ) + break; + } + + name = name->next; + } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + } + + /* Check the type and size of the key */ + pk_type = mbedtls_pk_get_type( &crt->pk ); + + if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + /* Look for a parent in trusted CAs */ + for( parent = trust_ca; parent != NULL; parent = parent->next ) + { + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + } + + if( parent != NULL ) + { + ret = x509_crt_verify_top( crt, parent, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a parent upwards the chain */ + for( parent = crt->next; parent != NULL; parent = parent->next ) + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + + /* Are we part of the chain or at the top? */ + if( parent != NULL ) + { + ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + if( *flags != 0 ) + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + +/* + * Initialize a certificate chain + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) +{ + memset( crt, 0, sizeof(mbedtls_x509_crt) ); +} + +/* + * Unallocate all certificate data + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) +{ + mbedtls_x509_crt *cert_cur = crt; + mbedtls_x509_crt *cert_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_sequence *seq_cur; + mbedtls_x509_sequence *seq_prv; + + if( crt == NULL ) + return; + + do + { + mbedtls_pk_free( &cert_cur->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( cert_cur->sig_opts ); +#endif + + name_cur = cert_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + name_cur = cert_cur->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + seq_cur = cert_cur->ext_key_usage.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + if( cert_cur->raw.p != NULL ) + { + mbedtls_zeroize( cert_cur->raw.p, cert_cur->raw.len ); + mbedtls_free( cert_cur->raw.p ); + } + + cert_cur = cert_cur->next; + } + while( cert_cur != NULL ); + + cert_cur = crt; + do + { + cert_prv = cert_cur; + cert_cur = cert_cur->next; + + mbedtls_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + if( cert_prv != crt ) + mbedtls_free( cert_prv ); + } + while( cert_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_csr.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_csr.c new file mode 100644 index 0000000000..dbf659b442 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509_csr.c @@ -0,0 +1,417 @@ +/* + * X.509 Certificate Signing Request (CSR) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Version ::= INTEGER { v1(0) } + */ +static int x509_csr_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * Parse a CSR in DER format + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + mbedtls_x509_buf sig_params; + + memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + mbedtls_x509_csr_init( csr ); + + /* + * first copy the raw DER data + */ + p = mbedtls_calloc( 1, len = buflen ); + + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + csr->raw.p = p; + csr->raw.len = len; + end = p + len; + + /* + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * CertificationRequestInfo ::= SEQUENCE { + */ + csr->cri.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + csr->cri.len = end - csr->cri.p; + + /* + * Version ::= INTEGER { v1(0) } + */ + if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + csr->version++; + + if( csr->version != 1 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + /* + * subject Name + */ + csr->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + csr->subject_raw.len = p - csr->subject_raw.p; + + /* + * subjectPKInfo SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + /* + * attributes [0] Attributes + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + // TODO Parse Attributes / extension requests + + p += len; + + end = csr->raw.p + csr->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params, + &csr->sig_md, &csr->sig_pk, + &csr->sig_opts ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse a CSR, allowing for PEM or raw DER encoding + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) +{ + int ret; +#if defined(MBEDTLS_PEM_PARSE_C) + size_t use_len; + mbedtls_pem_context pem; +#endif + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( buflen == 0 || buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded, parse the result + */ + if( ( ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen ) ) != 0 ) + return( ret ); + + mbedtls_pem_free( &pem ); + return( 0 ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_csr_parse_der( csr, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load a CSR into the structure + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_csr_parse( csr, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CSR. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCSR version : %d", + prefix, csr->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &csr->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md, + csr->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &csr->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &csr->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CSR + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ) +{ + memset( csr, 0, sizeof(mbedtls_x509_csr) ); +} + +/* + * Unallocate all CSR data + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ) +{ + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + + if( csr == NULL ) + return; + + mbedtls_pk_free( &csr->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( csr->sig_opts ); +#endif + + name_cur = csr->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + if( csr->raw.p != NULL ) + { + mbedtls_zeroize( csr->raw.p, csr->raw.len ); + mbedtls_free( csr->raw.p ); + } + + mbedtls_zeroize( csr, sizeof( mbedtls_x509_csr ) ); +} + +#endif /* MBEDTLS_X509_CSR_PARSE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_crt.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_crt.c new file mode 100644 index 0000000000..9041d440ff --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_crt.c @@ -0,0 +1,456 @@ +/* + * X.509 certificate writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - certificates: RFC 5280, updated by RFC 6818 + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/sha1.h" + +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif /* MBEDTLS_PEM_WRITE_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_x509write_cert) ); + + mbedtls_mpi_init( &ctx->serial ); + ctx->version = MBEDTLS_X509_CRT_VERSION_3; +} + +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) +{ + mbedtls_mpi_free( &ctx->serial ); + + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->issuer ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_cert) ); +} + +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ) +{ + ctx->version = version; +} + +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->subject_key = key; +} + +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->issuer_key = key; +} + +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ) +{ + return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name ); +} + +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ) +{ + if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 || + strlen( not_after ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ) + { + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } + strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + + return( 0 ); +} + +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + critical, val, val_len ); +} + +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ) +{ + int ret; + unsigned char buf[9]; + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + + if( is_ca && max_pathlen > 127 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( is_ca ) + { + if( max_pathlen >= 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) ); + } + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, + MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), + 0, buf + sizeof(buf) - len, len ); +} + +#if defined(MBEDTLS_SHA1_C) +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} + +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} +#endif /* MBEDTLS_SHA1_C */ + +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ) +{ + unsigned char buf[4], ku; + unsigned char *c; + int ret; + + /* We currently only support 7 bits, from 0x80 to 0x02 */ + if( ( key_usage & ~0xfe ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + + c = buf + 4; + ku = (unsigned char) key_usage; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + 1, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + 0, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) +{ + int ret; + size_t len = 0; + + /* + * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) + */ + if( time[0] == '2' && time[1] == '0' && time [2] < '5' ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) time + 2, + size - 2 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) time, + size ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) ); + } + + return( (int) len ); +} + +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + /* Signature algorithm needed in TBS, and later for actual signature */ + pk_alg = mbedtls_pk_get_type( ctx->issuer_key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 3 ) ); + + /* + * SubjectPublicKeyInfo + */ + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + sub_len = 0; + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Issuer ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) ); + + /* + * Signature ::= AlgorithmIdentifier + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf, + sig_oid, strlen( sig_oid ), 0 ) ); + + /* + * Serial ::= INTEGER + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + sub_len = 0; + MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) ); + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Make signature + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" +#define PEM_END_CRT "-----END CERTIFICATE-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CRT_WRITE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_csr.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_csr.c new file mode 100644 index 0000000000..0b9a2851e0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/x509write_csr.c @@ -0,0 +1,256 @@ +/* + * X.509 Certificate Signing Request writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" + +#include +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_x509write_csr) ); +} + +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) +{ + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_csr) ); +} + +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ) +{ + ctx->key = key; +} + +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + 0, val, val_len ); +} + +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + + if( len ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &c, tmp_buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, + MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_CSR_EXT_REQ ) ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, tmp_buf, 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Prepare signature + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + pk_alg = mbedtls_pk_get_type( ctx->key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 || + ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" +#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_csr_der( ctx, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CSR_WRITE_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/xtea.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/xtea.c new file mode 100644 index 0000000000..fe0a3509f6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/library/xtea.c @@ -0,0 +1,281 @@ +/* + * An 32-bit implementation of the XTEA algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_XTEA_C) + +#include "mbedtls/xtea.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_XTEA_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_xtea_context ) ); +} + +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_xtea_context ) ); +} + +/* + * XTEA key schedule + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ) +{ + int i; + + memset( ctx, 0, sizeof(mbedtls_xtea_context) ); + + for( i = 0; i < 4; i++ ) + { + GET_UINT32_BE( ctx->k[i], key, i << 2 ); + } +} + +/* + * XTEA encrypt function + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, int mode, + const unsigned char input[8], unsigned char output[8]) +{ + uint32_t *k, v0, v1, i; + + k = ctx->k; + + GET_UINT32_BE( v0, input, 0 ); + GET_UINT32_BE( v1, input, 4 ); + + if( mode == MBEDTLS_XTEA_ENCRYPT ) + { + uint32_t sum = 0, delta = 0x9E3779B9; + + for( i = 0; i < 32; i++ ) + { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + } + } + else /* MBEDTLS_XTEA_DECRYPT */ + { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for( i = 0; i < 32; i++ ) + { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + } + } + + PUT_UINT32_BE( v0, output, 0 ); + PUT_UINT32_BE( v1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * XTEA-CBC buffer encryption/decryption + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, int mode, size_t length, + unsigned char iv[8], const unsigned char *input, + unsigned char *output) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_XTEA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_xtea_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_xtea_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* !MBEDTLS_XTEA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * XTEA tests vectors (non-official) + */ + +static const unsigned char xtea_test_key[6][16] = +{ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 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 } +}; + +static const unsigned char xtea_test_pt[6][8] = +{ + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f }, + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 } +}; + +static const unsigned char xtea_test_ct[6][8] = +{ + { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 }, + { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 }, + { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 } +}; + +/* + * Checkup routine + */ +int mbedtls_xtea_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char buf[8]; + mbedtls_xtea_context ctx; + + mbedtls_xtea_init( &ctx ); + for( i = 0; i < 6; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " XTEA test #%d: ", i + 1 ); + + memcpy( buf, xtea_test_pt[i], 8 ); + + mbedtls_xtea_setup( &ctx, xtea_test_key[i] ); + mbedtls_xtea_crypt_ecb( &ctx, MBEDTLS_XTEA_ENCRYPT, buf, buf ); + + if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_xtea_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_XTEA_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/Makefile new file mode 100644 index 0000000000..749b4787ca --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = libplatform.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/esp_hardware.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/esp_hardware.c new file mode 100644 index 0000000000..d57441f516 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/esp_hardware.c @@ -0,0 +1,51 @@ +/* + * ESPRSSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include "osapi.h" + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Entropy poll callback for a hardware source + * + * \warning This is not provided by mbed TLS! + * See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h. + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_hardware_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + os_get_random(output, len); + *olen = len; + return 0; +} +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/net.c b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/net.c new file mode 100644 index 0000000000..e0692e6539 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/third_party/mbedtls/platform/net.c @@ -0,0 +1,440 @@ +/* + * TCP/IP or UDP/IP networking functions + * modified for LWIP support on ESP8266 + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2015 Angus Gratton + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +//#define MBEDTLS_CONFIG_FILE +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_NET_C) + +#include "mbedtls/net.h" + +#include +// +#include +#include +//#include +#include +#include "lwip/netdb.h" +#include +// +#include +#include +// +#include +// +#include + +/* + * Prepare for using the sockets interface + */ +static int net_prepare( void ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else +#endif + return( 0 ); +} + +/* + * Initialize a context + */ +void mbedtls_net_init( mbedtls_net_context *ctx ) +{ + ctx->fd = -1; +} + +/* + * Initiate a TCP connection with host:port and the given protocol + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ) +{ + int ret; + uint32 ports = getul((char*)port); + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + client_addr.sin_family = AF_INET; + client_addr.sin_addr.s_addr = htons(IPADDR_ANY); + client_addr.sin_port = htons(0); + + ctx->fd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); + if( ctx->fd < 0 ){ + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + os_printf("Create Socket Failed!\n"); + goto mbedtls_error; + } + + if (bind(ctx->fd, (struct sockaddr*)&client_addr,sizeof(client_addr))) { + ret = MBEDTLS_ERR_NET_BIND_FAILED; + os_printf("Client Bind Port Failed!\n"); + goto mbedtls_error; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = ipaddr_addr(host); + server_addr.sin_port = htons(ports); + + ret = connect(ctx->fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); + if (ret < 0){ + ret = MBEDTLS_ERR_NET_CONNECT_FAILED; + os_printf("Can Not Connect To!\n"); + } + +mbedtls_error: + if (ret < 0) + close( ctx->fd ); + return( ret ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) +{ + int ret; + int protocol = 0; + int sock_type = 0; + uint32 ports = getul((char*)port); + + struct sockaddr_in server_addr; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = htons(IPADDR_ANY); + server_addr.sin_port = htons(ports); + protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + sock_type = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + + ctx->fd = socket(AF_INET, sock_type, protocol); + if( ctx->fd < 0 ){ + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + os_printf("Create Socket Failed!\n"); + goto mbedtls_error; + } + + ret = bind(ctx->fd, (struct sockaddr*)&server_addr,sizeof(server_addr)); + if (ret != 0){ + ret = MBEDTLS_ERR_NET_BIND_FAILED; + os_printf("Server Bind Port Failed!\n"); + goto mbedtls_error; + } + + if (proto == MBEDTLS_NET_PROTO_TCP){ + ret = listen(ctx->fd, MBEDTLS_ERR_NET_LISTEN_FAILED); + if (ret != 0){ + ret = MBEDTLS_ERR_NET_LISTEN_FAILED; + goto mbedtls_error; + } + } + + ret = 0; + + mbedtls_error: + if (ret < 0) + close( ctx->fd ); + return( ret ); + +} + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + ((void) ctx); + return( WSAGetLastError() == WSAEWOULDBLOCK ); +} +#else +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + * + * Note: on a blocking socket this function always returns 0! + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ +// if( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) +// return( 0 ); + +// switch( errno ) +// { +//#if defined EAGAIN +// case EAGAIN: +//#endif +//#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN +// case EWOULDBLOCK: +//#endif +// return( 1 ); +// } + return( 0 ); +} +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* + * Accept a connection from a remote client + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ) +{ + int ret; + int type; + + struct sockaddr_in client_addr; + + socklen_t n = (socklen_t) sizeof( client_addr ); + socklen_t type_len = (socklen_t) sizeof( type ); + + client_ctx->fd = (int) accept( bind_ctx->fd,(struct sockaddr *) &client_addr, &n ); + if (client_ctx->fd < 0){ + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + os_printf("Create Socket Failed!\n"); + goto mbedtls_error; + } + + if(client_ip != NULL){ + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); + + if( buf_size < *ip_len ){ + ret = MBEDTLS_ERR_NET_BUFFER_TOO_SMALL; + os_printf("Create Socket Failed!\n"); + goto mbedtls_error; + } + + memcpy(client_ip, &addr4->sin_addr.s_addr, *ip_len); + } + ret = 0; + mbedtls_error: + if (ret < 0) + close( client_ctx->fd ); + return( ret ); + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 0; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) ); +#endif +} + +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 1; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) ); +#endif +} + +/* + * Portable usleep helper + */ +void mbedtls_net_usleep( unsigned long usec ) +{ +//#if defined(_WIN32) +// Sleep( ( usec + 999 ) / 1000 ); +//#else +// struct timeval tv; +// tv.tv_sec = usec / 1000000; +//#if defined(__unix__) || defined(__unix) || \ +// ( defined(__APPLE__) && defined(__MACH__) ) +// tv.tv_usec = (suseconds_t) usec % 1000000; +//#else +// tv.tv_usec = usec % 1000000; +//#endif +// select( 0, NULL, NULL, NULL, &tv ); +//#endif +} + +/* + * Read at most 'len' characters + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + +// os_printf("mbedtls_net_recv need %d\n", len); + ret = (int) read( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + +//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ +// !defined(EFI32) +// if( WSAGetLastError() == WSAECONNRESET ) +// return( MBEDTLS_ERR_NET_CONN_RESET ); +//#else +// if( errno == EPIPE || errno == ECONNRESET ) +// return( MBEDTLS_ERR_NET_CONN_RESET ); +// +// if( errno == EINTR ) +// return( MBEDTLS_ERR_SSL_WANT_READ ); +//#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } +// os_printf("mbedtls_net_recv get %d\n", ret); + if (ret == 0) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( ret ); +} + +/* + * Read at most 'len' characters, blocking for at most 'timeout' ms + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + +// FD_ZERO( &read_fds ); +// FD_SET( fd, &read_fds ); +// +// tv.tv_sec = timeout / 1000; +// tv.tv_usec = ( timeout % 1000 ) * 1000; +// +// ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); +// +// /* Zero fds ready means we timed out */ +// if( ret == 0 ) +// return( MBEDTLS_ERR_SSL_TIMEOUT ); +// +// if( ret < 0 ) +// { +//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ +// !defined(EFI32) +// if( WSAGetLastError() == WSAEINTR ) +// return( MBEDTLS_ERR_SSL_WANT_READ ); +//#else +// if( errno == EINTR ) +// return( MBEDTLS_ERR_SSL_WANT_READ ); +//#endif +// +// return( MBEDTLS_ERR_NET_RECV_FAILED ); +// } + + /* This call will not block */ + return( mbedtls_net_recv( ctx, buf, len ) ); +} + +/* + * Write at most 'len' characters + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + +// os_printf("mbedtls_net_send need %d\n", len); + ret = (int) write( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + +//#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ +// !defined(EFI32) +// if( WSAGetLastError() == WSAECONNRESET ) +// return( MBEDTLS_ERR_NET_CONN_RESET ); +//#else +// if( errno == EPIPE || errno == ECONNRESET ) +// return( MBEDTLS_ERR_NET_CONN_RESET ); +// +// if( errno == EINTR ) +// return( MBEDTLS_ERR_SSL_WANT_WRITE ); +//#endif +// +// return( MBEDTLS_ERR_NET_SEND_FAILED ); + } +// os_printf("mbedtls_net_send write %d\n", ret); + if (ret == 0) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + return( ret ); +} + +/* + * Gracefully close the connection + */ +void mbedtls_net_free( mbedtls_net_context *ctx ) +{ + if( ctx->fd == -1 ) + return; + + close( ctx->fd ); + + ctx->fd = -1; +} + +#endif /* MBEDTLS_NET_C */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/README.md b/Sming/third-party/ESP8266_NONOS_SDK/tools/README.md new file mode 100755 index 0000000000..9d46866680 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/README.md @@ -0,0 +1,84 @@ +## SSL tools +Refer to [ESP8266 Non-OS SDK SSL User Manual](http://espressif.com/en/support/download/documents?keys=&field_type_tid%5B%5D=14) + +## certificate generation +you **must** choose one of a,b,c to generate your certificate file +### a) if you does not have any certificate file which issued by trusted CA + +we would generate self-signed CA certificate,and generate certificate and private key with self-signed CA. + +- **change your CN field in your makefile.sh** to your IP address + +run the command as the following: + +**makefile.sh:** +``` +$./makefile.sh +``` +generate all of your cert and private key files. + +**rmfile.sh** +``` +$./rmfile.sh +``` + +delete all of your cert and private key files. + +the certificate files to flash are under the directory bin/ + +### b) if you just have CA certificate: ca.crt which issued by trusted CA + +we would generate CA bin:esp_ca_cert.bin for one-way authentication + +- **[important]**if CA certificate file is not called ca.crt, please rename it to ca.crt +- ensure the CA certificate file is in **PEM** format +- copy your ca.crt to tools/ directory + +run the command as the following: + +**makefile.sh:** + +``` +$./makefile.sh +``` + +the command would generate your CA certificate bin + +**rmfile.sh** + +``` +$./rmfile.sh +``` + +delete all of your generated files + +the certificate file to flash is under the directory bin/ + +### c) if you have both CA certificate:ca.crt and client certificate:client.crt and client key:client.key which issued by trusted CA + +we would generate CA bin:esp_ca_cert.bin and client certificate/private key bin:esp_cert_private_key.bin for two-way authentication + +- **[important]**if their filename is not called ca.crt,client.crt,client.key, please rename it to ca.crt,client.crt,client.key +- ensure the ca.crt,client.crt,client.key are in **PEM** format +- copy your ca.crt,client.crt,client.key to tools/ directory + +run the command as the following: + +**makefile.sh:** + +``` +$./makefile.sh +``` + +the command would generate all of your CA certificate bin:esp_ca_cert.bin and client bin:esp_cert_private_key.bin. + +**rmfile.sh** + +``` +$./rmfile.sh +``` + +delete all of your generated files. + +the certificate file to flash is under directory bin/ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/gen_appbin.py b/Sming/third-party/ESP8266_NONOS_SDK/tools/gen_appbin.py new file mode 100644 index 0000000000..1df8ed17e4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/gen_appbin.py @@ -0,0 +1,286 @@ +#!/usr/bin/python +# +# File : gen_appbin.py +# This file is part of Espressif's generate bin script. +# +# ESPRESSIF MIT License +# +# Copyright (c) 2016 +# +# Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, +# it is free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the Software is furnished +# to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# + +"""This file is part of Espressif's generate bin script. + argv[1] is elf file name + argv[2] is version num""" + +import string +import sys +import os +import re +import binascii +import struct +import zlib + + +TEXT_ADDRESS = 0x40100000 +# app_entry = 0 +# data_address = 0x3ffb0000 +# data_end = 0x40000000 +# text_end = 0x40120000 + +CHECKSUM_INIT = 0xEF + +chk_sum = CHECKSUM_INIT +blocks = 0 + +def write_file(file_name,data): + if file_name is None: + print 'file_name cannot be none\n' + sys.exit(0) + + fp = open(file_name,'ab') + + if fp: + fp.seek(0,os.SEEK_END) + fp.write(data) + fp.close() + else: + print '%s write fail\n'%(file_name) + +def combine_bin(file_name,dest_file_name,start_offset_addr,need_chk): + global chk_sum + global blocks + if dest_file_name is None: + print 'dest_file_name cannot be none\n' + sys.exit(0) + + if file_name: + fp = open(file_name,'rb') + if fp: + ########## write text ########## + fp.seek(0,os.SEEK_END) + data_len = fp.tell() + if data_len: + if need_chk: + tmp_len = (data_len + 3) & (~3) + else: + tmp_len = (data_len + 15) & (~15) + data_bin = struct.pack(' eagle.app.sym' + else : + cmd = 'xt-nm -g ' + elf_file + ' > eagle.app.sym' + + os.system(cmd) + + fp = file('./eagle.app.sym') + if fp is None: + print "open sym file error\n" + sys.exit(0) + + lines = fp.readlines() + fp.close() + + entry_addr = None + p = re.compile('(\w*)(\sT\s)(call_user_start)$') + for line in lines: + m = p.search(line) + if m != None: + entry_addr = m.group(1) + # print entry_addr + + if entry_addr is None: + print 'no entry point!!' + sys.exit(0) + + data_start_addr = '0' + p = re.compile('(\w*)(\sA\s)(_data_start)$') + for line in lines: + m = p.search(line) + if m != None: + data_start_addr = m.group(1) + # print data_start_addr + + rodata_start_addr = '0' + p = re.compile('(\w*)(\sA\s)(_rodata_start)$') + for line in lines: + m = p.search(line) + if m != None: + rodata_start_addr = m.group(1) + # print rodata_start_addr + + # write flash bin header + #============================ + # SPI FLASH PARAMS + #------------------- + #flash_mode= + # 0: QIO + # 1: QOUT + # 2: DIO + # 3: DOUT + #------------------- + #flash_clk_div= + # 0 : 80m / 2 + # 1 : 80m / 3 + # 2 : 80m / 4 + # 0xf: 80m / 1 + #------------------- + #flash_size_map= + # 0 : 512 KB (256 KB + 256 KB) + # 1 : 256 KB + # 2 : 1024 KB (512 KB + 512 KB) + # 3 : 2048 KB (512 KB + 512 KB) + # 4 : 4096 KB (512 KB + 512 KB) + # 5 : 2048 KB (1024 KB + 1024 KB) + # 6 : 4096 KB (1024 KB + 1024 KB) + #------------------- + # END OF SPI FLASH PARAMS + #============================ + byte2=int(flash_mode)&0xff + byte3=(((int(flash_size_map)<<4)| int(flash_clk_div))&0xff) + app=int(user_bin)&0xff + if boot_mode == '2': + # write irom bin head + #data_bin = struct.pack('> 8)+chr((all_bin_crc & 0x00FF0000) >> 16)+chr((all_bin_crc & 0xFF000000) >> 24)) + cmd = 'rm eagle.app.sym' + os.system(cmd) + +if __name__=='__main__': + gen_appbin() diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cacert.py b/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cacert.py new file mode 100644 index 0000000000..221a3037c2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cacert.py @@ -0,0 +1,64 @@ +# +# ESPRESSIF MIT License +# +# Copyright (c) 2016 +# +# Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, +# it is free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the Software is furnished +# to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +import os + + +class Cert(object): + def __init__(self, name, buff): + self.name = name + self.len = len(buff) + self.buff = buff + pass + + def __str__(self): + out_str = ['\0']*32 + for i in range(len(self.name)): + out_str[i] = self.name[i] + out_str = "".join(out_str) + out_str += str(chr(self.len & 0xFF)) + out_str += str(chr((self.len & 0xFF00) >> 8)) + out_str += self.buff + return out_str + pass + + +def main(): + cert_list = [] + file_list = os.listdir(os.getcwd()) + cert_file_list = [] + for _file in file_list: + if _file.endswith(".cer"): + cert_file_list.append(_file) + print cert_file_list + for cert_file in cert_file_list: + with open(cert_file, 'rb') as f: + buff = f.read() + cert_list.append(Cert(cert_file, buff)) + with open('esp_ca_cert.bin', 'wb+') as f: + for _cert in cert_list: + f.write("%s" % _cert) + pass +if __name__ == '__main__': + main() + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cert.py b/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cert.py new file mode 100644 index 0000000000..b48a3f610c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/make_cert.py @@ -0,0 +1,76 @@ +# +# ESPRESSIF MIT License +# +# Copyright (c) 2016 +# +# Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, +# it is free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the Software is furnished +# to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +import os + + +class Cert(object): + def __init__(self, name, buff): + self.name = name + self.len = len(buff) + self.buff = buff + pass + + def __str__(self): + out_str = ['\0']*32 + for i in range(len(self.name)): + out_str[i] = self.name[i] + out_str = "".join(out_str) + out_str += str(chr(self.len & 0xFF)) + out_str += str(chr((self.len & 0xFF00) >> 8)) + out_str += self.buff + return out_str + pass + + +def main(): + cert_list = [] + file_list = os.listdir(os.getcwd()) + cert_file_list = [] + for _file in file_list: + pos = _file.find(".key_1024") + if pos != -1: + cert_file_list.append(_file[:pos]) + + pos = _file.find(".cer") + if pos!= -1: + cert_file_list.append(_file[:pos]) + + for cert_file in cert_file_list: + if cert_file == 'private_key': + with open(cert_file+".key_1024", 'rb') as f: + buff = f.read() + cert_list.append(Cert(cert_file, buff)) + + if cert_file == 'certificate': + with open(cert_file+".cer", 'rb') as f: + buff = f.read() + cert_list.append(Cert(cert_file, buff)) + + with open('esp_cert_private_key.bin', 'wb+') as f: + for _cert in cert_list: + f.write("%s" % _cert) + pass +if __name__ == '__main__': + main() + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/makefile.sh b/Sming/third-party/ESP8266_NONOS_SDK/tools/makefile.sh new file mode 100755 index 0000000000..434be2b598 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/makefile.sh @@ -0,0 +1,198 @@ +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +PROJECT_NAME="TLS Project" +mkdir ca +mkdir bin +TrueCA=-1 +if [ -f "ca.crt" ]; then + echo ca.crt is found, generating esp_ca_cert.bin... + TrueCA=1 +else + echo ca.crt not exist\! We would generate self-signed CA certificate,and generating esp_ca_cert.bin... + TrueCA=0 + +# Generate the openssl configuration files. +cat > ca_cert.conf << EOF +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] + O = $PROJECT_NAME Dodgy Certificate Authority +EOF + + + openssl genrsa -out ca.key 1024 #you can change number 1024 if encryption bits is required + openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf + + # generate the actual self-signed ca certs. + openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key + + cp ca.key ca/ + +fi + + openssl x509 -in ca.crt -outform DER -out TLS.ca_x509.cer + cp TLS.ca_x509.cer ca/ + cp make_cacert.py ca/ + cd ca/ + python make_cacert.py + cd .. + cp ca/esp_ca_cert.bin bin/ + cp ca.crt ca/ + +echo esp_ca_cert.bin generated OK\! + +if [ $TrueCA -eq 1 ];then + echo trust CA + if [ -f "client.crt" ] && [ -f "client.key" ]; then + echo client.crt \&\& client.key are found, generating esp_cert_private_key.bin + mkdir client + mkdir include + openssl rsa -in client.key -out TLS.key_1024 -outform DER + openssl x509 -in client.crt -outform DER -out TLS.x509_1024.cer + cp TLS.x509_1024.cer client/ + cp TLS.key_1024 client/ + mv client/TLS.x509_1024.cer client/certificate.cer + mv client/TLS.key_1024 client/private_key.key_1024 + cp make_cert.py client/ + cd client + + python make_cert.py + rm make_cert.py + mv esp_cert_private_key.bin ../bin/ + cd .. + + # set default cert for use in the client + xxd -i TLS.x509_1024.cer | sed -e \ + "s/TLS_x509_1024_cer/default_certificate/" > cert.h + # set default key for use in the server + xxd -i TLS.key_1024 | sed -e \ + "s/TLS_key_1024/default_private_key/" > private_key.h + cp cert.h private_key.h include/ + cp client.crt client.key client/ + + elif [ -f "server.crt" ] && [ -f "server.key" ]; then + echo server.crt \&\& server.key are found, generating esp_cert_private_key.bin + mkdir server + mkdir include + openssl rsa -in server.key -out TLS.key_1024 -outform DER + openssl x509 -in server.crt -outform DER -out TLS.x509_1024.cer + cp TLS.x509_1024.cer server/ + cp TLS.key_1024 server/ + mv server/TLS.x509_1024.cer server/certificate.cer + mv server/TLS.key_1024 server/private_key.key_1024 + cp make_cert.py server/ + cd server + + python make_cert.py + rm make_cert.py + mv esp_cert_private_key.bin ../bin/ + cd .. + + # set default cert for use in the client + xxd -i TLS.x509_1024.cer | sed -e \ + "s/TLS_x509_1024_cer/default_certificate/" > cert.h + # set default key for use in the server + xxd -i TLS.key_1024 | sed -e \ + "s/TLS_key_1024/default_private_key/" > private_key.h + cp cert.h private_key.h include/ + cp server.crt server.key server/ + else + echo we would not generate certificate \for ESP chip when trust CA exist and [client.crt \&\& client.key] or [server.crt \&\& server.key] could not be found. + fi +elif [ $TrueCA -eq 0 ];then + echo generate cerificate and private key with self-signed CA + mkdir server + mkdir client + mkdir include + +cat > server_cert.conf << EOF +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] + O = $PROJECT_NAME + CN = 192.168.111.100 +EOF + +cat > client_cert.conf << EOF +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] + O = $PROJECT_NAME Device Certificate + CN = 192.168.111.101 +EOF + + openssl genrsa -out server.key 1024 + openssl genrsa -out client.key 1024 + + openssl rsa -in client.key -out TLS.key_1024 -outform DER + openssl req -out server.req -key server.key -new -config ./server_cert.conf + openssl req -out client.req -key client.key -new -config ./client_cert.conf + + openssl x509 -req -in server.req -out server.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key + openssl x509 -req -in client.req -out client.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key + cp server.crt server.key server/ + + openssl x509 -in client.crt -outform DER -out TLS.x509_1024.cer + cp TLS.x509_1024.cer client/ + cp TLS.key_1024 client/ + mv client/TLS.x509_1024.cer client/certificate.cer + mv client/TLS.key_1024 client/private_key.key_1024 + cp make_cert.py client/ + cd client + + python make_cert.py + rm make_cert.py + mv esp_cert_private_key.bin ../bin/ + cd .. + + # set default cert for use in the client + xxd -i TLS.x509_1024.cer | sed -e \ + "s/TLS_x509_1024_cer/default_certificate/" > cert.h + # set default key for use in the server + xxd -i TLS.key_1024 | sed -e \ + "s/TLS_key_1024/default_private_key/" > private_key.h + mv cert.h private_key.h include/ + cp client.crt client.key client/ + rm *.crt + rm *.key + +else + echo error happened\!TrueCA didnot initialize. +fi + +#delete intermediate file + +rm ca/make_cacert.py ca/esp_ca_cert.bin -rf +rm *.conf -rf +rm *.req -rf +rm *.h -rf + +rm *.srl -rf + +find -name \*.cer | xargs rm -f +find -name \*.key_1024 | xargs rm -f + +echo esp_ca_cert.bin \&\& esp_cert_private_key.bin was generated under bin\/ directory diff --git a/Sming/third-party/ESP8266_NONOS_SDK/tools/rmfile.sh b/Sming/third-party/ESP8266_NONOS_SDK/tools/rmfile.sh new file mode 100755 index 0000000000..93d491553e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/tools/rmfile.sh @@ -0,0 +1,16 @@ +rm *.pem -rf +rm *.srl -rf +rm *.h -rf +rm *.cer -rf +rm *.key_1024 -rf +rm *.req -rf +rm *.conf -rf + +rm ca/ -rf +rm bin/ -rf +rm server/ -rf +rm client/ -rf +rm include/ -rf + + + diff --git a/Sming/third-party/esp-gdbstub/gdbstub.c b/Sming/third-party/esp-gdbstub/gdbstub.c index 03f6d49389..fe655b8e1f 100644 --- a/Sming/third-party/esp-gdbstub/gdbstub.c +++ b/Sming/third-party/esp-gdbstub/gdbstub.c @@ -719,7 +719,7 @@ static void ATTR_GDBFN uart_hdlr(void *arg, void *frame) { } static void ATTR_GDBINIT install_uart_hdlr() { - ets_isr_attach(ETS_UART_INUM, uart_hdlr, NULL); + ets_isr_attach(ETS_UART_INUM, (ets_isr_t)uart_hdlr, NULL); SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); ets_isr_unmask((1< #define EFAULT 14 @@ -46,10 +47,10 @@ extern void *ets_memset(void *s, int c, size_t n); extern void *ets_memcpy(void *dest, const void *src, size_t n); -extern size_t ets_strlen(const char *s); +extern int ets_strlen(const char *s); extern int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); extern int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -extern void ets_timer_arm_new(ETSTimer *ptimer, uint32_t milliseconds, bool repeat_flag, int isMstimer); +//extern void ets_timer_arm_new(ETSTimer *ptimer, uint32_t milliseconds, bool repeat_flag, int isMstimer); extern void ets_timer_disarm(ETSTimer *a); extern void ets_timer_setfn(ETSTimer *t, ETSTimerFunc *pfunction, void *parg); extern uint32 r_rand(void); diff --git a/Sming/third-party/esp-open-lwip/include/user_config.h b/Sming/third-party/esp-open-lwip/include/user_config.h index 0c5dff9156..d608ddf81c 100644 --- a/Sming/third-party/esp-open-lwip/include/user_config.h +++ b/Sming/third-party/esp-open-lwip/include/user_config.h @@ -5,9 +5,10 @@ extern "C" { #endif +#include "c_types.h" typedef signed short sint16_t; -void *ets_bzero(void *block, size_t size); +void ets_bzero(void *block, size_t size); bool ets_post(uint32_t prio, ETSSignal sig, ETSParam par); void ets_task(ETSTask task, uint32_t prio, ETSEvent * queue, uint8 qlen); diff --git a/Sming/third-party/lwip2 b/Sming/third-party/lwip2 deleted file mode 160000 index 5b73bb11d5..0000000000 --- a/Sming/third-party/lwip2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5b73bb11d59285d49a6efeb20726186cc5cc2b74 diff --git a/Sming/third-party/lwip2/Makefile.arduino b/Sming/third-party/lwip2/Makefile.arduino new file mode 100644 index 0000000000..a14ce5031b --- /dev/null +++ b/Sming/third-party/lwip2/Makefile.arduino @@ -0,0 +1,8 @@ + +%: + make -f makefiles/Makefile.build-lwip2 \ + SDK=../.. \ + LWIP_LIB=liblwip2.a \ + LWIP_LIB_RELEASE=../../lib/liblwip2.a \ + TOOLS=../../../xtensa-lx106-elf/bin/xtensa-lx106-elf- \ + $@ diff --git a/Sming/third-party/lwip2/Makefile.open b/Sming/third-party/lwip2/Makefile.open new file mode 100644 index 0000000000..7af2a0c8d3 --- /dev/null +++ b/Sming/third-party/lwip2/Makefile.open @@ -0,0 +1,18 @@ + +$(shell makefiles/patch-non-local-includes \ + $(PREFIX)/xtensa-lx106-elf/sysroot/usr/include/user_interface.h \ + $(PREFIX)/xtensa-lx106-elf/sysroot/usr/include/sntp.h \ +) + +SDK=$(PREFIX)/xtensa-lx106-elf/sysroot/usr +LWIP_LIB_RELEASE=$(SDK)/lib/liblwip2.a +LWIP_INCLUDES_RELEASE=$(SDK)/include/lwip2 + +%: + make -f makefiles/Makefile.build-lwip2 \ + SDK=$(SDK) \ + LWIP_LIB=liblwip2.a \ + LWIP_LIB_RELEASE=$(LWIP_LIB_RELEASE) \ + LWIP_INCLUDES_RELEASE=$(LWIP_INCLUDES_RELEASE) \ + TOOLS=$(PREFIX)/bin/xtensa-lx106-elf- \ + $@ diff --git a/Sming/third-party/lwip2/Makefile.sming b/Sming/third-party/lwip2/Makefile.sming new file mode 100644 index 0000000000..7550a72f75 --- /dev/null +++ b/Sming/third-party/lwip2/Makefile.sming @@ -0,0 +1,19 @@ + +# ESP_HOME must point to esp-open-sdk + +USER_LIBDIR ?= tweaked- +LWIP_LIB_RELEASE=$(USER_LIBDIR)liblwip2.a +LWIP_INCLUDES_RELEASE=include +SDK_BASE ?= $(ESP_HOME)/sdk + +all: install + +%: + @make -f makefiles/Makefile.build-lwip2 \ + SDK=$(SDK_BASE) \ + LWIP_LIB=liblwip2.a \ + LWIP_LIB_RELEASE=$(LWIP_LIB_RELEASE) \ + LWIP_INCLUDES_RELEASE=$(LWIP_INCLUDES_RELEASE) \ + TOOLS=$(ESP_HOME)/xtensa-lx106-elf/bin/xtensa-lx106-elf- \ + CUSTOM_EXTRA_DEFINES='#define LWIP_NO_STDINT_H 1' \ + $@ diff --git a/Sming/third-party/lwip2/README.md b/Sming/third-party/lwip2/README.md new file mode 100644 index 0000000000..e5f0ca0eda --- /dev/null +++ b/Sming/third-party/lwip2/README.md @@ -0,0 +1,87 @@ + +# lwIP-2 from original source + +This repo offers a link layer for esp82xx-nonos-sdk-2. +The original goal is to try and use a recent lwIP version for stability reasons. +Currently lwIP-v2 is implemented, other IP stacks could be tried. + +# Notes + +* UDP/TCP codes using lwIP-1.4 need some updates - two examples: [arduino](https://github.com/esp8266/Arduino/pull/3129) and [sming](https://github.com/SmingHub/Sming/pull/1147) +* ipv6 not tried yet +* tcp is more stable ([example1](https://github.com/esp8266/Arduino/issues/3075) and [example2](https://github.com/esp8266/Arduino/issues/2925)) +* needs more testing + +# Tested + +* arduino NTPClient +* arduino WiFiAccessPoint +* arduino OTA +* Sming Telnet sample + +# Build + +makefiles are working with linux/osx, and maybe with windows (using 'make' included in msys from mingw...) + +get lwIP sources +``` +git submodule update --init --recursive +``` + +optionnally tune lwIP configuration in `glue-lwip/lwipopts.h` + +build & install +``` +make -f Makefile. install +``` + +# MSS + +Remember the MSS footprint: 4\*MSS bytes in RAM per tcp connection. +The lowest recommanded value is 536 which is the default here. + +# How it works + +Espressif binary libraries rely on their lwip implementation. The idea, as +described in this [comment](https://github.com/kadamski/esp-lwip/issues/8) +is to wrap espressif calls, and rewrite them for a new tcp implementation. + +Example with lwip1.4's ethernet_input() called by espressif binary blobs +finally reaching lwip2's: + +``` +-- LWIP2----------------------------------- +#define ethernet_input ethernet_input_LWIP2 +- lwip2's ethernet_input_LWIP2_is called + (/ \) + | | +-- glue (new side)-----------^-v----------- + | | +glue_ethernet_input | | +- maps structures glue->new | +- calls ethernet_input_LWIP2(^ v) +- maps structures new->glue | + | | +-- glue (old side)-----------^-v----------- + | | +ethernet_input(): | | +- maps structures old->glue | +- calls glue_ethernet_input (^ v) +- maps structures glue->old | + | | +- espressif blobs -----------^-v----------- +XXXXXXXXXXXXXXXXXXXXXXXXXXXX | | XXXXXXXXXX +wifi calls ethernet_input(/ \) XXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +------------------------------------------- +``` + +# History + +Original [cleaning and port](https://github.com/nekromant/esp8266-frankenstein/tree/master/src/contrib/lwipupdate) of espressif's patch set from lwIP-v1.4 to lwIP-v2 with references to lwIP-git-sha1 + +[Discussion](https://github.com/kadamski/esp-lwip/issues/8) on how further work could done + +[First](https://github.com/d-a-v/esp8266-phy) version of this implementation + +[Second](https://github.com/esp8266/Arduino/pull/3206) version for arduino only diff --git a/Sming/third-party/lwip2/build/api/api_lib.d b/Sming/third-party/lwip2/build/api/api_lib.d new file mode 100644 index 0000000000..52aabf1b0e --- /dev/null +++ b/Sming/third-party/lwip2/build/api/api_lib.d @@ -0,0 +1,12 @@ +../../build/api/api_lib.o: api/api_lib.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/api/api_lib.o b/Sming/third-party/lwip2/build/api/api_lib.o new file mode 100644 index 0000000000000000000000000000000000000000..046b01b4df9411805917689e30a2728146cbc184 GIT binary patch literal 2052 zcma)7&2Jk;6rc5OVz;4g`hh5_kQPM0r0zO)ZDSW1kw$408nr+gsi#`w-SKAC^{%zM z4hd8$2aX)MaO2LE8yAH51CZc=IB?<01vqkm-<#cuCzdMuui;sVNZcA$t~jzBpW}1T$T>TD#r3Md=;biJv^1l(j{V* z>fd0dwG_rVt60@K#cEU=rusD*Yw34stn<{NX8j>q^;=?A^-E$#?Kc=^oHMS}FRYmL z%k|Y);C_>>th@t?0ZLdy)E&D{MDr@N!Y-gSjDPB9(8}dw82q9n4s6-bL}zgp z2C?vMB8`dgL*B?Dejtt-?Pj-qt0{WU*l%~8cE8thdi}2Nbke7ln{4$3y)4^!Wn@-#ncL?4CIR?#|H>NTLn#7@j-KGhTMW8&@e zl<{fUfDWT@Ys=1wNOJWOII3UiTi@&~r_04B@*f!FUBAc$uK$8q9>aTLbF8P8(b5t(Bi zVb|xLK^s05R|8O<&vSmvG3k#*el!(~ZEbAawy%3>l4W_4M9%#!drsoOX}YbJyXJH{ zP9VIo*X;8f#e&#NxD__t4Ctd=#2FuM$K!}Znn5p13oc3&ad7Ut4inLEld=B6UzxCf(IFbt`9iTP-hih~njp7J;l z=u%|UMk$Qy%=MDVMBq%^LpfJhmcwiogjS=(Vt@XtFj@1&YbRd38I@zw1FIIkY9l5V^4lkI>P}}^#NqxK(7)gMaA9+ zSC~S-LN5_0MaAxc>*F3`Uuhf~mu{mPSDqKRlD`06Qv_Dkds5=HGIkb$A5^f65j|MQ z`w36y?XnLU${~FQ)n7#&8{UIYi7HKZTAc;O?t*--l3-OHS^bs%jJ)sQI}4?C(|T8- P^i=eEUm&2rHdXIGb=MW< literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/api/api_msg.d b/Sming/third-party/lwip2/build/api/api_msg.d new file mode 100644 index 0000000000..ec0b841fbe --- /dev/null +++ b/Sming/third-party/lwip2/build/api/api_msg.d @@ -0,0 +1,12 @@ +../../build/api/api_msg.o: api/api_msg.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/api/api_msg.o b/Sming/third-party/lwip2/build/api/api_msg.o new file mode 100644 index 0000000000000000000000000000000000000000..fc573b1faf2dfc60f73f395848d688b2ede3f48b GIT binary patch literal 2052 zcma)7&u<$=6rS~NV$-y4N{d=lRay|xR$|w&Ya1J6L>i@0Xw(8}q@J+GyW`EO>s@Pi zohGzWIdJ6IKcKh%16&Xn4*UT~a6lZmaODCVIneLT?!*&I6+Gq5`@Z+yy!o}yd9t~4 z%PFYt6Ha6jcUVGza?WW{Vt95Dov8!On z{Joa%-{>|~t}hN6BAfPF-L4Dlj*`O$`F1B^9F$|eAEv%DNTLn zHc#wszVQ?8W8&@el*!@vbbc}$MS^AfNt)ZoiFDNR)G~b>B^(}^M6s-c6DN$LFc!{u7R!mq z9P#bh&C|l}D@51AT-qyhM_I<)R74yvKbi%@kcyX>k4C9DI1%P4 zj{|`zMK)cO!l=$%FPTgP-o!nWdv#?w>}EmeG)gS?=f4V*HBWRq@uFu`j!Dh0iMh~C zCR^5`G{3sQUs>REU2`$n%A5e1^ak@blhuuK33?r)EO$=BuW6XN+o1M`*ie;!Rl}}^ zI~v~5@W&edRKxc*Jk;=5!xIhX8h)f=ST>DfBD!5`j`w>^8W*?ji1#)}eLjYgFsX_X1b)7r+%oU{$>bC0;9IXA$^81Gs==Gi=pm&?9_X1YM6^Q@< literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/api/err.d b/Sming/third-party/lwip2/build/api/err.d new file mode 100644 index 0000000000..b118c0e0a6 --- /dev/null +++ b/Sming/third-party/lwip2/build/api/err.d @@ -0,0 +1,13 @@ +../../build/api/err.o: api/err.c include/lwip/err.h include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/def.h include/lwip/sys.h include/lwip/errno.h diff --git a/Sming/third-party/lwip2/build/api/err.o b/Sming/third-party/lwip2/build/api/err.o new file mode 100644 index 0000000000000000000000000000000000000000..66d4c063981fb34ecfd0fa32a72b0cf3bf084046 GIT binary patch literal 2044 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/api/netifapi.d b/Sming/third-party/lwip2/build/api/netifapi.d new file mode 100644 index 0000000000..c338769159 --- /dev/null +++ b/Sming/third-party/lwip2/build/api/netifapi.d @@ -0,0 +1,12 @@ +../../build/api/netifapi.o: api/netifapi.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/api/netifapi.o b/Sming/third-party/lwip2/build/api/netifapi.o new file mode 100644 index 0000000000000000000000000000000000000000..3c7ffcfd46034d339ed879ece8fdf0bed5b92eaa GIT binary patch literal 2052 zcma)7&u<$=6rS~NYLm21suodHAuSTnR$|w&Ya1J6L>h%C5Vg=WQctzUyR(~B*Sps4 zI!#)n_Ru3oF5I{yZm4I3#GONt5C?Aj0dPX%0N-2B#N+f(p8V#0-+OP~{9Zra+Wput z45q|j_t=~<_H+pmld*Q0aFwmGbLf>o?)onker4O9J=jJ5PjX)KF6)U4l2R{f5cRsEWnQTrK&8Rw0+>laqc z`sMoCYjD5CR#rX)#Q+l4kadxIP`aFJ3DLX`t*{Gd4db8sIke^SF${ijnuK=Q&_t(6 z9)*eUZ6b}a@FU*HV}2-(8|`MdeZ47qPT;q@PP^Z0IlX?@cRK5>4u7xZ``5comFtVc zhR7$qR=4W{yQB1|LB73ll!US^4x-F=COj*S8}Wl^(wenSo_P)EY+?)ZnNM}WeL}ng zp0TnyS&yGiN3me}L7ElzNg^#yuCq)J;*`TvCQ)qr=DxjYx80uGv7Ip$^LQNRz=b#} zoLqQClqOCb6(Zy04{hfbOkVf{uiu}6FqskzlGKTkI7);QOp~%BG6NoCpXZ)I8$K0R z15lpN3x2{e>4%~?o(RS#Q6mvW6acs$W80gX@7q_sEY0&GO=IWgwmm0F=rr9{%UyRm z9VZlC;5GaF+H8I7EUtx3R|9&t5J}F5J4ukT{k^T>#*MvOyZd*xhPyj=wr+3i?hV$L zH*V|h#k2GAatNi}K`9Fm|v2>PlJLETc-dUaVn=((G-0a)^ zVjk@YZPm;2nzEj%K=qy|0;|S-7nuGRK7x{b1M({@eeB6kN@qBLsy=}1d+0j^q^Q_u z;0jadH|Qk-QdI0yaDCh(>?@5!}G9+XnekCBdpZvid81j=Ue>TZPiPX}xPu PdMbLouMnWP5>@X%$O9Ks literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/api/sockets.d b/Sming/third-party/lwip2/build/api/sockets.d new file mode 100644 index 0000000000..321e029e42 --- /dev/null +++ b/Sming/third-party/lwip2/build/api/sockets.d @@ -0,0 +1,12 @@ +../../build/api/sockets.o: api/sockets.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/api/sockets.o b/Sming/third-party/lwip2/build/api/sockets.o new file mode 100644 index 0000000000000000000000000000000000000000..dffa07f85185b2e74ca6f2c8c0c9c7956b09c68c GIT binary patch literal 2052 zcma)7&2Jk;6o2F0#BM{~lonA`AuR~{A+hV&wT<1%h%`#0K-8}^QctzUyW`EO>s@Pi z91^Hh4n1<@!i^jM02joC1AhP#91sUCT)6;84)EUWPCT(x!IR&--|xLQZ@$;hHg|3_ z#y|^$$1rCA&zCS_0kl=ZRak{H@D#DFxXs?gWcCG;OUeOIVavSza?f@zaqwJzoG$lj=fz!zhc!d z)mL9d_gk>C@*YwgpoBHdxcE8thd;Mu6LU{HxLI6 zkxzTAZr4NXjncyg`F1B!5|*vpkFvm>@=P8z;*X+ft7zRk^BbtZr%@wM{U<`^o?lG! z#O&r1KjA(m{yxt@HOH$9(%C2$kng9NbdD2gspYCw`Z!KGdQ=j{w(jgX8&2Enc^$`{ zP%)p!agJDuL+R$imrNOC^hPR1$h?QRa&Z|&aQ*?YJ-+}VD(`Cxr#cd&MP z{nqxNc^Z?w{AeQi2(8QtyRQ*#3wShF@J4wKUM6CW_h2*&hY=MoF&~XGad0BcGoFM3 zyA;{9Q5s`)@ceW#5qKuvp_;3w%HeDlgjS=)hClw%n5=c;wG%JijLxy>@f%_-ye12l zjVSf6F7Q(eoVIH&7Ocz(B8$#oe$iERRt`a@!^(2!4E&0L>2))D{wNNr&c9+{&%hl6 zZy5Lk1K&6BBLfc&JT~yez|z2<7?_sC)b|g;{}lSf(pl;qFTTn1&ib6+DD(8my(o|N zgtqFx@|tBmG)k!6rv+549`_w&^uO@F@&bH`qh2OZijLhw zt}%svLA^+z6dn5zxjF73?kkN$eC`n2fMbf@)MQ0z96&vX)6ok!Mur9WZbcj!BdO6#We SuAkQNDOk=S+Y+QtSMk%kZjqPCDm>IrMSJKn6i-nDku zApxZJ58%KRi7WpB65@vV0}$L0;=+|%xpIK-&CbM=aA=?W=6&CLZ{GY~Kit}V-?A*G z#bTeZC1dQ-3L-XRU72u$t+9*j3t&fb$8wQueGPI=IvA^2=N$NIR^w-QYPFT;h}G(k z!E9$GPD@sE>P?C@s5VUfdos?-pVByM)S==0C0YFkVov>AVpii17-n6zUTt1kwVT(P zYtO^|3R_)$2NVM+*g)1*>Otvht`eeo5n5wc&|20%&5LN|@-Ym4NtQ;gY-pm3w1}fr zgf5ZROoTCS6$w8S$E|L=-@Vxu18*93`(AfA=y-!+KlFO*ogRO)6NWeYZJis6!wBjVYZkgf)xi@Ub-iVv{1EXnLbT24v$Qt*!Jyxchl|q1Hb2bGb$GF zBq@MPaa4MR2+BB1y(BJ0&dDFS-W`~t3`fCmSb->A5S*r&7pF;_3U9hdWk+OAd4fG( zdPZINbX*TWc_A0UtZmm)3rcqg4^Y=3WSym4#q&hGxbt?};8y{(TocK1f>=QnQc zjN0ds>=(zgl22gEys`%x(Y7$3=F0p@Q7}Ij3CAs%ETVBt#TDk0NiGggg?Y}?NT5rV zO&g^#sxv>xW;1~^@sH$OeOV5(IVH3fEe?D9uf}9;xzeS_R_{f7YH*k@jn&CVH7 zs#ib5pE<*6vzB7B)g=M4=>+s82dC_c#K+!FgrdprRh%Vv!K{}AYbYvSe-|<`d6!hzaZ~Nz)MhCH?4OK QN>9bC_Z0%>Yt;4r1K(#9LjV8( literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/apps/sntp/sntp.d b/Sming/third-party/lwip2/build/apps/sntp/sntp.d new file mode 100644 index 0000000000..1f0eb9e4a8 --- /dev/null +++ b/Sming/third-party/lwip2/build/apps/sntp/sntp.d @@ -0,0 +1,21 @@ +../../build/apps/sntp/sntp.o: apps/sntp/sntp.c include/lwip/apps/sntp.h \ + include/lwip/apps/sntp_opts.h include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/ip_addr.h include/lwip/def.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/timeouts.h \ + include/lwip/err.h include/lwip/udp.h include/lwip/pbuf.h \ + include/lwip/netif.h include/lwip/stats.h include/lwip/mem.h \ + include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/ip.h include/lwip/ip4.h \ + include/lwip/prot/ip4.h include/lwip/ip6.h include/lwip/prot/ip.h \ + include/lwip/prot/udp.h include/lwip/dns.h include/lwip/dhcp.h diff --git a/Sming/third-party/lwip2/build/apps/sntp/sntp.o b/Sming/third-party/lwip2/build/apps/sntp/sntp.o new file mode 100644 index 0000000000000000000000000000000000000000..5977e2d1a43020ae7ed61c3348f2bf30079d83c1 GIT binary patch literal 32304 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/def.d b/Sming/third-party/lwip2/build/core/def.d new file mode 100644 index 0000000000..af7fa03afb --- /dev/null +++ b/Sming/third-party/lwip2/build/core/def.d @@ -0,0 +1,13 @@ +../../build/core/def.o: core/def.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/def.h diff --git a/Sming/third-party/lwip2/build/core/def.o b/Sming/third-party/lwip2/build/core/def.o new file mode 100644 index 0000000000000000000000000000000000000000..2e9b9ab3ed1b1da42c91b43701b433b7575ebef4 GIT binary patch literal 14992 zcmchd4Rn;%naA%tGx;JPb-wsz6FJzCeY|NnjOop~5= z^_<SE>hzvpl3 zn5e7p&-8;!PcZGId+~RTPBc4BE&h%VPqufKPb{rypXcxR;ADGUxxc;x8C-2`t@6;z zA8h)_6Y##a=lCrvoT4Y5f2ipfe&_v@2bFr=)8z!FKKAxYQ$KrhXP#2cW$MDcrGb*g zWmlCt?@(i(XU2XG~Xciok~?`y@&&niLo zX&>dI^O(QHQ+ndY@v$2=kET<}O(Ti;aBSoC(V@YCNPoC5w6JYK>-?5^&B3N%^SqY% ztqa-~hWf(&k%7UX==B?8!|}w(rerETy7`8&@f&qt@ltu{#PhYURUCJUf^U0X_r2sP z+5d9D?|i`CSnO%4bDHW7Uh|(Po9ff$`Cj+tzjyMLVKw)s zb0Bg`JatP|aZ8}=3LosQ_NY#;DxSA`iPPDsX4EZc{!L-Gg!JT=&G6Z*c|I|0(?Dk~xLZ&W-x3(B> zhxfzN(bgEeYpdMH_->DDW(fA#4qTnvadp<38Qe~paULf>j0$+1!U$45p1iq?c?y~k z^ZN3l@wD>z3Z7wFVV;+1g$2(s=F3~ln9sKZmOO>N2eh!@4{ne`;PY|r!Eyx@eZIYj zoGbGPa{#*<`MWQBg)yx zlsDjumryarw0Gf4X5n%P`uZk_OP$pow5jY0$W}pC>hyTF;@S-<)3!ifa23m)=m64j zc%6OcLRRz;4NtI~a!}DXGtoZ*O$i5;vz;CIk&ZQ+*yYGM6;f3^M!UPHu@_X%4k@Nz zNjtkKe*$v2f@##;-=QP!gmU&h3YlAj{j9+;Ms*Ezv<;0Zj788X``PdZ5Y-iWgl3QF z7%HS=eoVTleu&))JxYx*WV%8{loKgW$;c+QHd3a2u^efoW!=QvO- z%v0V%SJ4COMTnYwj817eCAAn)ky>)wb_X>KR?$%D?b{vYnZBoUI_9ZOz=#z)Yhb9n z7>bqo7!p|*wh`JMIjbj4 zT6Qt3)iWWRb4CTdDX7&9n&2JP%Ye6I*k!O0{^RU+({8`kUC+SkcAudRJ=Cp-r?H+% zl3PlTETt!tlhSqYj=lnvnhk$3JZi?EPve(x%{cToQyDbC7pkNhRdq9+Nyca~-<3>~ zTTjtotPQ@1eduOlRBx#!6PdeA0gOVaE>l;?V3|dCGr(XXnqtwDWXxP7eSv{nE1h&o ztz2c+iiH-snW4cLi?rr|+F4t9Zq;a(nG4)#u*SB}q_c5)e^fm>J1!h?%v0r2H|UTi z^4xN>)^xR8YpjV$x0Nbz)q^!i((YVb=fb10wkbe2&AqYAMkF75Q=z|hl1%Ml*UUW* zg;trN+ogImgNSBFlQCApjwYFdlhv?8B}NnJ8RuI59|r4McCcHh9jt7j?qJzo$PQM< zJislXhXLD|uhN(fHIrl-;uP|yF+Uh_2iR3WR6AR~89-ZjW`J#zO*-4#4)3VX>+HBx zz`FxHrbC)A1DLgD2H3X6q+1i&@x0b*IO z0{-+3#?|d+U=>c?Ra}K02CRgmzQo`njjI`4r?DGX?Q$yMu7-6CT*V#+6YyBXxN4V^ zX9I+IfMLL$4ozV&0`FBxXOb`h4>_*d4d6Ni@4*yjNPVzl^Euh|$c8L~M?<<0jJt@d zc1v-^T@%iyue@-8SwoHk!!SG@+eFt6Px%@zRms{?Hmb#anUe>=4rvbLOK0TqOp{-$lV>BL)jrK>B2^(WKL`VMr zDtB6KZFLl$-5SE|u2j08JjB@$N`{9(=-N~|8I2Eu_3X&wC@SxZ%JK4q;CP)PJX_&f zq#T@g(D^FQ!;$kI)nZrWGr5V!k?1KZ!1d-Lk7i$nRT0@^>=uF@t+P#Ey*kw?%14bo zJ|`d50OotQ6_sTrFo{GD(ojUcH!o|e2*+?;N8OAG$2Oxt8+QxZqAO+_<~Gm0q9m`E zO*PG)QpDq(p?wM

    huT^Njy5(namKr|kU#v_4&(YVeC&4ExX zIvCGN7PmlV(`^CN>kp+vnYiMj@5Pde!>iO#BAND&##68q>G$(NKAqSYiSrpQ+}t}l z66WgDF>GXw?n2F|hlfH*#ir$07#``}9Ey!b+_Hw!iFiu&Cr0~X5n2oK(yZ|K)gK)g zK!^2(QW2Fg$~tJ9ryIt$HySfFRPoW_zDQE_jSi%uH^MM3>G2Vi$@=IEExA>+O^$|# zM_77Xhq~>$IHpI_i4d&~!070_X4K2}l+Km0Xu3)pPNSt7!a?0vXj3rT=$KN=mn>Q2 zuMZ~^sZ=_Vhy^~k+@Foa2Lr)|=H`Z`!2J1v!AN)@99$T>$elC#U5+1H1aBnQ>V3X< zMSLKk)^soH?da^jdgYp)WxXp`^ekK5v9fz{)0B?R6^nyYxTm=Htuuv``RaLf?{nNq zdB3CMj%l6Mq0E6kL*9p}&-)_XC+Sm<`t#t~2I}+J%zJYkd>1^+Cc9@8S7$Ba%t!e; zc)qkC+xzgD%FRbQ^DyK&iTb?1Q1-W%AECZI8&FQRa(l1;q_Tp@L;DNhZ5uz% z4sBZd?O?hy*{95@chlOztY;TI9n;7hW|qs7Sc&2F2&qe*4e)+=>P*1XQLY+N+wW>QhoERRCU|(x+Pg4zUvD(O3njLN| zA~KRp@X(&)I8Uwfsdr9VX6VI}n{-}x)?`Hbz?F$n-)uNWhWFqimFc)C3+HuTL1rZ0 z%YhE^g9XaZWTphg_^~|Z}h7ZR!lDWS&kuPis?-3j?GVfD_IR!;;xd#;ftX!*S7h!I`{Z+SGXsGtKJjav?X} zr5v+twT@Y`d^)cN^GW@ShDQ+Uwwr0F`wcpj>3%cv%Z+{)LVDWay@~nB8xYb}mAH91 zZ^+dM=^Zc~SF@9+QPm)*GVCWqXBI+wt6xtxjhagxFuF_60qV2Q=&e5c$T8#2eyjph zze6zVPdTcst~ShFjAKcg8xYc4oBd=Ofg6IaG8`jApM5}Y_0wdG1>G2YmEkR9=uaS| zxB5HCtPI>P_$n}qxI^$ghN;HxaQJ==4(1eJ=F@S`SUyWI$J=2d9G8K^4Fs+p-s(3B z=F3(qUo7}a!5n+5qtAAx4jY7gP;gxEs9^SqwR4-``vpHN_;JC{2!57q=F$57KbzXTi-df+;2y!( z3H`8;50Oo|TLj-P^!JlFVc@<6w)68zq4PtssoNnT|A~;lCive3|AuVl&pTw(Cm#wO z-X?7w_#vBhn2Gx6w-iRdiaMqaGss4M0okmPijmr2 zp+;vb<)$s$g&llq&)DBXHg&ic%=)k`4+#B-h5lng{v?@;6z(s;b}b(gIzJ(s`n)XU zM}_$i6B?j+NnRYE>p$m@jsLLmu{>9Bli*IWndess=6%-6uMvE$VD8&iCoEX+KgQ;`kZ%>N_g!RUNf$e$3b{{S#L ze=FqA3I3Vje-f;27?^>;#kjBNJO zp9|J|nvuUPky=Xrv?8&@L|C(2=0mI|&A>=!&s z@La)7f-ez#x!{$8R|)2SLADNqg5!ddg89FY)xTBn9>Mnt=8r@6zWk)%9|-Yo&xkF%nPw*namkC}bc!l6q zf_nt>M=5K6P;gvuQt-Iot%7$5-X(aC;Clu0k1Sj6w*?;%{FLAy3O*>9zj9eSKNEaZ z@G-&q*@_Q?aOLp!JW~y}&lLI@)|_o>Ct|SVhP;$=u*sgWgQ=8Zrdj*?dC(~9`Wt5bt&X2;%3?h&*9+F?G^3MSPpjWf zee@mOQh3Wxz)Mq)v8>nOI&@Xt1Z2BiAIKg|gsn6YHQ-{aN zrd<7hp|SsG;{Jk9ycwG}Lch}3nGn3wFjUp;hS}eLPBwFZ&tjJOEJmIUooC2qJ{&a6 z^YUTCd?b0%FrVFjYM4L3ylR+lI{7Ok?eN{qFAdZFzZbNG4< z^HoN~F#CaL80O`i-DH?=eQz*46U^s0>agu!Hq18OW|(cf(=gW)&pFg*d%sCG^NP=I zmig>PMxg%EFzfsy!>seOhFRwq471LBj$>Zd`4z*g^S>Booq7JD4(rS_51H%iJ;Oop z9}Kh3e>BWJpaPSw((D6g8|LFP&pecKp3E`K_dW9svn>9TOdY<%>oD8_=J|*6CE%+J zcY%2pqWntmb%y!Ar`Isw9Yzdq0Bqp0)~VjR zPzUSmy5@SbJYDcCa=xpr_bbEfJ1b|~EOQ>)Jz;}jy`Nyt(~ZGfogISj61-3Fw*@~X z_@Lky$!sXxtMHb8Dfooo{}Qa{QPrKZHv3idn zl~e4K^u7z7+;(suw9dBoAOupc3-LKt38B^dE5q$3Z3_mH>zlfq4%Fk?e+6FJOC!D! z-a2dVA0QyNn}mB{k873oc)YXrehZfN-b9>xhIQ87aR{WnrW#j|_IMw+_VQs&+N(jN z9qHCtdwf?T?Zsfv_6_^d+B?_SYc>YBUa4mtqPn~Wqi5#<*W-j$LTJmq2y$8OQz)1F z9NSTC^w`f!j6I-sJPSN%n1Qu-S&qHA_)y1vg!ZNxJ=$B7V~_XIn4M%uN3wR@n`Hg& z!9gbt0qt= z=@P4Cbg0Mg4d(W$Q`bSSEk}>h*Nr`!bPx16{?^eJ-KzlEjtxQg`ytyg8{YN{&&M_o z^F0Q8zMOVY&i8-P-VWHK9_`h`TYFriqFdDgO!nW20xU8V#i)nTh!F@deEJMed*$%F Q?Mi#qm~?}XS!eD2H~CU~{Qv*} literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/dns.d b/Sming/third-party/lwip2/build/core/dns.d new file mode 100644 index 0000000000..f451d457da --- /dev/null +++ b/Sming/third-party/lwip2/build/core/dns.d @@ -0,0 +1,20 @@ +../../build/core/dns.o: core/dns.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/def.h include/lwip/udp.h include/lwip/pbuf.h \ + include/lwip/err.h include/lwip/netif.h include/lwip/ip_addr.h \ + include/lwip/ip4_addr.h include/lwip/ip6_addr.h include/lwip/def.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip.h include/lwip/ip4.h include/lwip/prot/ip4.h \ + include/lwip/ip6.h include/lwip/prot/ip.h include/lwip/prot/udp.h \ + include/lwip/dns.h include/lwip/prot/dns.h diff --git a/Sming/third-party/lwip2/build/core/dns.o b/Sming/third-party/lwip2/build/core/dns.o new file mode 100644 index 0000000000000000000000000000000000000000..80cb722f075439dbcf3b05ffd7e15446b0aac28a GIT binary patch literal 47676 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/inet_chksum.d b/Sming/third-party/lwip2/build/core/inet_chksum.d new file mode 100644 index 0000000000..bc010c8e38 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/inet_chksum.d @@ -0,0 +1,15 @@ +../../build/core/inet_chksum.o: core/inet_chksum.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/inet_chksum.h include/lwip/pbuf.h include/lwip/err.h \ + include/lwip/ip_addr.h include/lwip/def.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h diff --git a/Sming/third-party/lwip2/build/core/inet_chksum.o b/Sming/third-party/lwip2/build/core/inet_chksum.o new file mode 100644 index 0000000000000000000000000000000000000000..dbfea4a5b1fa8c769889694aa6022b18152da643 GIT binary patch literal 21132 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ip.d b/Sming/third-party/lwip2/build/core/ip.d new file mode 100644 index 0000000000..8f511c0a51 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ip.d @@ -0,0 +1,19 @@ +../../build/core/ip.o: core/ip.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/ip_addr.h include/lwip/def.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/ip.h \ + include/lwip/pbuf.h include/lwip/err.h include/lwip/netif.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip4.h include/lwip/prot/ip4.h include/lwip/ip6.h \ + include/lwip/prot/ip.h diff --git a/Sming/third-party/lwip2/build/core/ip.o b/Sming/third-party/lwip2/build/core/ip.o new file mode 100644 index 0000000000000000000000000000000000000000..74a670fb6124f12a6646f287ef69e97d18ff9a20 GIT binary patch literal 5344 zcmb7|ZERat8OP7Huk9Phag!#ct+r}j)v}Jwc9J@2vM!}*;%26Kaq~huL3_EeukB0h zYtQ#OO}dS-4{Xv{0Wk?!RkW$lu@40?#E0?nX+TGXkTw|NMPq1e(uy=BK>g5-N#*~X zdry2?i6M^SbAIP}p7We@p7Unsk?izgMNybY3OmW#HO4-(8JZwt8E&wLb+az^CzUb$ zA*sr@VXUN4dnmvqETDulkOdU&lV}zQgpNQS2t;DA392E>c3D7;yi7VRbd)T$h)#tX z8iR{~svhA&^)c#2h3#7a6fPBtwi`uAeH>21r;$Y#xY^zdU=1IpW-d{|IzAS{$WHCz z2peT>2jTY!*9QroCw%ZA;YsTG>XU@GK^h$WJ}{Dlhwjjq?!$PrNpR>ZgiO1a_^HnV zRqY%kp>sbWakOgMEc6Uu?p0y#S8HJ`K4R`yuj<*u#)VS=TBWsNt0t z$=z;%CDYOv zO!%EwfvWZ_Y{FNFwP^Vi3;&HUrY#{4U!|7a+6QFv{xxu)b`TE2*OTaFTf9LwQDq*L zTjN7i*{VDxygD?%L9mu)SP5{??mQ;m$4~j6~P>&J)d<1z&J%F4y zq9C*zv5q1cT{^*y3dlFpu>4-HV-(@b>s8M7)Hj(H1a86Uu5b5m}=xdk|VE7+lQ5j z93fV;uakU+7AX+bts;xe5v$rV$&V6;wH+8?B4iW@N{_NT-rE_B-xBZMiW%)P?d|qgkk=Dr9dp zbfZ{odKI(jgVo4L;>L2T8v?c**1%bLd9sZ zs%5WuAz-Cy-Edj8ZkH20qe!%CE!%I##aMYAU^Z=|s(XQyrVmxoTw`wC<#CvrT}n(O zGO3Z&P$F3)mlQq+?3!zC(lHCJRkxE>3;qm}mlMf36pmXQD~yhMP_|oyCA*%qY>e7W zmRdG%2+NXD#hlubu?%EFFFGJQTAYo#H#?e-H-q*f=mz&Jwk{T8V~f$&@Mg@?HM3|L zX{Tzen(OJzz;I^ofH{IrGQ-Kt=*VDlWOTTg9O@q&GWHD?i+hI$gl*AWO`A?*WN>&m z1x_v3*U}_gs9AQ|&)tgEEG8R9(_QB$ZP3e;Siv-{V$pQOz;D_@w3+onWyQg}$M?pE z?xM;2Ch~p&_`avs8;i~Nh!>rkc0QT$Lq@yMvuN)nQkJSl+4=AdoST}-Gk3jVwmYQN zz~17Ah`T2neQJJgDbKufFg`gcpC=fXtMz5<8~*@rjGbKJx}n9Ro$ibf;ciOv%VT3f zamx9Xp^NP*4xl%^{Gp}88>`Rf>1~@Ex+&IM%T@mj&W|6XGw8*H@|xkSu-4u|bl(~n zM$YF&e)as^+;scoE@Y=Rda@dHTKO6~)@hRmNeoPH;N~%l%s;o>oqzH%Ra$o43qIE@ zP4YW|wP^l`7QX>8S%)=@bsYI3#<=D(x`7#+nwYpJv8T|iJC0kgSCg|-iFU;u;Z?2JBFUKOLexikk!WzEzC_XEoN~q;R+m| zUKs0-jvva64Mfo(<*e6SV;QB}^va4Lx*k}H?}gN|QS>&dA$4zw#S33n69&{-Mu?FOkdZCxShyCk1790k^kFu1mZs z@xv0Ik@#tepOg3niGM2b%M#N!U@`tbOMFG*s}j=|5cV;NcS+nY@iB={NL-NElDIB$ zOX3G5epKSeB|anZQxcz*_&JF$O8f(fet7ee~|cXiT@$-2NL(HB4~71izIYMAdvfA#Q)={ zAL^H03DGaVGf@|5C;WX!R8R_kD?a!8y34SemDY;v=)><nU4b3NL?q$w EKN*ihvH$=8 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv4/autoip.d b/Sming/third-party/lwip2/build/core/ipv4/autoip.d new file mode 100644 index 0000000000..8b5108f196 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv4/autoip.d @@ -0,0 +1,12 @@ +../../build/core/ipv4/autoip.o: core/ipv4/autoip.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv4/autoip.o b/Sming/third-party/lwip2/build/core/ipv4/autoip.o new file mode 100644 index 0000000000000000000000000000000000000000..0bab9b3742c8fb4d3f44defc94d066920d58db7b GIT binary patch literal 2056 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 F{Xa%~+VlVb literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv4/etharp.d b/Sming/third-party/lwip2/build/core/ipv4/etharp.d new file mode 100644 index 0000000000..b27884d562 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv4/etharp.d @@ -0,0 +1,22 @@ +../../build/core/ipv4/etharp.o: core/ipv4/etharp.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/etharp.h include/lwip/pbuf.h include/lwip/err.h \ + include/lwip/ip4_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/ip_addr.h include/lwip/ip6_addr.h include/lwip/def.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip4.h include/lwip/prot/ip4.h include/lwip/prot/ethernet.h \ + include/lwip/prot/etharp.h include/lwip/snmp.h include/lwip/dhcp.h \ + include/lwip/udp.h include/lwip/ip.h include/lwip/ip6.h \ + include/lwip/prot/ip.h include/lwip/prot/udp.h include/lwip/autoip.h \ + include/netif/ethernet.h diff --git a/Sming/third-party/lwip2/build/core/ipv4/etharp.o b/Sming/third-party/lwip2/build/core/ipv4/etharp.o new file mode 100644 index 0000000000000000000000000000000000000000..0848f9f3de4548e5df4cdc1bbe429cfc07ce0144 GIT binary patch literal 46748 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 z zbxu-zs^US4&7MD=+v)h*fHv+qiYF`PuLWA2D#hkqfY{-W|Jl8!R>fV4S14Yi_zJ}v z6`S`0c%G;Gv67o#*%kSnO1?uee|XU5=l6=udjW~NU&&ukY~B%w&g)A4cg621{!lT0 zpwRALx!l{wvpQW+aaeJd;u94|6c1Ev-ZhBLu}WU1xLomc#j_OirxI=6%x|BH%~mCE zSIl2ewE7zqZzjv01Akc2>fE9DKBdFoT(mlS6!Yf|?S9c86~C(ZuZsVn_&vq^Sww4x zzc*|-k?#?(??9KLI79IXiur?zR{spe#fnEO9%8{Mw@QCV!nT| z^3{qrDE@(B{@|n4zg_V!6`OZ4QYQ~9`EM2PRs5vlmlVIM_zlHxEB=q-FBH3c4&HE;?d6Sa!$9!#_@OL;Z->>-Bihrm0am7z5=1+E7JAYC9hT^vs|4Z>v#h)ww zuVV8)OUjag^{h>+zv5FA4^*6|xKQy(#pa!t*q@^0GZa@TK40;C#r&aBo40nw{C!Qk zAA5!3A1J<7@ePW9teC&dY3E&Q%bq4OD9ndrj4nT%et$AaxjuG z|2E04d1@%f8iw+@@b;cNk8<4WS*8V)%h+k49L&5lQ!ag=m2xo4M`!cH{8?t%EHgdJ zOvC1r^=3Jun0Bq))Q_yYSUV%CF|oATm$l8)uI zeW0Dp!ohXHTV6qyc3-7PPRB|BU;JQV(;ve)M3zYL!*I;3O zoO_sX1Y9f}1(yg91oK@3IlP7`s znPKuYFh4U)t^{`oUjV+6jIyyTKNMya@%;kjEEhjxPiE8HBFy~XAWEzJDiFU2ELf8i^@rwLyJ9whuD@EO7!E2D((0G}iLb8xxv-C({` zp#6KmvxM&l^PK|a4}j+j{|d}^3Y2rKv!Tc;Vc`TTpg(ja3epwn!J=0q!e&FE~e- z^&b`91COX?_S&@%rVs^ zoCD_j1?uF2*9i{>e_xp6<%hx?`+TQ>-=a46_dA9AK+bmxlym&<6wU%aEX+BIpYf&+ z=cvboPX#|KJOs>l3e@44eO34z@L}PJV7_ah&J^$m!WG~n!ZX4C0CZ$s!Ox9b?jwvX zCx`D8C{G4Qgt3%&h6r;S&lf%gJVKatHAZ*<_#ELu;BsM>J`&W?{aczg2i0_)g(#!M_l`1WY|Zwh|~=6eUm4Y-&~g;T+w z3ikznDcldt`!Mx+uS*h+f>VVH!CbdehxfYv!Xv?_37-k(I|%BG1M{=`WZnadgiFC^ z3Qqu!7p?&F-30Y71fMI+dtIe)J9xG*?{)KpF9GvC1>_?U1d_-o;6a3Il(%X?*ta0579nDcF4;Z>Lta27Xz%6U=ujOm_wN zE#WJ`?+bIDIU;;B_&>ti!Tdf2V` z`~&b4!qdn6e^2oy#ak8cQ2dbMJ&F$~ep&HbiurtJ^Y)eEU?48fCTDtW$7edr!xWb& zo}{=^@jS(RMziw|pUW(-Rm^8GE9diTZ>e|1x76c4!naBH*WXg_*>9=$k8i2> z`M1>LbHTSM2mhDyx6w2ARHXgCwJ&YZaetkRY0bFa{lMz+z8w4(dQDVDsc<*xfteOtbYrL)VxdMN&a%=~G4R4*bcX=;+J78}uWVFX=+1lIQ+aAvU zX^n{JO;yyW%2E^I??doN(^#aFP03F)n)L`ws)XN_4 z%}|XwYmd)Bwl@#X9C%)%y}`Zg1u@T-KyID2m)pzUTl2j=2-@RbuC-^@ zRyeo)kN29*)|lw=^sHX?O7P&ubuR5i;H|ycz4G@W>^+R@*4g~=T?e^TF67n4?L{H8 z_RRVX=Qe*E0f)b#{x0cduipYZo1m_lzk$l0S@$V>tr(=g3l?E72YR$O z7~baZKIrLjelwoKl(`r`^$mKgKkIC|=KsT3Awt^Y+Sxj*_foI?dfEi@HT%R zLQm(1-xFUX_kG&5*SL0NoKgzm`e734!ixdg8wPLfecsDn_i5O-K|Nb%?U{A16(VdI zfc+PFUZB|OB_Xa(cjGF@S&ISAbce&+baS9*<1l_wk@x@N$aMDFiM{NFf8@0^lvqPR7<_`E$qXziWR%U;PA?8V_C?Qw6!=5J!J{LL(e4%*H-Ywzq{_6l!AUE_Ix z_C~>5do#rz=M=hY&%)l6JiGIp_UJF@rFZsZ?|-jThtBHp9TT>aV(wDt>3PHEZ@JjB zio2k4T86l+qFkJSaT!{{Oi%^2D!weczkU z_s(z5oH=u5zgLoXHa0J_EKBHMiF3qgN{HH1k>f=y6)MDZF-@!fzvI&V`#!qo$X|{= z`O4FtimEsF2ao*jm(O{`?D_)-YF~b-q&)Vv_xYG7?>rGH_kFO$^RqrtQ6BM#S-U-X zJt9)&TXNGobxVq4H@$rFHJ*zTB331=myYfeV(l#xBjxr7yFJU!7JF7jrcL@`XDAx7 zo@d^k(!6yd8j3v~vwqF=gf@Sy+zv%fSzKNHUdXl%P`J@EAzc zFC2+A6vc{)I~xjP4aKpdl2}7Ytf(~BP#P;Li#3!*8pWQwV$&u?ZVH5F6i?XgiTJ!R zpJ!L3q&gDbo->Xket#yZzlrLm=ddG~`DboD-+{ z(0TsO2~m4-LDOpMD*ClzH8R5$?;$^A*X%m_rWFmf-E?%o4o$Q!r2=~T62^fePrP#Q zmv8L<@Sf8Bbp`LBihmYL_uswIb0|?9Dt+4W`KB2S|1kwodci6ZM=T6@W} z{-Oy>f=`r&Vjqq_)NDnXMa9%m;llCdj~!~Z4>kJ^HRl~__D3EGSg%umNl`&tQ7Bea z7%3{+)lkyf5Ek=F>gI)aMJ)8h?E1+5V(Sl7{4dYzrSl`DlMXd|4mEpE?ktN<^`Qv| znHOnB_q-Qr_J+J4SEfAQ_Q>?o=cbn&nqK_jk<$IGXl+Oc zaTLKTtnDIXiMdEK)Zuy?{cU3{iNZSDgXjvM?L)N3W9K8f+}>qf=B)rROv3dmT&{kr z?FV0O+v5;j=G|rO@m%2(x1ktjAc8HIto1Ui=Hb#tnB}qZ>hc%`et^n69^X$<#N+Wd zL+G`Asllx9*naK+o`CPS@XizP|CK4*_bfGS`#G6se-;I78@elL$M&yfWCaFL#AjcD zn(}tz=6@fBY~Q@^fCFzq#aH_~pb){2X?rvKBX|OF%L&8=8sCbAB7(bUaN9iMPgwH> zD~Pk8;9c}1V7~2Ld=661B6uR4yKvv>d<&WvI;X?n4(9?$wmYvua)I+Gx?!7B1^HIz zAk?=w*Q4lWCxA*eIdN!?IERs&b@IU(XESos&a==w-+3ALVN_?Y_&lq-6gS~mP_~@2 z>6mjpig=v|A+|;ET3EE>bPOeu_proXp1&)Uu`!;exD4pyP z_MOxz#F#t?t3G=+Y!n2qfG>IPUBjF{7WQAU3Ua3h%@NL(FkwNp10uf-%?AG~t&mB- z{I60|1Rj9g|N2Q_JMauL{cn&1q2A5H|0XdMxE^}`_gJzx5TwfAM{pk(n9KGa{Wf?~ z(OZ<~ThAgYFZvX&_$OLyY`7@FoXOUBxHPlqr%aq+U4opsMJKa-h4m;B)x`tZ5#gUB z6S1PZQLjI0vGuh@Z&0nuIspde7qMIXH8SVaqA9Fro;4pirxg#53<&>xnR9wknrcfe zdQ~Ta575FbXCdLU=}yUE7-kzvIX0!TBZ9qD`pzz?bg@?2OC{#JnoPpRZHV&N>A~aa z!DBx_+Gjt2yR^(s7%e1%k5cJpFG!`AaWA7=s@5>O|H%(z-Y2+A1MDl;fUJK$>KEhK zo9u(}S%4+Rv2)mRnf8fsyOD0xX$$Q|t${$}We~}U6 z6H0Z9Koijp`~Y1MID?!g3g^L&9X$DA*m25`A)MW?U^%~s+~Z7#*z3GQ9p@?d=@b5g zP_pyqKhKJ}Q{*pDJH=IyZ*rYmLH#pb=PreF`72%L;_xoN z#r5t1RFl72dKWkYb>*+4ejsok+{)iT4hC+g&RNvS4`tF_B7Y;@2?g$>&2z}b!oL;; zCON4G>BKz{IsNXExSfq0B-?=&RN$O1RRT+>vxP=Ofv+If*~axz9O#2lXFGWuroka- zO{l`nT4`Bxku`Cc$eA{Y3mi-zCvhAUPd;B*EmC936cn&pEmkeNo=u4lvd;hM${wKi~S@+3RHo{buBg?~=1@7cLA6@gC}$fmT${Koesk@*(73hr9?SAouLRz1@3NYo3VsVE92~ z&6HW~-W}q25t$6(Zy{Xh3O(DAUjf<2ke#qV0c6tqS?Od}Sid-oSp@v&p;=SGw{UEA5Vg2LEJbSeBj|-NR2i&l z>!jZy?Va;1?nB6)^G5(rIQirgJ%ZGeNJT#eyiV|AK>rS?vLPK-vxs~dscX@BE$T&0=N`_&L9Ds~N zbFP%R!-H|ijSmWISF-Ns?si6P~KgYGvBF+$a3^n!CC_oHg=?)HCh!qTl$J}Z=R z?w9fzKvdrd%}_aaV~$uUp>zh6OILtI^%*Sv8W$F4r+aKXBXjal(EiI|@H@F2684M_ z5asb)uf7d8`%M;SV`XtseE~`q$o-hDb!($XqWU0m3eTWT&brYLqI5Hha6Oii;KmL_d3;)^z8D=*a3<^EIJj=qe9Fq|X+@gHEGe;0C@gclg~t`H znOI^KPsG5_6pnK`M3_4YG3s^^q^N;WQyD6mB^de3EN`LXoZ_77SV#s6gtw51rm}_5 z4o=7=v1!}ZsG?JWobm#U14;x&OBBq4!-e)SMvIhDpKG*Ol~Bo&@z#lxo61;wsZaV; zMhVm7EX&OpKOGrWaA-m$ETcBxiIc<9;fX%CdKkloj)cr*VsfpKGX;rU&T*C2XC}MN zJaKY~Rhm~f>Dnc-!g6H|&G(=ur>asaIZatq$>Z~tO{`gsC73(Y9Sllo9vcw3WVeMx zjcnbFOLtqsGwG@&*brtSLofqNLF-^!9IXJ`N6t$$_82cKM%zp;XHSKlHfznq_09&& znUj2?rmP%&HHScjxehY1J=Cgnr383UHQK(2C1T-CuCpDa)e1sUpazXX>h+8ND~x#uv7;%FbYpv8M6Y9IKLHQ8REFlgv=5fl|=ZE z94|%fTJ$2|Ra`L6=szXqs_ua&?@4bukRb!N`Uox*V8jo2;47oIaIuALxfW8lLMpT~ zVx{_ME?Twj`{;$TUKr4A7BLYXK?9~?Y#Dy}g&HCBNRDiAwr{lgH7d&S4io{%> zG$F~Zv;;d$28s^iGRBn}UzegbMs9Ad09`}3B4F=AsKdo4B)0!oxO4~u*lD^cbHGtt z3vkh-4s`$yC(E;^bntmu&tW7j>*K-#+~sF)9H6eDbh0Wnys1{C2D|!4x|3D?n^VKb zB&vqfLs?N-S%tse{*j~*sjh+HN<3v@ex4fb{=`uj8BY;sFBnn`wLQ$vH%{!})ZPEg((j$Bul^Cbr$dG zPxNNQNX-J|#$x+$|jM8I*3dwZlA?y4xnVH63mBtJ+&z z+B#gvo7)=e8#cJ@>q#e*@#b|+tuc{FosfU z72i!|Cv+z{AcN^-qN~s7#=h=!oH}Y}Q|*YePvb*9JsG?ja?ID(H;;~6dz+dXjmt!C zH?LA#bap5!OAjZuqNBQ9&8AkN29{IFm9@6CG@~;)z?p>@->#uARrj?B?YdYLPQe%#ty|;g;6AMOk^`|&*Ik_=w5^0g@#gGpqy5c>lek`g{w^y`a zLSW7{EsNJTG{jfdFO4s2YVK%kb4_De4t1#s5a$6jBs&frB>ILj*}=p>l2c+JkvY#8 zX3lDMP}4Gz$tJQRnK;*XCnkj$VXNYs;(h&Y1zkhKTQP6g<0(w1Vb|x}YLK&14pk;O z*d0$})Q1K$Nn@8 zjlgD*tIpj5u!5nM=^ILCFDUtwY7A#2-)JCY*}0VaycdB ztWkYbzXUsvySKSRqBogi=d9krTFyk1<>o0Jafc!2oSu5JQ*-;boL^k*a!}ej8b$Ze zNN0ai$W^Hxi7=*W=U*4^Sg*Kcr7W_taix&ul`bAhmo7aeT+x*t%4D)bL;cZJ%fq9I z!QN<1Wh_=%9i2Zv+MDd^>8e?jnC+f;@>`-X4sJZRiS^m!U?vf78tfSoI630=OWIqS z*K{<-o13r(>zmsbSLfF+X?<4 z@^mn-?3;E9Txtwz=tBM!tJA5z*M~-*92TF z%MXN(Q>-7)rJc&m)`4uIQ&eWMX*cfEq#i{o<+^a65-N|89dnXY@-aqK%I&wZGm{aO z>12OGN{_KHMtZCbnc1D}9O;esq`A+!MqEjX69#7=a}%AN>Exzkvax9&lTM@)gS|=Z zhg<9)i1-wxt)k_kvTJBy00)Vv+#=^`rCY7^Y)h6MplU$^hr=*B^?w8mU@q9=$kAK^ z;N|Ov5xnXJOpCnuroaqdygi!1d(8OLo?0eK$t%~|XbG>JZ)O?~(nj#gxjZWH3OueF z!7IiaDb~liIU4xTZw9ZNd!rJsd?hr~To*?) z`ndd$Pb&4;BTp^!ImI}?WuAP*kYqf~8Ybn*JbG-qC$0HlIC@~CE&PbU!ZaAC+C^qy zKaW$>^*+V?R^T5J4#-GwAQIsI+T&M&RpuK{#mAUC?jh>`K=QDVLwzG z`s8~R^S%oF}*#XPxVWeBRfidt&$%={0+tTBbM`Dweb!mr;M!I&iSp|{&S^68Ckbo&T};% zo>MxMktoji*)uUE`&k1LKKW-%*>8-naNJ~ATksnb%-Em$+ByG2C= z`fu^^7lHn39r~}C{%c-r@R^WLSJ9`c0cdJ@{hr!=7nERU6;rH8`e`D|~ z27hEQzr@k{{N6|N0)v+ryu#o$1}6+2FnFuMR~meS!TjNiuJ>Mp_Z$3-!7m#8hQS{1 zsGTB%%MG4w@KS?U8@$QjI}AQx@ShD{hRs;}-)8VR2LGGE7a4rH!Cy7_CWF6e@SO&K z&)^>!%wH^Of1Wa!U%YGis|Nqo;ExUVV;|M}{Lz?Zd{3I=lMP;K@L2})SAM!|)?og~ zQp@)ke4W9!8Z3YRqt*_8pQg*cVDM`Oe`0U|8@JZy*{C^e@H~V0yH0%uEe7jz2fytR zRz5Z@1pabUb2nM}HfYE*hJ1%1-)+eE81kzO`PU5jw+;TTq4Pt7A10&C438T8IGFxF z4*5aKmH#gpI`11?jB`@kIl7T7{^>=;~R@C1YT3Z%^S5+* zjvZ&Pe2!9ca+V>F8eC&Ae}$**EH`+S!SdNj+1y~rHyX^J>uEdk*-7bdGvpT6{egXQy*s*CT6TL0Gu^T)wj{<^_$8T@yHKQ*|3&nL=$iNSmy)betJ zscK;_V36-zYP|S&dD~Tjh{dVzg!b_h&|{lawC}Yle_}Ve?uTQgU2ae1)id~0~}Vo4$Qeq zeZCLzGYc}`+hU3n;Dw62z^5xtfg2R3!TfPH%Vxo?ig$q5D!u~DUsO@&YhXVAleyLh z6@L?)Rm^qIIZPeCGwo9RIGE4>l)nhxqxcWtFDd5wzE1In;2RYeAm-d=S@yxV74yA^ z^PF<_!F`JP85Do0NjX2$dqgpR9rlD`p4ZPP?ncb{PyHUmFDTxE_+`ZxAbw3T*X5rT zUyb-b74!2Lt_9j*JNS=AWcr@3_(x!VenL6lWB9obnQM{jg8VCRMDal|zipwMzSJsy z6?}?fezsGmSRh`en6}SQ%%34|BxBBVzIQ1OgHwtl;335`!6S;f4lYnU2YiuYejD@! z#e9#yO!4X9s}(N=U$3|kyjSsZ@NJ4Y=kHL=v+Ewk{Cwhvirc{tDdzm={}{0?8^KR1 z<~)B^aX3;%eNT(IfJh>_y&V- zH~3zI_Zj>PgV|}z{ipLD8>9F8V)ysKEW@DnegZb@eXs`Sx9aC2mB;#jZIl7xXY}r8pkxMZ z?^&>E&&Gp4*FD=&qVj0(4P3emP*lNQ9YF=1_bSq+y*k+Anx{P!$@R;}U|j|%hLDLL z5axo;`v4Nt-T~O-|G?4Sc$G*0{3yUO)wme8OmN@H-ISZh{L(Rcr%rW$xI9*m&**sd z&4o?STbN6Y`YxZ-4f$Qr!_egd>tx`wg4vE=;H8RtFx$cRG3K!yrzrn`GCT}>d@j;K zXcHf$tDHXk=_mOVJS)A`AhdTtBm2nBvFS%SLc6LZ*YZ F_uqj!#C-q& literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv4/igmp.d b/Sming/third-party/lwip2/build/core/ipv4/igmp.d new file mode 100644 index 0000000000..57b780e171 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv4/igmp.d @@ -0,0 +1,20 @@ +../../build/core/ipv4/igmp.o: core/ipv4/igmp.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/igmp.h include/lwip/ip_addr.h include/lwip/def.h \ + include/lwip/ip4_addr.h include/lwip/ip6_addr.h include/lwip/def.h \ + include/lwip/netif.h include/lwip/err.h include/lwip/pbuf.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip.h include/lwip/ip4.h include/lwip/prot/ip4.h \ + include/lwip/ip6.h include/lwip/prot/ip.h include/lwip/inet_chksum.h \ + include/lwip/prot/igmp.h diff --git a/Sming/third-party/lwip2/build/core/ipv4/igmp.o b/Sming/third-party/lwip2/build/core/ipv4/igmp.o new file mode 100644 index 0000000000000000000000000000000000000000..3d38b450e3802c7234eb7fb32eefc3abb3d69a3b GIT binary patch literal 36996 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 EA18ADLjV8( literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv4/ip4.d b/Sming/third-party/lwip2/build/core/ipv4/ip4.d new file mode 100644 index 0000000000..2b313081ba --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv4/ip4.d @@ -0,0 +1,23 @@ +../../build/core/ipv4/ip4.o: core/ipv4/ip4.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/ip.h include/lwip/def.h include/lwip/pbuf.h \ + include/lwip/err.h include/lwip/ip_addr.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip4.h include/lwip/prot/ip4.h include/lwip/ip6.h \ + include/lwip/prot/ip.h include/lwip/ip4_frag.h \ + include/lwip/inet_chksum.h include/lwip/icmp.h include/lwip/prot/icmp.h \ + include/lwip/igmp.h include/lwip/raw.h include/lwip/udp.h \ + include/lwip/prot/udp.h include/lwip/priv/tcp_priv.h include/lwip/tcp.h \ + include/lwip/prot/tcp.h include/lwip/autoip.h include/lwip/prot/dhcp.h diff --git a/Sming/third-party/lwip2/build/core/ipv4/ip4.o b/Sming/third-party/lwip2/build/core/ipv4/ip4.o new file mode 100644 index 0000000000000000000000000000000000000000..36aaa4ef3a571482740c310517ae65bcd81b2972 GIT binary patch literal 33820 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 Xx8s1@4-QFbZ&{^MzpzFSXYqdlh-J95 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv4/ip4_addr.d b/Sming/third-party/lwip2/build/core/ipv4/ip4_addr.d new file mode 100644 index 0000000000..98f6987747 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv4/ip4_addr.d @@ -0,0 +1,17 @@ +../../build/core/ipv4/ip4_addr.o: core/ipv4/ip4_addr.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/ip_addr.h include/lwip/def.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/err.h include/lwip/pbuf.h include/lwip/stats.h \ + include/lwip/mem.h include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h diff --git a/Sming/third-party/lwip2/build/core/ipv4/ip4_addr.o b/Sming/third-party/lwip2/build/core/ipv4/ip4_addr.o new file mode 100644 index 0000000000000000000000000000000000000000..0f80cefbf7f67471eed359d3fc2179c7129bf011 GIT binary patch literal 19832 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 UZd&g;l&*?e?>Pb#mm=%E2IM#xm;e9( literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/dhcp6.d b/Sming/third-party/lwip2/build/core/ipv6/dhcp6.d new file mode 100644 index 0000000000..82215c3f2c --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/dhcp6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/dhcp6.o: core/ipv6/dhcp6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/dhcp6.o b/Sming/third-party/lwip2/build/core/ipv6/dhcp6.o new file mode 100644 index 0000000000000000000000000000000000000000..cf993d4c31ee9fa5eeafaf4d2658e1b0c9b0aa2d GIT binary patch literal 2056 zcma)7&yU+g6duRkCf%j!mbL;^AsGouD`9(+CLsX@v0W{zEvpu~U8yIci9K;F96Pd| zunU#Skpq7K+_`b(4&ua-3!>t{jXwZRNF3mM&dg>u9NMS6dEfWmn>W8algGOU?-_={ zlo;$Iwq%Tbv4)7rSgTC9!8X|i_6XQ2xn*2OvT+5?wbH>@#W?pjV8y8YNT#y3j$oxy z{R7Oj)}o|f6{}jOSdD7KRKF!-t^HCO%c2f7>-UmXzb9r@zb0nXeuiPjCF8aF@r%z_@{mWZMl35gI}B`p8R#_Bw&n-fFh_o6R7&)oG~QK+HXn zPrJ=d#|3tW>9I$?!%38cvMt6@7C2L$6(?T&Ni=OPS|`tZ54xDxnfWZIdd7W9{4vj1 z*_^H?NN2-XuzZ|mg?*Yxi<9dt(?@a2;VF|S=BJtPqUpTj1!I5OaecOT_sHI{TW;5F z+s=f_`#g?w;6fZ1PA>c+N)soJ3XyU0hqiMMCNF}%-|H$y6}5x3lw>eZ$YvJTKBTcJA)kOOk|6!)-R* zEvMafLgA16MvvcIEQmdaFT~F1a-`?*x){*SyCzFB?VT){G#|qK5Fqh`a++m(GHxn_(w=kTAgNTYt%!k8F%+G{* z#*%OaaLN?}xIuAfdO0;l92mveQ?a+uAE&}x)e?9YD{CTpI#@x&MRM&+3F0BB;a z+$fWs)1uVBy28(|aN4e=m~3N7fJ{0A^{s(Zbwdt8r(?)+mo$7;!*s(9dIBIeROP>} zVOPU#4ex09j)p(f@Iws`G(6JqM8k!KKhtozuJR3p^BIMnSvpI(9r9gXc2?*7ip*0d zw|Kw*pGSK_TlKWOhODP5P`%F;fmP$a0Zji5??Oqw0eJ#T4?g)x=?wc&)d!G$2fa=} zii&*zt}umugT6>Wii*7tu8;c&`%2@`xb!uuam(`pSMnFY%Zk9NdLK)?C1V#6_(=t2 zjOctN?^j%%w`CtPltcO$s^5y|vEg0#l&I45O{=q@*d35BRT8YqBdg!iC&>E&zKc*= UH?4OQN>@d%_Z0&AZB+IC15C3P9{>OV literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/ethip6.d b/Sming/third-party/lwip2/build/core/ipv6/ethip6.d new file mode 100644 index 0000000000..8ca009ed53 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/ethip6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/ethip6.o: core/ipv6/ethip6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/ethip6.o b/Sming/third-party/lwip2/build/core/ipv6/ethip6.o new file mode 100644 index 0000000000000000000000000000000000000000..b25d68a31c19c417afddc95168aa0957793a8b0a GIT binary patch literal 2056 zcma)7&5zqu5T6%&o6yj7t1T+1s$?XfMZ)$bO+rEy#CEl;mah7>U8$!=FZPSq!m%UU z3A=5j_Si%J0JwAH$Qkv@AAq#t%7tq=A#s42XTRj_N);Vt-u!+u^X7d!&$f2IW{iOn z29IFL0A8$M!~kf^gln)0=in(~Q*x7C#bovalFQNoP+@24=&P{WZ|JF1R<01MRR2b1 zm@8qNL&dB%C|0A|XsW-EF<1VS#=JxwYUXRns;`Kd)t`v5+8=0uU0@$K*6K#%a%1%p zx<7(?{Y#`cKnZJ@b&+~ddO24KvH1YC0&CbZ_D|y+wsQG64E~}d4lLQwL}zgp2C?uh zBJM=^A$PNg&&843Zg$((o1$lr{dU)G_j@h7*YEmvXT8-P%~#5029II+Vx3S(i9XR+*vnPVQ| z)-OGSHu_Xt4M2H5&-sGmq#uj?Xet1JX!VEydI z&7DE>EG9eI(In?1w0TQW0^y45L{v45@gD`Dm1i`H3)3c^nAr zQe@LcDU8*@@si0z;F&mwa;}anhqE~;v=}8Oy#7~VvW8sh(qokGMtKbS0BB;IdQk?P z(V|qZdWyeuiqmc_#en*fATsC(7S|kPbyf~Rhr`Np7c~5yhUtYf`UId@s4D-eh8+!e zG`y+dZ!~;Q!w)q))bLot6AkAYexhMo5|iIR1aB$ynWeK-J6?R3mz~u)e^}PGi zKb3cke>peGK4d6|^ckxDD%Nnrd+1Z5O4FTIXF;)BNM5QWv?`Bm@$Xgyk1_8R!tLU!SV?AOGSPUjP6A literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/icmp6.d b/Sming/third-party/lwip2/build/core/ipv6/icmp6.d new file mode 100644 index 0000000000..a3f9646f47 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/icmp6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/icmp6.o: core/ipv6/icmp6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/icmp6.o b/Sming/third-party/lwip2/build/core/ipv6/icmp6.o new file mode 100644 index 0000000000000000000000000000000000000000..ef3655ba5be55e4dac8e8eab9a8ab63c2e4784d4 GIT binary patch literal 2056 zcmb7FOOF#r5bp7ev9lYN<&l>FF_98NBxYu9Y{yPy#IjmeOIAFxti&l+d!{`*%6P__ zX*;_K5;^9OACL<-?zwP>6XFLT@i=nh2p0}HKvhroy4M^KC0Ey1RbN-XrrWnyH!c~5 zL6jKeS2Fbo`MV4mlaPiWoFR+kAh`wD624`e2D0Fv5&=R=#(_Bql#J>_h?Gj@6X=yH zZ@@FHa+GjVvMNU~S1rF3rt%*etNctD>vQZ-wO$CXavwdbatA%5`WOr`4jbPt9Gy28 zjxQ{J0pV}R{QP-vVE_rMz&eIKkS^ycAT(crmdH_P4defXgV2iQ!!Ypk(~No1Xwvc` ze>iHnJ{c!@6ecXNapvBT1rhb~m`>QP*Qm7`=W49&41z|>X>{6kr`>4pM< z&=_`o8tFD5rt)e4UClq-1MzwYPk6^XkUdjn&@9`i<3JmNz!L zOLNN?*SobjAiMeQkkdX`o)vamA>0XDPQszRS}B>YTrpJaux# z`~5x-_XM}J^(zT!AIE`E(_Tyb9DD|rpzq;kNjdcR4$By)!#@kk|Q z4&BKN?+N_n{3QFJK@RF|Q2kaMfemj%Oo=Lu-?Tal%v}cOA4LMIcxa1%w<7rzcn<&` W0>yRXdKW?Qs_6Cpg@k?^RlRrb))sI8 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/inet6.d b/Sming/third-party/lwip2/build/core/ipv6/inet6.d new file mode 100644 index 0000000000..3991e9d645 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/inet6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/inet6.o: core/ipv6/inet6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/inet6.o b/Sming/third-party/lwip2/build/core/ipv6/inet6.o new file mode 100644 index 0000000000000000000000000000000000000000..26923437164e1dc8ea91a75774cbf1a74b3a11fc GIT binary patch literal 2056 zcma)7&yU+g6duRkChWH9mhw{t$w;LX3EP`A2}w~9+tsq#cGUvgm3ktY*b}dXV@LKR z>_VmX$bmnA-h1QPJBSlUE{KW)H~s*)aNt0{=Xf@=;Q&v0^S^`tnaLc%YWaD>`ONE26ig9KYzKT)%0iH@_R(`{wGt(gRjg{AVl}D_Q~j2VweoXete2=m&HAli)$fQ|)knmP+D|adxL~|lzqn@B zFV)vyhWj#GTYDcA1C+3atQV*UrI&LpAevX96?PG=Vfpi zqc9PHO~f0EAmUyg^O-pIT8&QYT0?Z5QPAo*tzNh3bbFn^X>T;!{M}{{TV3EV$8%DO_QP{ zGDked&M!Ru7JMqM2B5rvOMb#J=`Vylo(RTvwzjU@SN$x_bD5^Gb9={LkR)^(ZnNob zIPJC*3V-A`di?GAg4kJn88&?#(0fuOIUnpMqm&)&Zx1$a?BCftxVt^r+r7K}$>!dE ze`9s?#%{l{iexuG9!oximD$`LDn#4DT$(F$hk4H2OvD`D!f+Z6A}U^DJ{)FZb}Gy> zo`eEj=GnAS3Zpu6{d7DQI1~4%n5$cq!)%s>R-?pXfBd5`S@YD5CqBP7D#xS;KofK6 zMw#r47N!2xCH~wJr|nvZ$<`JG$fPq+pC&j}H_9RCbd0jx1r5KbVY=Z4Jpm9Ks`B5` zu&d#=hPO0)Q^Ox?_@0Ib8XjqQtYN9)FEw1Ot9S$9{GUS4ES+V!9p$^c=&a89jWSQ2 z-2DCicOLBtZPkC}HOhLb0@Zt{2&@|S9bo!z_y9`s800A|J^17&r8De9RUbh11bT%) zDJu36xWW|r75WN+QdH~~xIXTE>?@5!lt#x2eZT*;pRuPXwp>U~z?jWTu~fge?{ zj1iqJ<^6)I^IqA94CRnMfawSZOej8Q2XPDa-S^xk5 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/ip6.d b/Sming/third-party/lwip2/build/core/ipv6/ip6.d new file mode 100644 index 0000000000..8cf08a0dd7 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/ip6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/ip6.o: core/ipv6/ip6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/ip6.o b/Sming/third-party/lwip2/build/core/ipv6/ip6.o new file mode 100644 index 0000000000000000000000000000000000000000..dd5a67268f98d43ba06af35430dd5cd04cb0791d GIT binary patch literal 2048 zcma)7&u<$=6rS~NYLiemRf{O9kQRv_MPk>nYa1J6L>h$; zVp=TrAzL!W9Zm>;uk$np6l-#kdBH8*D&Gpj3SjD>VCt$^@eNU#cwvJ$> zQvD6gcGlulvWio!Q>;d{VX9w|an_!c#&M`a&H1%t)vt*;)h~!ywI5-ab=i8Uer3b1 zU$1XI3-^m`W8*DQ44_~QSy!nCrK`D?5Y2PY3cG^Vvi_=HL|ZN&!{C=>Y2=m-O>~wP zag>VCCDNFPFy@US;d61?Xg9mmc(dEoxuKXh zL^18Px?LaGA7v*E@*Pg%G*YcRj`Pr)@?4%al85oMwP?K}4;s+L#8&3Boa&1Ej0DF# zXJvD?o-mt@62Xe&ESK(CA}vm>vrHc+8HcA#qS)T;BX`Gb`#rzodJ`%Z@FXdKr8tpZ zAp#j^sh7l3)nAVWH<=={RN298NqRyd2yP=sqn_LwCsq?F;B41OV6MUpN{JR zC@cayWdlEBV0zgWJ$;A^)%mX&*f(&; zz&i$h&%k#L{J_9N1CI?nF|ai7Ck8IpRet;6{GURfS2{}DABPG zz%{1OFVJfQl<3&|;O4jz`%2@`xO5ZsxaE0)Yxx7$Qn5=2{Gfv>Ms$8I z?+KpGo2m~P${~FOHDAOgHoOO)7G0X|v_1=py$kZ0PJ-2WWX%`)6Y{=;?-G>OP3zr+ P(o-?(eU5-R4_)sc1m1M~%ucmO1Bc>vT~Zn!~072=KufJ?Z5?~G^SiMfCypE=)m&Y3fRJL8AD2k%*y z#k5%L6SicGJzhh^W~?m}Zm>0>wU>xh zs(*sn&RU$7tm0Jb6su8fnCiD=oVA~%ajsE^n)9n<)hEQ9>Q}_9+K({Ix@^5#zp`%E zuh%!9hx-+_zWxp<22ikutmmi)rK`D0h~^r!!mgmTtiS3TXyx)T41P(LMy_mVqO-J! zqf~@0k;X)XF>e$JpNrE*yV-5uYKopW4%=O?-S4%$UcVc9ovl`fzu5}ITivG44aK}6 zifOOa?fSs}C_8D8?{E^Qk!s81I1jxk&&$(B@>x7>En2V0g9dalv2*iTPW7Doj0DF# zXRFUYsUzD!lP5 zl^u~e<_R``=^3=)({Vij<%PWDXB?CMT$HC%!Pwr;&Rgz{AkT`T%(BG0yXP)R8hK5> z)$+HzPRENxFb*Dt9{Xz30lKtXzQt}aOnJ?_IMzk%=r@1nJR20n5MZ)npjAqd=rs4|o(I^-5 zb77wIG!p2t$fk|b7}c2{WRr=&nfNDiuD&dX*{ljJM~lOL|660S_PJY6d~tVlj!ln% zA@<6xve^YAO8u)V{FxO_`?VCCtuG0XO^0B7o>bjZL(uV9s@!D*Uo|k@a*Lh;hzr&E zuN&AmaL2$q27ceb9~t<8frkbj8+c;i(!gIBSguRHgK+*&p{JJ4Qf-HNo0pySIlrv( z^vNyW@PFsgp3qkPS6)-q(-o-RBTZoSxNiW{|HHdbl5aqMhNVZJ{G@b-1E}r;$i9QV zMnH*q7}Wp( literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/ip6_frag.d b/Sming/third-party/lwip2/build/core/ipv6/ip6_frag.d new file mode 100644 index 0000000000..ac6dc12bbf --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/ip6_frag.d @@ -0,0 +1,20 @@ +../../build/core/ipv6/ip6_frag.o: core/ipv6/ip6_frag.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/ip6_frag.h include/lwip/pbuf.h include/lwip/err.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/ip6.h \ + include/lwip/netif.h include/lwip/ip_addr.h include/lwip/def.h \ + include/lwip/ip4_addr.h include/lwip/stats.h include/lwip/mem.h \ + include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/icmp6.h \ + include/lwip/prot/icmp6.h include/lwip/nd6.h include/lwip/ip.h \ + include/lwip/ip4.h include/lwip/prot/ip4.h include/lwip/prot/ip.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/ip6_frag.o b/Sming/third-party/lwip2/build/core/ipv6/ip6_frag.o new file mode 100644 index 0000000000000000000000000000000000000000..584ebb00654954268aee58492ac2990b72f2e772 GIT binary patch literal 2060 zcma)7-HzKt6duRkChfB6R;7ZfLKumkR>ICEO+o?+V!K*a3)?@oEA@(KVvoI69Xqm} zunS1-1M~%ucmO1Bc>vT~9spEv%MEwH9bCY7oS9}4F507mPz*010czdYO7qx}0kX(OiaB*hRF4@lSmNZMl35gI}B`p&%|k?-R!onH$~40{C3xA_j@g;*YEmHXRFoW@3nmYdbg=^eKBi@ ze9~)myDqRhN>3W(I~+$zDBI#V%6wvt7C004q@1f;mcwjTg_fhlVt@RrFj;fy))SxK9hGC!BcO@7 za;r>sMvGGa>Iy%*!fC%2VzTuG0W#?jv@e*d8*&Ib9z&M9py5jzrdw{%GXSxnD*qh~ zyBh9jct^vZX!x#%?`wFd;XuP<4Hp{zO2g&4%6AaX7ZiGG=`7`T$hUdXS)KD6GEbe{ z{0;wq9_1$Numgfbo}$sx*Dm>MSUB6XdZn8B^;`NY@_vNxJe1Z= T>)nLXRnhBxivY!ysCxea!$uhp literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/mld6.d b/Sming/third-party/lwip2/build/core/ipv6/mld6.d new file mode 100644 index 0000000000..2766056387 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/mld6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/mld6.o: core/ipv6/mld6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/mld6.o b/Sming/third-party/lwip2/build/core/ipv6/mld6.o new file mode 100644 index 0000000000000000000000000000000000000000..e05d9ac815e00316c1c80b3f19095c86b82ae642 GIT binary patch literal 2052 zcma)7&yU+g6duRkChgL6SET~9LNXGCR>JlsO+o?+V!K*a3#%5`uGACJ#GZI996Pd| zunS1#z>z-yZrr(YMu-bnE})7(fGdIn7Y^_}duB5m4&^Ct-uJ!t=FM;C(ca-(hG8%z z2K#_58DpQXA!0JtDHCq74R)1%3T&0!GHxQ-_!(rYbTC#kE?tJNW;A|)r&e3rB37&a z1!h`nQBts)Rc}(PLA7D(-;lA^ek+Z2gE};<-%D2ij+j;dikQ*(35FS)#?9vSb+ftE z+;|4=7uovy8=x3K!UnRQrXG|o=UPHE&p~VKI$Fc{yLlCDxqJ+RUz{ePT{bk)d6GwA zA_AL;Hx)s|y*%a%aprYez0RGM=sT03({nn5e%t8}dV$m3Zg=^s?I5_*YpL8oEIg6V z`t4rN1$M{jsYkw}X_SPrEl#2=aArI!&b;`eXx6S;C(nEjT21W2e3nza;65k*3C~#7 zq?z!d*`nu77eNq|f`1bJ1dvLVaU(HOGSriO25m|nL*&mUq#RsPEwb~W79 z@UDj6*6@28eyHJ*h9?@HYPitwCmJr-Ret~A{GURfSUN|!9rByJ?5xiC1(~N#t@?KV zH;?v&w(3cFEm==hpn9Jv0;|S-1(^O9-h`5T4e}V4KKA4%r868tRUbh1E%YS?@5!pjO)9NfJb^!8)N`h5+Wc3&N7 R>8a@TzC=Ji4Mdjp{sk0F6>k6l literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/ipv6/nd6.d b/Sming/third-party/lwip2/build/core/ipv6/nd6.d new file mode 100644 index 0000000000..1a509b1d1b --- /dev/null +++ b/Sming/third-party/lwip2/build/core/ipv6/nd6.d @@ -0,0 +1,12 @@ +../../build/core/ipv6/nd6.o: core/ipv6/nd6.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/ipv6/nd6.o b/Sming/third-party/lwip2/build/core/ipv6/nd6.o new file mode 100644 index 0000000000000000000000000000000000000000..f14e749b137ea07d842ba6a1526bed9cfc2f501b GIT binary patch literal 2048 zcma)7Pj4GV6o2F0)Fz>BsuodHAuSSrip1{5u5E0P5or`cAZlsTNIhYVcgLF*>s@Pi z>?VNJegKYKkoX3O8&@R6finjxAr9R50B}O$0PoH2#N$W^p8V$he($|`^MCzl_uw7I z7-(VeAuJid<28&}03DTZ12*9ze2Ums+-6rXnSG7Tb>#r4u?v49tg*)TWNK^c7_8Om zzag{iwK$bfv+GTYHK;b4`d4J^wI|BhHg#y&zbaP$mY7}tf*5Q3hz8hY_EPi8hSj{@ z+}Hb+~=id*g>C;>j5Y) z)Ey`7ymoEt%&6@|>Q#J#=eEJ+%zM2nr&GztXk}j7V~uE=z@xc?H!ceBa*=Sn3FCP*im7;o`FNa*#Y&jxJdFf) zDYI$gG{)-S1=(~e@Ql0@HCIoS!`Z9|twoCszyGZ&Qb4n`8{5C)@S@em8Vbb-|}cr zXsiA!uT|AUqlD@`E}?4mxUV6j|Ae=d7vM`IKO?3OJ^4xL42P(?4?_3`^<@H;=-3Cy zHKx!nsMiQoqGRtPH^-H@uQU#gOE*!EtIi9#mOl_YuL)XR@1qKDRk2GL_(2D&7}3SK zyeIf<-mLnNp&ZgjsOF2<#0~GGPm3;1cUqqX#ok5onNC8h^T?Vn^e4>w4trD6yN{= literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/mem.d b/Sming/third-party/lwip2/build/core/mem.d new file mode 100644 index 0000000000..2074eb2045 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/mem.d @@ -0,0 +1,15 @@ +../../build/core/mem.o: core/mem.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/mem.h include/lwip/def.h include/lwip/sys.h \ + include/lwip/stats.h include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/err.h diff --git a/Sming/third-party/lwip2/build/core/mem.o b/Sming/third-party/lwip2/build/core/mem.o new file mode 100644 index 0000000000000000000000000000000000000000..765f6dd02405f0acf59cf06e01a10cca24ada18e GIT binary patch literal 7152 zcmb_gU2I%O6`tAa^-moCnO-D*D5)wW1eHLjf+i+Vf&Jj#O=DU|dSCBm=STE!1pgi^F!qAkXbszHF@VPQC#16pbstI-)@M4qUG)tt z{{QX&D>SH$tNjtKHpW#nSj;wez#X%#7eJ52;%~dEC5I|#isuRy6KiVu9-Xc6U%RU1 z$E=#-@4Bk#sB<=5LDkd*?k}9X<%_Ir>mO0YCvXWyk6`NNgMjuaE`p1(*INEg$B7a> zu*msmpw^XeMLO(U+ni&)2)~^-E#GE+o?|q2_F4jr4UTr6G+KKptl(LYXXiF{qxvaG z9d<5w-_9Y_m)UW(Ch-MIyv&)da?Bu#8}*t$s_Q=_+=8DY;-D;wC zMzwzDwC1sb`RYP?2KWTNLPbv1%RrgFHvnUEAsJVTh$M!bw-~9dQ z0b^QHw&tJhtM*uoX^oqpH4=zzHl__t(PMLi*ThoV$Lh!%U%Y6s;1S4lT)AjXZ1c<0 z7}V)cS2tN#wI{xPpkX21GF5!GFNUdls?>H;_YQEey>Y|)?DPAgo_^m&I^xPy=t8k( zjuk}VLauQ4ID3$Ud4G!e>J)o15qCkf8V95u`88b|>xj8NKe`dUp{Q2=XPIW^S7=)M z-_8zP-7yNU%@j+a8CnUmx%5yupFR_w8yXuKAKNt&P9ztzW8=xO$%)bA#N>E3xqEnY zcly(#+3c?I5#?sXGeco{bz*dUJO!LuD4rdfDX*5oayhp+bhZ)}%IReO?8xwVGR&{z z$Q3gAwQOjl9?CzPTQvs9LMp?vy@5FVa*ZE+h#R$%?B@QGWQ?$;83LSZX4*JCR(;7Yj=q zQUx3N_Ev7<}5V6OflpSJKtCTWL9WK0IAKY9tPEg3*j@GQO2kZY7dZ zj|88a23f!)mF2q8@)*qFg9rB{c4SJ$a=B70=99+`Cu)ttQgS3UI+_|z?%thT3NwqD zk;(L9(erYj4+*3!Qs10%o9FawVXVyE~7U5=%Ek9($d9(ihYK9?VL9(nR9?je(6Vw==Lxon)nn~VLf8BJ6Q z^XVEzr>gfxlhyllI_J%X3u{Z*?dg@!q&!cKsexmcz3GL8Qh27Wo5zGtPnXh#r4UQ@ zB-U|px2q~*YEqfv%1VeWk&2G{82+fJSzsQjHGl$x zPaDqy^Kq}me*MCa+<|$xq2G@V`MNcg?_PM-F+p{EYk$1jM-Z4#HnbBB?ZJljqt%FW z=3c~?AJMd^y}{^L6E}J<;=9%LMi+7)N6~|z7x9jMf7SXY>-xLQlTnwuy1Am0w7Opj z-0mTeEu$4YZo9Y(`}IVQ-hfWiN{E>m{gO_^?Oy0@0uGqt$cg1R3Fmef`$&WxN7Bx5 z#LwP7IC$^858{5*ES5wVv%|_GVkYznP7s5`Sh6UeXRwtmv6CFZ!^Ge-wk*n@AeMXN zS7jeC*K@$bM+B4hG%<8epk`5>Q^XR7FOvgIowSFS1yg607&;ZyEUI&sSYma79AN4^ z@8K5&Q-`-_Ci6sYakR$j_kMkD~|BaY|h22Kc ze0U#N*Y*Li9E)AH#vde>_-`j}1rhc*u;#?`gtFZ5JTU^ zO)xn-1(UOnSYpNeCnjfBFgY|`vx}Ro*~LoM>^QP!7f-=1Zh~EW*>7)zpr=1)8lJK z_5ReL$DCeIkLQT5m-qB|_N(4MMGuv;OSp0msF6pzjpFOQ1idG5W4vF!HdXH)us%aT z(~rhKJcmM_XTIKBSkx&z5bE(;TlIKG=@_`pU2yn^yqdy?8+eBxa7jt1l{Wz3&%3kN zn49S5y!>^e^QIc~euIwv=vPy{#~SqRK#%iMk7tOilHs8uV5X44zfg z({B0gro5jU3uHMK5X@vjt}?qg-##Mirp L&HWU7YO41?6xqa~ literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/memp.d b/Sming/third-party/lwip2/build/core/memp.d new file mode 100644 index 0000000000..f1f6fe467c --- /dev/null +++ b/Sming/third-party/lwip2/build/core/memp.d @@ -0,0 +1,29 @@ +../../build/core/memp.o: core/memp.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/mem.h include/lwip/stats.h \ + include/lwip/sys.h include/lwip/pbuf.h include/lwip/err.h \ + include/lwip/raw.h include/lwip/def.h include/lwip/ip.h \ + include/lwip/ip_addr.h include/lwip/ip4_addr.h include/lwip/ip6_addr.h \ + include/lwip/def.h include/lwip/netif.h include/lwip/ip4.h \ + include/lwip/prot/ip4.h include/lwip/ip6.h include/lwip/prot/ip.h \ + include/lwip/udp.h include/lwip/prot/udp.h include/lwip/tcp.h \ + include/lwip/icmp.h include/lwip/prot/icmp.h \ + include/lwip/priv/tcp_priv.h include/lwip/prot/tcp.h \ + include/lwip/ip4_frag.h include/lwip/netbuf.h include/lwip/api.h \ + include/lwip/priv/tcpip_priv.h include/lwip/priv/api_msg.h \ + include/lwip/sockets.h include/lwip/netifapi.h include/lwip/etharp.h \ + include/lwip/prot/ethernet.h include/lwip/prot/etharp.h \ + include/lwip/igmp.h include/lwip/timeouts.h include/netif/ppp/ppp_opts.h \ + include/lwip/netdb.h include/lwip/dns.h include/lwip/priv/nd6_priv.h \ + include/lwip/ip6_frag.h include/lwip/mld6.h diff --git a/Sming/third-party/lwip2/build/core/memp.o b/Sming/third-party/lwip2/build/core/memp.o new file mode 100644 index 0000000000000000000000000000000000000000..cd7bf641c854bf4a8b28b19356fed0353cb4c28a GIT binary patch literal 14452 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/netif.d b/Sming/third-party/lwip2/build/core/netif.d new file mode 100644 index 0000000000..451ae4aa92 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/netif.d @@ -0,0 +1,24 @@ +../../build/core/netif.o: core/netif.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/def.h include/lwip/ip_addr.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/err.h include/lwip/pbuf.h include/lwip/stats.h \ + include/lwip/mem.h include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/priv/tcp_priv.h \ + include/lwip/tcp.h include/lwip/ip.h include/lwip/ip4.h \ + include/lwip/prot/ip4.h include/lwip/ip6.h include/lwip/prot/ip.h \ + include/lwip/icmp.h include/lwip/prot/icmp.h include/lwip/prot/tcp.h \ + include/lwip/udp.h include/lwip/prot/udp.h include/lwip/raw.h \ + include/lwip/snmp.h include/lwip/igmp.h include/lwip/etharp.h \ + include/lwip/prot/ethernet.h include/lwip/prot/etharp.h \ + include/lwip/sys.h include/netif/ethernet.h include/lwip/dhcp.h diff --git a/Sming/third-party/lwip2/build/core/netif.o b/Sming/third-party/lwip2/build/core/netif.o new file mode 100644 index 0000000000000000000000000000000000000000..d15d1094c1051e00a43dd906ba00e8d7ee18d31d GIT binary patch literal 30220 zcmbuI3w)H-ng7o_Gf5^)fRIE4j5vV+K}bkKfFPg=gi9n`OoD8bJ@&;KV29Ilzeb<;lXDsDq@ePnA+g^OTRFxDFB#%$sOUQ zfL9w_aLMRUdGO+i9~K66IZ~Vn1F{}_`N_s37o~4|wenElx552&1wj^R^4>mK5SZ$f zdj+{uvga;;t#HHw&-)u|Wa+PQ`U`3Q@WaE8n~ z<+C3Tk2>bXI|cPlc3F=-oBr^V_a3?B)vMpxmNEQL;7Hby2}eqIy)j|^m|xY*`ylvw zXun1#vzcX*0*FMT`W80{!Uq9KtzbR}Mj67@dgk`3w=KO-k)_PNGR*XQqe$|oo ztBy?XPps&UyuyqFX$E8Sn_I``y?nAfFgN4LfF1D+RP-h4EHUQL@bJTh8HaCq;@)Fd zpV*f5STTBIf3Q3_w{-Y%8&2@Mr{v_xsT?eSY!dS+?e`NhvWq7~%XdwvnYVu?$_#Q^ zO=*f043IcYw|iOnOU4h2SMr4?j7 z7+C(|vxU*pdyHR$!r>V~?@ijaWM_=+43=p}4Y4#^gV(5)_XqUY&uv=M6uefj&417c|~3li`_M=@XVy0w2O2U`Awy zLJ0N;_IlKJE&$N_1&BL+rtQT7bNb9*3Lk~1%YpBN_w}P8mbX7}LvXKmV<-xyqwFGh zXVdB27~1RQQvr^4?t=GqibKP|dp%mZF?199)|C&jwRfsG>z4-a+Qaxfcvm*#Y`;#Q zHAH$8GCJyg9^U0o1vCE*=uce-%AHNNZ>Tc0ekOE&2?6VaPj4YUy#=WGD)zW?0Wb9# z7!P>izoHugft0@>OCXT;0))X(N_$t#1VU-EF+_oIN*2??Y2~mH2&J50EEGCy(?Zi> zJQRZNKhsVq?JEqt@b}P=l+aBmG4&dJq+JAYC}rkD;BX_#NGW^T)+W7**0xVaB>ghv z3GA3eY^Cv?=Mj%l;i_fCnJ6px*6qY)PzcTaA#hkIv|s~bk$+)lMe3llC-O2f?T%az zgP)4zL$WI}6BW2Bau`jxGIAy4J0p{kX-DKCd~T0iiqtD2e}RSmNECTvkzR0Lz@h6Cd7vUrIW}*pCg*^4PUSKFZjy&))iZeP|x=iZb{<#!nEW+W8%04Guno zcuI)FVJ)*05}8bTF}vgOx2)2;_{?Ipq|_Uj_GBgmDWTE$vZ&@ZOFqt+z^M>=sD4L-JJe z29}}w#%+g)?yPG8sqgah?%X^G4n>Ta1C6u2y1=f`*`NZg!rF$?<& zEwG=wf#~C~;QitiL|9UR6+Qwxc|8zw9J!6%6F!-idhY}Ff znhBGUmc{*h;(xNk4tvanLhM=S4V*-le9lFraAw~FKgo9U^H%dQ#3yrldN0`N`4Zx0 z%J*2y_dFhbo$%hkZ_$o?o9#WD?F~rtC$PZxJa%gtYF=<5maF%H$6*cJvT-WAb0e4s zrZ+lp4NQz<2X2I}?bsM#Jf8wM6n>YTO9c-Dkh=u(>1fvgvayr5S&iLDS&fuMNcsLp zQZ7ZxI;1?CoHC8`(hbU#k*w!Nj|0HN-y3)n0>5<|ZR{ep?yY`wR+JG{o| z7dQ{!UWOuuqkVTq`El-1jhTGHxoMJ*z$QuG&A<$ zgEQwMh$p?wk$%)>UB%Sg`S{>+-hxz&n^(-TKZS%PNZ@L|HaUUIoQruNIbj15zJr8s z+XR2GJ0N3U$6JKB@eZO{vLXlGf_AZ;$_H)7c(uj67eI$cqE~08T*b-yQh-D64_-UA zT)z`uvROLW3Eb7VfKdVCy&hN#9Xoh;BGC@sLxAzTb`CLk;|n1FIkLvL zEe_lWgMK|vNIgx-SGY8{@+3?_U9q*NAw#g%<0(3GGRLls>()=48Kic5LQu94Welr( z1sQoZB@S;h>kv}XFXz$XANgf85m`u8o+;`IQuYm`WGrP0hf$@>W-W%l>2VN8@{qS5 zX4Xbz81YSxpq6s$9J!UtTuJ9_KsN3YT(2VuBP;pA$!5y_4nygev1HC+zoN5BARM-i z(?Dvzg-uycE%vW3EWZqEH1i5SV!Tn_q!HPX;E1zEtT}U(mw6_RseBWOoDUJYQxL-+ z8VM=7lR>Qg)0^ZaZ%dB`>cbvdI5mQhg3 zl(A7;*U>3{<&YJZsUq)!v4hjcAe}X{>0^t$lI&4lR%*qVe_Ciu7?)y7vIFR^vn-6k zvc3Kq5B*tUt9$n6uJKG@%qcJ)DNk!19EN=p= z85V=*MJ4my%&=<{)i_mAjXpS#p7nX^rJgx<6EYF^P+{!&u%b?8SdIodhLk1Vm zy8+g5yF3dXx(uT5z5;0yJQ5i2yg60QI-Rrb?kH6KoOL>9UA#=}7E-BNR*EO(VAE$n zQV8#vx)})k2GoJ9%fhEGsuzhpxTYY2$}*U4aXka(hm^q%U&`QW_`yZyKw^(zQ^$aZ zlxHqy;B*u9-w0_8K441XZE`ZttVfDiP|+V^A&%b$64N z!=o!0tcxcAtV`sqPc;2w@M$Me|AyF7`?Qz0o2 zr-VNXYZ-hQ9u^sV3x4qUQJ0Gg!^GeLiwz8%ZesdS*WOS}J%jtL?gj=AFIGb zdpk0<40yRhM>4noesD*g3kf%bfSDPup_8fcOfp%997tvG(JhXT-_xx^ErWY3u4nLd z_`$`;AlU&QFvaoW_aS~0Jl6582nKw_r*-TP92`t#zHalTUtgW$E z6u>RL(1JRyz%c0Ni*4#@V092fuk<&Ic5mZ$KfSqalZbG!wa+-gt5dw7Nl!CgFfBcR zPcJK7%q>qw5!6=#FLwM-%IOeK1fYQ;ZrB?Pk}|*Ai>!i#5jj`x-Vic62l~ZrW;AEMBp?p?=ZohSiG}Hq=zt)h}M@ z@3Rfz_s3Z7rnaqp{hbZIq5hKDNcH>LPj6`L@_Tso!Zk}8RWdkjEzRwXGx|CjuV~ph zqpW0h+02rba*Ryb?836S<)ww?b7waf&MGdQ)i|fLxq0U75~thTa>b06zMk^Z*|Uql zMNQp1W>8kw+1|BTK4Wd|z0HL^jlHp*_F_=#e-`%jZkhovb!*^vwd|^kD_y6uF=#_) zW8YS3UT;fh_Z2PDJa?cs_}%GGfmnCUT59jH4en{&i7st6{zaf+Q%6f<7y8HcjFBysx>uL3u{&_T5c;`U%g`Ssx|eAiD5Q%w6}D{8aT0e z(eNvXxz*Tf+Hp5&=xp57(AwUCr6uiZZSQI}{&cUbs%ltKxu{`Dbxr-^TH~+RhS<&? z+^(1x3%(cQ+1(fGYV2%be%n8Zk>%uOEvuK9kJ}tfKO5>#5q5NQ_x3L7SX`B;lXuW8ld8eP+mU9#-iL|HO8V%#ox$L%q$3)UYi%=FJJMJ4;%uw~grYg@?%+HJ0G zU0s9g{Dg6?X4@KHX-$>g3;ixxxw>}M(%Qv!b#6lRwruNf!TNCbOJA*S(W;f$Hrc<@ z=iNP0{ls1oU%$1LmvFbm&ee{(wqMy|2kWD&%&%f%>>C>GR_PZZWryE*9t3rZm%6SWd{(dliEhL9PkzKU!!909 zA3MWvedmZ&F06I?8fT2{=ziBRNfX#aB9`o*TXyT7Re1L;3kU^?+hWrodyXOFIy?e@XKHW0JQ@V?JZ-QL~1 zHF={oX6d3u=S2%P^>+95#k#vY3RfT7JM?rQBeIH1t6b*pOD)Gx+?jWu6cQ@5aaSmna%1tmD_>GUHU zk(p}u8Cx^U0(K&r`sDPio%mXuREIglD^593pPk`s+Ca#H=-J|GGc9_q3 z;3t;FM|bL<1JAyp%_uw{J6*ZJA?>hz9_q{xmt|{*Z!qa-hdc(Jb_(I~5M`NkV>|2(_a5Oyg^YsWr>hlE$?b7B3c>_ufVs>S1ha_Uvbc#%D&T&LWlbK@MpoZZhS35 z_epuF%e<4}xl9>9-8I5>$T~1AgQuO<@FU=9hx5mA2iVo^vtT#Y`@pW;Tfua!GnxHB zJ9om<<7Z%K#v#eMLV2FbVKP=<`wv9e09YvUGX zsBdRytg*=y^~HMqu+5P?jTFg2r5|YWdB4mrHbqG~Jd-~n<4r$FXm4OiG9GerRT&~h z9W_a*NRcxrDS-xY&JH0(i|jRSh@`QiE<|#OhB=iu10Oa6$W3u#U4A5-#|W`teLmxS;)t zL&tf~Nw{GAs}WxowBPaR^aY6sC>THEoqlCfx*mP%^Sny9ASBua0vgd*9S?p0x=Vw0C+PcjvD!3z~(A zL{Kn(p1bs_r1T~B%VH;_HQnQkua-piWEST8WeC~o0vkWmY)0rD^>?`lLdHJ>&zlMT zDD%e2TZDNN&cgEwZ>G*s|9*JhW;@}taDVy{Lg$$NUoL`>@z;~$X_x}6-$n3QSYNq_ z)81V+evX;0rU>)TOp2c`aoWhjdRsmyKG9r`xNgrjiF0OTVf|e%ao(u1u>J-l&MytK z%vAF*;?A-B#}Vgk^7HUnW|}#Ylzvp=yvb$ZS?B}ASvTMQ3^P(qaoWq5I5~^Emc4S> z=Vd;E4|MeqFJ(i%(o4KS^HuE&O&{%H@1E=j zzXg?x+o@k-o%$W$sb9GIrSb$-7Y1LLxFyKzGxfGEkuCm~g*G5o?=}Zt2@+XOC6C_^ zlxpG~-jFXmea%7FgXH&HL){J%1-L80kS|G+)a>PeYbFPes(A?MJlWdM0#i;$j)*)T zOnEUvt`CnB9*$4ilv75Ih@5ji2NRi3VLWxoQG|4!920yJr<{%)5xKQL*NSZ(>QEM? zj>wtn@ec>!xGU$#*31*1%#)6J$ZWzGC1;zRj;%j*xL?f>Ip0pudGq~n3W6ML^*kN< zv`?nv=}e}KPy6H;LR)|SxdU7UJmr*;BO+(BJ$a}VYZC^>=B_gMc>}*;c8Ec4*$5$qBtZPn&MRScX zb?+4ZGD6$WivVy{@YJV_91%H9c$N5o>xQQeW#ov+_lSG|;f=zyZ~K|X;BJFwUdqT3 zkpoQ*j`|P*E@xzdy`{d4X*tXY#~^2v{|6*z3+E%W^HAi|l@2gI*2N;HjO@nR+Qj0Z z%&u`T*Cw5}+z+D&av-OR!be1I$5isNo^IU%jjMkLIEM=zZU;P>y4MM_-)<7-_}ro7 zwq4Mtj%^osHQ0_FCkxzcc-o|l?A8&wJHC!8z|^6P?A8(6?$#047j-BjyLD72@(m2( zy%qR?TMJKp%E%FsH;SC?9s}>u7+fnn^(iAqM7~YrI}mv;U=O68`OnPUhoScRaxcTte!WCrbS0SW#`pd|i z3~)8@*>)!xhLGOr?;sDu2iz|BY;X?3 zs}=7P=D6KXhMg}Wq<3~W*F9DY?jHDTFzf#{#SaQo?T2L8c@!bNvvYu)fe*NY@Y!J2 z=SjuS3bQ^hlVRr-g!InNF|rK$Yt#`wPKN$l2`{Vb-eiN>&zWS{&p}A<^v95~*U|BgpADvdp5g*wPL*OZ?C_uM(K|ckWZBc^QwK~t zm5TY#rYWbL)nwSIM@aANtR-V@(ygZsI2YWgxJ~#R$YW&K*@2MW+1W+r0Kx60j_`G4 z=F@AUVRWsToV9Wdv~7ZeW&bDn&a3_JHDq<3~6Bx7CEeVaPMsfc^ytk~|G9xD&W zu6NAh9gijRP=d>Y_r_ba&x=lH2IXRhd$nU8^NyD*u2sBF@kYg)6?ZA#u6VcNPb>a{ z;(HZ;Q}K@!A5{E|;^!6rLGcO2A1b!x!RN{G8(F6~CMhijOINTQU9) zG~WNYil-``t$2~*%N1``e6!;JP;CGGy3CVQY@%-5w<_MD_&UY6DE_kI2NeH6@j=Be zDt=Y*yW|usIJghN?(Q)hGLM&BxbbAsDOX%gmbUQUbGo}n9oXGH`1==5rEH+nwX>%j`;c}&K|BbZR+^Y1iRs1EzKT!Nj#s5Q= zG5Q0U2OQk1V0T}7OX-{>OSvH&<}R=O*YP6HQSx)hA}>-rhb(2y1GB6Gl)GH%)GOYg z^qWM#2>QKB=PJdYR{GbAemV5-R66%5eo*OuTlCL|{sE=)q~d3k{!ztmk)=OBB+I># ze?0H*jl;oC=S;HnPp*@YL)yFC2v&nRweII@_w?^`F6#RC_bq8 z2wCp2zXiKH?VFTKyFMVx-IZ(6-DA%LJDohT++8P8NA9lWluLhJK$iRJBI?L}b*0i- zN0xG%lzyw|pNlcQLh0;Le4WxCQ2eiCsl&I)a@TzX?C!chQ9A!gmO4D6^p7e&uJr#w zmV57eV0Z6L#kzOpjv|ZAab(dS52k($?J80_WlE=9boN1~l5%NFjnc1G`dbxWr}#^X zA6EQRve3*{zTE|o-kAC z%vW5g^w%lgLYDe(Bg?(LAMEb%dzH>jiti%xp%3mJC4W%y56SXk;op?}N%B%Z@6$?t zOz}I4xqrBN7Ame%e5v9d#WyIvPw{sZKcSela%Vb@{WzmKapsbCI_xsXeAIC~os9KQ zR}AlXj^cTW7b~t-yjpR+;#S356mL`9uXvB*YZZS^@r{b_A!AL_eHGsEHxz$M@neer zL-A9JpH=*l;-iY+AY(ny{T<%%2Z}x3&qXJ!I74x^V*b*U(;u(cJ_m^%`@ADuu5>O? zyh!ndiuvnV&i+Ql&5HTV?sV)kyOhNr&vEww`g|q)R#rC;L>ioWv2l*T!a{m5?WBc4B@-vh?S8-G^e=W%6 zovnC*;!4H*xg4ioqxfRQmnv>l+@hF2MC9z)=P#-AHA?;&#r(Y@r$3;Wzf|Pp-%@O! z(ZuGDm7G6lF#otrR zUuSZ8`9n;O`D1X7f35g=#r&lvr*mBKKNP>Gm_Oy@^hYTkqc~SFf9uKVmnuF_@%f7R z!%Xg8TB~@S;>#8DN1EInwNLStigzpKPcpf?D1Xk-@m-4VR{SrD?ent$64d?g)1B$ zIpX&gUSZw44!r7(zq{c3X!q_SO1a!^@+k*1T0ptn8F>G3?;Py?$DOm3gINxrOWocw zpK|P1v{OO3>=jj%gQ>raa(U*epojxcO>_mwU+v99Nc<%_iVKh?B-ZAHmDi1!OrRrYpAN#RB2V;N4i*@sd8D zPq}afS^B?9@iMaXe~seRWZ4Jm72ENW{$EeI@J6z%oo2;tWa;w`#XV$MQ!&MMyrj=L zUT!SxeG+Sfjz7Tb`g|!_`We4v6z|Vx$kLxp>dgHCS^Dh??)lO`_mQQ4o+eA5{DCa} zP>z9j?cGC`_Kx71l{QXO>$i(6ZQ;F_zl_GJW(l*nF~Tf@_g?Doku6_14}7lh6foca zQ>Pfrdv6xr8Uu)+9JXF4!dcqTYQn2)+y!b`woggM{&y#VuG3N94p9G@$^0bC`#5xh!x z3z&CT=IsLW?n>so?j*~e*(c0tvs;+k`=^E3C;Nq?;9G?`7QDOCP7(Oa!d&ZL6XyFs z-eaj#1?D}LTm$C!3;gjrPSGcX^T7PBfpYfYbHePy=Y=`nUKXAT{-f|T@N2@Hhy1NY z+F?KQhyTcYhW=3aLNM>Ql-GcV39kZY3SR^sEnE-gcNx^b7|gpanf+fNyb)X^+yv$w zm^#hi^Mu>M6~Y~0{+cp%y1_NVeE#NrnDT4DYlW`|ZxH@GxLNoXFn`~Z`UBuD;V*-) zCd+=ZU-2En=nlhQJf;rU(L-d}bAG7!r^3{KT$uVt$k><2zg5gTZ5B2V%Kt8mp*Qaf zbL|I^NFC0-u<#i02w}b#87s`Mcca2wYmDQ6wl z2(u2C33JXj3XcbO2y-vuU6*-T7Js&w%=z{?GK}PcdDkU#-rgb1c{?D?y!Q!n?c6Us zAN);W?gNhqb07GzFz4O@Va~nBg`2^LggLKx2WB0(-k%rdIrg&fUhp4<_kmv%z5&ep zF!SCDeqZIbGbfe*K zL6d1}r7-6}y>JwKnK1XCCSmqrt1$P{o#fE~xIKz_2d13o0^Okd5-SFWsT@DAITzh| z9VK(}z_Dz1UUTf-xy-%Koy!$uHVSSTygQdUmhO(hG*<^K-8kEFQCGTrc&B5_5;^CJ zlUw_8=5n8M_mGW>IVaqmg!91hb&79R%yD%(_bYycjI)yN0KDU;6dzXnisIvn-&btk z#fi-voSV*OlspWIaMKl+E3Q(!TJd_tZHo2#w7rzenC@5nMa5rL%sYeAe^l`kil0-= zyMfbxP4NlE_U{BZ_;CE+2)KD=-)o7yK*`G#S17Jgyp}9`ezW2p#k&;mBg>wDyW)Ek zKdAVJt2<4-w$s$x zb((rS+fJu`cJG6(J3mg<-b1Hp@91gjeR!IB=Wt&+jrz?yO+EhKIZnr3|7q&kef2cz zXTOs;4ZUYSpj7h%j5}w~{=FEaPA>*7j%)e$7#)Mmy4>mW66Nwa-j!?5 z62zUouYza8JLk%skz{Ybvd3pdXYWGju`ivy7r|FMW1`3C;v{>o!QOGm*)QBvoW0g0 zdmCYV9nzh1_2YLjPI1AioX0O_>H zXAfuZ-lY0XBTWN$U>@ea!RO;YyWNwUX#1NV04oIRfLy1i|%R}UrH<8zQ}ul*hgaW@`M zAm32yC<_Zx+j|uDmWjQo%HAC4VMyclLWqAIapzq9N|Wq`&^+FM zt1E3fd#jV|byOtAw@}%;GRYqA5{qa^oU_OOO%b_5^)b7a-m0i+_#*)qe=E|!Ts@E$eeR!@x6p& zru{$MsrdJg&bhR|C6&AHB4duBqgXEIt1CAZ;PTMMRoKkFND$}JJm@h`g~)p@#XB}6 z(jK>n_Of#m{|<*)oxL-X?7e@Pv46);d)T_-_6n2i-9>vtw6`G1-mc5>?>q2( zNqb!HNVezJT(RfQpotT3x0dHnsMz|kj`og<(COVZ)o&+t=%_=#0`^pP^K0mpQ$d_- zFaP%!j+rz9FI3h#C4?^RQt08oct4l7`2Y5c?Wlrh8mAfG@3=gOnpW8RA``{Aw9SxF zTp{vDVUK#Ww*;PPw8uvpHQmgIctO$6L~+g@!+;YajLkGAit)G*?A8a@b2_}XcRM!rHf)3#plt2gpK|up@wE;pB5G@b_2^S3zlAxg6RBF`+ ztru*yO$+t%R4Z-0)!G()qO}&ELPcx6Ra;8cs?~~?R#cSl=d4dmpgvd_WJZFZVt89& zq`3ItmhqK&8RtFt{+4bf)j{V2L9#Mg+<5SXzXrvP3l`>OG&UYA*dAUovi^#UL?Z9@ zU7sc5+i$w^h8tRzcHcdE(@j@ydAWFT+xTC1N#so)Iqs_LAjr9T)24&}E*$Z~l|e!G zj7v%)S4D#2p?!)A+CEx%a_d9Th8Xpp+P7deFyi?%?kfX!Qt-}Boc2W z7MEluZh8ux8srotlL!A@&^d9%*hKhus<5w%65-qAlV01qw`KO{pTPIbFevK$)R80E z!*=y~sq0%|yJo;pyO8(z-j{FucvbxVr@#O9<)6ih_a1z>GV)Y;Fzn!w;)3mkk?oOS z?vFEL!I&X%V(|2U3BeaCT%;S&+CXe2bp!iR{k1YE1Cq z_{2M75|K0iF(^^;tNe9OB!_oN4(YQ0_LkATo|_v>{-f=0k4E;smrUgCpPNxIH*4Q} zZJ#9)rHPD5-C${Icz)OL5484LWJ)-v>+T28&gYmf>YOs&i?&4dRCXwdCyhGo~z9GIPz3Rkhmgz*r~KWhZ^bp zb8|BWB|a?2q=n;&NI`k$qJ++w`*(f+r5oS6{Lrer$BSj|oQeLKfmnt(5%F9^A7no4 zi4^3;I4RKe$+2w%$98+FD-@EiwH5S=?cK}CJU6y0QP3;n#gey65{Xx<2KLS$)vGAc zHoOgU{gvV2yUxAB1pI<`TgJN?0cR6#3it^yHj;>708c6y6~$DVU3DZqy94nhK5S2< zwIuwM1`B#+6+985f#D%$Y02A3bWg;R6R#{QYk9X{@x&{)JOn!n^I{iH7+)DH%9s-w zpC6n3htDhXVxuD$P-d!OJ@H{r_bL8W(p7_T{iLIP_K*0pD-s_zyBz1@Q&~YtUdH&m zSn-6m@pEH|*wjb~>Pm$FV%gbGd{!h)^$tpT%79Z8J}|s(UqM@O#leAn zBgu+`g}q1h`lR5U;nOnC4;R*kO|_BmP1Zgqgzh_UeDW`xy$22)T-tR_pMhs##P)9w z3VLUJbW^vY%(j6yztp+M6+z>`rO-I9J&Foe|THJ3kB$ z(A38&a!M~?0kjxppt-uCjdZ$FNndM`RHtSCPC z^k3p1e0;xK`1eG5G{p+K2IG6hUMV@f-x!S0XPuM7+g`jQ{49!&syH|;D+d5@Rbvq0zfo=8!2 zR3bj?<*vII6(us`bg-lsrnj5dufd(qvDnM?0F(Vg8ZYYH{-j2cyvO&Uzo&)qRpDW( zwC0td4S5-pAB-2~ol#N{xj5|QG552i;8cAu_=R#{ui zv@lYe<<8hG`@Qu{T7Tl4AbZuWT5tNu5jcb(*A>h-tZG;qc=mCUUNCk~q|Zl3P9HE0 zmy}>v0;?Qm*6#8|?o|o&7-s6DZ)YAp^2*t$wJ0H1f%n*=Dd9=~c&9XHcu6#v({*5e z)=5VWBoE^J*mvOId1vp%wfYNZhw+2w$lI55#3L1L2Qkl zdvQV>IGC9kOv^0F9h;cfd07~KzGR={d7VdvlS^_E85mrtZ(byO zRZ+&S+Lvbf{zSI~M-ZYxxGqTG>dQ(roP^ZoHzD6kkD+^mVTiHLc**S&%RsUTC&-r_ zPePBO3*tJ&81C;_9=Bh?mdJI{P2u&ieqe^4i1T36=@iF0A%9);8yTCzEs^WtfY)Q$ z<%r%E?`F0{Vw~7Y+vydNxohB>Z&P|U6g z3K1D7_%l;!dvT2U>!R1kV#fjKz&A2dZR4>UjV}AZ_Y>4oZJ}QGlwNu~`a#CP<4sJp z&W?7xZ)|&dT*}hEalktGMqQlwss7XU()6bAx@bG!hNSe8u`E$&@B1mK<45;h=9>7P zl(~lS=cXMbg`xdWZU%ZCH;p8av#N8rvFOe{F1uBSy*||(287E-mB9W|1k&DJMmaS+B zBIp&&kw|t%4a`Ndv--eB?8nsmcnYjUVi|pziN!t;wb=JiHY0{&zZP-U@0f(yJ5YUQ z?As`jbsb(}e?UHZ^El$SVK{clVB!==V{7^oD`76SR;KOWVIp?va7w39VVxA)OzHZ0 zls*P&MhV@?j%AjNN6GjjI2yzk;Wdn3N6+J&#L;*!xEG6m4wZ~JZ!|LF!=aNEza1vB zK>q1G%M4dQ>q>&EyIRInj_EsCv=e-n~* z@kSWEEWQ_gb!q%E$k)aXKz&VoJBnTszaB>~j$a4O)$!#h+Y&DaH^;BR(Wdy{pt&l3 z2(OK3Pxh35u(})Z62yDJR2bha?b(SU(fIQa$AZ`gu$Wy#$55jFMARGq6^;b)=b#nF zUxFYK?~BsWAod#M+3P-rZl{wW>5_dt?jwSn&MbTbG04eTLvSLei28StJ13gz7YErpsFRBk?~l@%v77MPId>mw2uDY#7XBTQ z;~JS|ja~i@1K{7{P?tv`P_?eCBs?=hYhCG7I3_}`x-KD)6?u?Xg8m3EiqTLw7zd79 zw!-JT?4p5-Vl>cYGV8x6MwR@Pt6PF_c?=g;`p3hWu~Eom(cx})vD8d=6o+`h30v>L z;qEk@KF~wV&y@0gpme-cF;l7tt9$+#CBiB>Ivz()SQUiTVsrs=!HGAcDuzvnVe5NP zKIu+~HXwV_j{&WOUjTLidOZa=2`%XL9AFCJPXJDtp!YXf(QVSR=nJ_3hOMiC-Os6ruw0VI`_O?tth^5^E+~YIUD7wK zjQ%sMq)P8OP!8|t;70^=lYZPGeso7!=f@r5#|-3Cek5Teyvz9!N*^@hu=v4pNgn^7 z{iqIyS!Z_8ncs>tTq$|=2wU$`XMQWrTo0o?WsdEMwBh(3x}KdO3ZD@x z<;W+?pmqZ1c=);$xdg&~T)ZNvq~BOT9MFFOpbOw;)YmtxilFv_2FM0L1}B+EraOix zJj99X?Aymq7gqIAoD;yp4e?&!G-&Dj2%xUm_Cz9S62b(NOl~F-(+WoBa zy)YZ9ylDzshvIt7dGlV##%)CL9wEvj--hG&BF~|EUyi#bbQLYo&sQd)3fMJ2?4MRRS zjW_gRX_RjBo-J(MriDtQbbBe3`kjCSGCg?CaC!u%J;q|Z+~LUwF>L)4i!G&$#kQhY z5mqRd3#(2*Kb$K^cvT8c+Xtt^CaJZL6dwZzSiDJ;{sg7&DDHAckn7J0M%PY*qMMND z1UYdFk~qYsYOe&n*|P9Tu>?2e-Z5;wnKi%-CqE7P?EbHbRy}e(cVa-ptD;=q*C1a| z3}EM`%>D%p3m?McCofs^3x5>t1eXpby5?;+{+$7y;8k3THE{x9aw z<8hZC3Afy+xcrsK_gew;m$9FFkDyZ@NlDhpTh_4kKGfNL;cA@2A4whGM429o+31g= zyu9pXQ)Q%G$xif9P9K*)3we&n$5Of(xt^S!;U`khRm^Xr$Dd06PUe5bwjY-K&yX+R zJsv&m8&*d)f=}cHksk79Ic$w%RX*u3MDIcQq%6#nTuSl*Ljglh0fdzWc~Bk;gcS^B zHO4jTpJ7#}BS%j3gB$ebLLaV=`CjMEcG!A5jJO_HFW1cqjH_6cw$+HJ8m;6NLrNviBel79^6Jf@-xc4S@(LLf=0>|9?{03B= zWA{i^KSAC(c8@r=m&e7id&Kl%9+#nU`9hc)oF9SZd*yiK#)&9ap~2mC@1|)1Jd)XIZ3r%?CfO_7Yss9yF0Q9ozC8#)vmXLVWX*o*z+vTr~AZ- zucL6!-4KTN$JoFJnWrb=gK~U7^8M%HIQ!=rC}2D@HwMmfRRlK#1&uh$Nx>uQ

    0s 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 I5u{oCPiYfzi~s-t literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/stats.d b/Sming/third-party/lwip2/build/core/stats.d new file mode 100644 index 0000000000..0f7158ca39 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/stats.d @@ -0,0 +1,12 @@ +../../build/core/stats.o: core/stats.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h diff --git a/Sming/third-party/lwip2/build/core/stats.o b/Sming/third-party/lwip2/build/core/stats.o new file mode 100644 index 0000000000000000000000000000000000000000..ced31395d3f1eac911c320c708c9edcdbbf96f6a GIT binary patch literal 2052 zcma)7&u<$=6rT02Yque8qJmmfA#Ejo6p3BOuI<_&Bhtu3fv5%2NIhYVcgLF*>)mK~ zoF;%&4jegh;l_!-fCJ)$#2c7G;Ytwq6ac#|R z+-z)Ihx>W9w)Q$G22ik$tf#35rK`D?5Y4mD3cH5Zvi@qUqb-+@Vem_`G;+&^COS`x zI7&t65^2sv81rV4@Dp*??6i8FJ1x=oreUY&bq4*m*B|skue;Um^1JOYywhvx+)$h} zMRDA3_j*3CKgmv;b$nz!WkZ27|!@MCqL1G|jv?P2yB|(|KBUMCOzy z*z~1m*nv;S^#GI?a>>s*CjFt1XUBrE-JP9R-P=K)6@|>Q#Jj)iE=d}BEx+CNx4drG zi$pLDS_A&_VnOUFTnd*i2K12>X~D;P=`>@92cz-!y@Ln)hYv^N{k?~y_qO*BhFe#* z@9hm+SCH%%XEVtsurgoRBaLWVm``(M{-h|FpNoX!8cgQVIHuwX^T{L^Cl|sz=V>I+ zWsyxAr7@~AKgeb?fiv+>%enexIm~8NXgOLO_Q&5EleI6rcH)aSqjPL}{D#;ougPYY zj41W5t?6eeB6kN@qBP>OO$%Yv_vvl<3$y z;2Klt7w8QFN_6aPaC6*K>?@5!Efu?p!1p?+Vnk0? z@_xkAc}?{pLph{RpysPs$A9bC_c;RQYt;4r0qo-x^Z)<= literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/sys.d b/Sming/third-party/lwip2/build/core/sys.d new file mode 100644 index 0000000000..8f09c96a0f --- /dev/null +++ b/Sming/third-party/lwip2/build/core/sys.d @@ -0,0 +1,13 @@ +../../build/core/sys.o: core/sys.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/sys.h diff --git a/Sming/third-party/lwip2/build/core/sys.o b/Sming/third-party/lwip2/build/core/sys.o new file mode 100644 index 0000000000000000000000000000000000000000..0bbe00e19ec9a284e234383232b2c79eae44d6fe GIT binary patch literal 2044 zcma)7Pmj}95T6%&NlHpsL{UKq)s;$1rP|qqBqXg;u|&&i%L>{qD{*S{V!wE;I(B3` z+f6~DAD{=0^fPefz!CTad#P0Q&>J71Jyq&~&OG~VURFXd%DnmgX6DWN?>yYtzR4H^ zB@BLm1p|1nf)N9tB@?c|Dx87`h)u~&_7NsC6Pt_D0Z?Km{zX_~m6v2nE9Wp+DwSU$ zGt8AB%AjPHYZR+cZ8YU4WXzS{r7=%ahl=@^WaVeX%<^x_CD7~1ggxFj_Ex}oA8T+qx3R}5+90q@39Ql@PXri+y4g5%W z7Locycmc1cA>SACdaKcCU2TZ2J@#51yVdJ9?QXB*+3mGvn_p{s-qlV+<$7YjF4AeY z+37flol$&HC*RH_i2S0>_JYK-r##8#_3)=)+RR%!P24(aKCz|wET+2TJ|gZOPe3+D z>+#~*C=`(H#YtuzCDP)Gb>@BIMAXxH>bNitV~#0 zg+3Km15lpFGk(Nz{y&RsJ{16)gTa^96*q~~G>hZVzP)KJNaWiMr`dGY>~`Dsg*$c| zJ^p#VAb20Ighkf^^h$@@(2D zg|Rv~ZakR?JQL?Y&ef6Sa5l?Ai&0|2->(%WYb?EV;`w_~IR-s^O^jnN$$%4Dl=_#C z@%N5#+O35cP+bs21|30u@nmIIl&6DXMX56yKBr-N)r_7!iiN83Khv3i9LU@Y$DS<*%>|5jtQ|M3B z^8^Y}v0KRXai_SiG!BhRH&Kl%&kMPde-Kh;F^#CsUd+R+$snv zQngeC)Y_Vsh}GIwYrVF%{#tDPd1fn?=v&IXP0Q-_y2z0 z&pV&YnP;AP=9y=ndFGipbI#f9S-5PGZQGU!wsoPE%vsjv^~gDvHC+gz);Fv>EvpKd zV}h^-22|R7a-it_fmorn<%5CC-Wxdh!NB(X%u&78GW;C{)TDoBU1HVST)Bz?nt}$=LLWd?bJr2>Wn$XzL73I^zv1McTXOQMC z(u6#VJeIXLW|vo16g$85S3Fsi_vlbIoZfhW76mfAko)X=15XtNDxUF_|Ke~}_;}&6 z%*v+5cYSpse`rC~!l9wc(88)KuQ>RRfx9!FK4kxcEq&WuEW6~U z`~wSGGW=iNAKa1g$P+E4)+5_C44(llWSkl`?K9(lUYT7u-imctk*4gTKMquSp7P9^ zZU0fp%}z!7-}iZNJ++_k2}=Kbu9jbmYk3Wjlwaxabvsb;Lhj$Zjhw(b+R^2-JEiLo;vi?4MvoV~yRXLNWVqZ2m=0;URx?*`(!>(bw-6DYD!j31vl=XGKDR$nromG$|WYcXe0%ejw^RacFpS_9W+VuT>d)BHvr; z?6!s>`A5 z$I-7y|GBsIE<_kHC(3BOc8y@nY;37YBDrmcm zBB8N+BlfSm zY1$`P=gHZPeWzRo?Ut3M+t(eS&Ri5-HEtZBF zBLfMtSj`BTE(bibY6u+2i?xISFde7U@l5M#>(&?8v$_GtS|T+yByt6BNXO_%)AWQ;F24V#VBVuY zf9lpp-x>(q8x6g1@b$~y+cGLLDOB|OK+I!}nii|EivBtf%0A)oebK6Tbs*wcu^~kz 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 Cl`WS5 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/tcp_in.d b/Sming/third-party/lwip2/build/core/tcp_in.d new file mode 100644 index 0000000000..2a55f3a220 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/tcp_in.d @@ -0,0 +1,21 @@ +../../build/core/tcp_in.o: core/tcp_in.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/priv/tcp_priv.h include/lwip/tcp.h include/lwip/mem.h \ + include/lwip/pbuf.h include/lwip/err.h include/lwip/ip.h \ + include/lwip/def.h include/lwip/ip_addr.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/stats.h include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/ip4.h include/lwip/prot/ip4.h \ + include/lwip/ip6.h include/lwip/prot/ip.h include/lwip/icmp.h \ + include/lwip/prot/icmp.h include/lwip/prot/tcp.h \ + include/lwip/inet_chksum.h include/lwip/nd6.h diff --git a/Sming/third-party/lwip2/build/core/tcp_in.o b/Sming/third-party/lwip2/build/core/tcp_in.o new file mode 100644 index 0000000000000000000000000000000000000000..6f0c7f9439480174765e58b5cb3cd48f059cc749 GIT binary patch literal 57356 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

    BjOl*Qae7ye%X#8hWN)4q^I%Ti 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 F`#+6rdQ|`b literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/tcp_out.d b/Sming/third-party/lwip2/build/core/tcp_out.d new file mode 100644 index 0000000000..8cac8ea263 --- /dev/null +++ b/Sming/third-party/lwip2/build/core/tcp_out.d @@ -0,0 +1,21 @@ +../../build/core/tcp_out.o: core/tcp_out.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/priv/tcp_priv.h include/lwip/tcp.h include/lwip/mem.h \ + include/lwip/pbuf.h include/lwip/err.h include/lwip/ip.h \ + include/lwip/def.h include/lwip/ip_addr.h include/lwip/ip4_addr.h \ + include/lwip/ip6_addr.h include/lwip/def.h include/lwip/netif.h \ + include/lwip/stats.h include/lwip/memp.h include/lwip/priv/memp_std.h \ + include/lwip/priv/memp_priv.h include/lwip/ip4.h include/lwip/prot/ip4.h \ + include/lwip/ip6.h include/lwip/prot/ip.h include/lwip/icmp.h \ + include/lwip/prot/icmp.h include/lwip/prot/tcp.h \ + include/lwip/inet_chksum.h diff --git a/Sming/third-party/lwip2/build/core/tcp_out.o b/Sming/third-party/lwip2/build/core/tcp_out.o new file mode 100644 index 0000000000000000000000000000000000000000..3d9f1b5cd3cd4031cc61369d78a164fa8cb0e122 GIT binary patch literal 62700 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,EBSaOpF%d}Rw+J5@g~K$ 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/core/udp.d b/Sming/third-party/lwip2/build/core/udp.d new file mode 100644 index 0000000000..d6b1b34adf --- /dev/null +++ b/Sming/third-party/lwip2/build/core/udp.d @@ -0,0 +1,22 @@ +../../build/core/udp.o: core/udp.c include/lwip/opt.h \ + ../../glue-lwip/lwipopts.h include/lwip/debug.h include/lwip/arch.h \ + ../../glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + ../../build/user_config.h ../../glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + ../../glue-lwip/arch/cc.h ../../glue-lwip/lwip-git-hash.h \ + include/lwip/udp.h include/lwip/pbuf.h include/lwip/err.h \ + include/lwip/netif.h include/lwip/ip_addr.h include/lwip/def.h \ + include/lwip/ip4_addr.h include/lwip/ip6_addr.h include/lwip/def.h \ + include/lwip/stats.h include/lwip/mem.h include/lwip/memp.h \ + include/lwip/priv/memp_std.h include/lwip/priv/memp_priv.h \ + include/lwip/ip.h include/lwip/ip4.h include/lwip/prot/ip4.h \ + include/lwip/ip6.h include/lwip/prot/ip.h include/lwip/prot/udp.h \ + include/lwip/inet_chksum.h include/lwip/icmp.h include/lwip/prot/icmp.h \ + include/lwip/icmp6.h include/lwip/prot/icmp6.h include/lwip/snmp.h \ + include/lwip/dhcp.h diff --git a/Sming/third-party/lwip2/build/core/udp.o b/Sming/third-party/lwip2/build/core/udp.o new file mode 100644 index 0000000000000000000000000000000000000000..df4b42524f75fff91da4c566388cdd23be1329eb GIT binary patch literal 42672 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 TnN6yaI|CNsGYxA5aTfm{C=+}Q literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/glue-esp/lwip-esp.d b/Sming/third-party/lwip2/build/glue-esp/lwip-esp.d new file mode 100644 index 0000000000..6f4315385b --- /dev/null +++ b/Sming/third-party/lwip2/build/glue-esp/lwip-esp.d @@ -0,0 +1,23 @@ +build/glue-esp/lwip-esp.o: glue-esp/lwip-esp.c \ + glue-esp/include-esp/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + build/user_config.h glue-esp/include-esp/lwip/timers.h \ + glue-esp/include-esp/lwip/opt.h glue-esp/include-esp/lwipopts.h \ + glue-esp/include-esp/lwip/debug.h glue-esp/include-esp/lwip/arch.h \ + glue-esp/include-esp/lwip/err.h glue-esp/include-esp/lwip/sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + glue-esp/include-esp/lwip/ip_addr.h glue-esp/include-esp/lwip/def.h \ + glue-esp/include-esp/lwip/netif.h glue-esp/include-esp/lwip/pbuf.h \ + glue-esp/include-esp/netif/etharp.h glue-esp/include-esp/lwip/ip.h \ + glue-esp/include-esp/lwip/mem.h glue/glue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/gpio.h \ + glue/esp-missing.h glue/uprint.h glue/glue.h glue/doprint.h diff --git a/Sming/third-party/lwip2/build/glue-esp/lwip-esp.o b/Sming/third-party/lwip2/build/glue-esp/lwip-esp.o new file mode 100644 index 0000000000000000000000000000000000000000..3761a1ce3ada49508fef74454d936005516290f3 GIT binary patch literal 54820 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.d b/Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.d new file mode 100644 index 0000000000..81a1950bdc --- /dev/null +++ b/Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.d @@ -0,0 +1,33 @@ +build/glue-lwip/esp-dhcpserver.o: glue-lwip/esp-dhcpserver.c \ + lwip2-src/src/include/lwip/inet.h lwip2-src/src/include/lwip/opt.h \ + glue-lwip/lwipopts.h lwip2-src/src/include/lwip/debug.h \ + lwip2-src/src/include/lwip/arch.h glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + build/user_config.h glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + glue-lwip/arch/cc.h glue-lwip/lwip-git-hash.h \ + lwip2-src/src/include/lwip/def.h lwip2-src/src/include/lwip/ip_addr.h \ + lwip2-src/src/include/lwip/ip4_addr.h \ + lwip2-src/src/include/lwip/ip6_addr.h lwip2-src/src/include/lwip/def.h \ + lwip2-src/src/include/lwip/err.h lwip2-src/src/include/lwip/pbuf.h \ + lwip2-src/src/include/lwip/udp.h lwip2-src/src/include/lwip/netif.h \ + lwip2-src/src/include/lwip/stats.h lwip2-src/src/include/lwip/mem.h \ + lwip2-src/src/include/lwip/memp.h \ + lwip2-src/src/include/lwip/priv/memp_std.h \ + lwip2-src/src/include/lwip/priv/memp_priv.h \ + lwip2-src/src/include/lwip/ip.h lwip2-src/src/include/lwip/ip4.h \ + lwip2-src/src/include/lwip/prot/ip4.h lwip2-src/src/include/lwip/ip6.h \ + lwip2-src/src/include/lwip/prot/ip.h \ + lwip2-src/src/include/lwip/prot/udp.h \ + glue-lwip/lwip/apps-esp/dhcpserver.h glue/glue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/gpio.h \ + glue/esp-missing.h glue/uprint.h glue/glue.h glue/doprint.h \ + glue-lwip/lwip-helper.h diff --git a/Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.o b/Sming/third-party/lwip2/build/glue-lwip/esp-dhcpserver.o new file mode 100644 index 0000000000000000000000000000000000000000..ff7f1c2a92ad65511f85ae8623ad97921c50a706 GIT binary patch literal 66792 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/glue-lwip/esp-time.d b/Sming/third-party/lwip2/build/glue-lwip/esp-time.d new file mode 100644 index 0000000000..b6f9265581 --- /dev/null +++ b/Sming/third-party/lwip2/build/glue-lwip/esp-time.d @@ -0,0 +1,16 @@ +build/glue-lwip/esp-time.o: glue-lwip/esp-time.c \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/sntp.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + lwip2-src/src/include/lwip/ip_addr.h lwip2-src/src/include/lwip/opt.h \ + glue-lwip/lwipopts.h lwip2-src/src/include/lwip/debug.h \ + lwip2-src/src/include/lwip/arch.h glue-lwip/arch/cc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + build/user_config.h glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + glue-lwip/arch/cc.h glue-lwip/lwip-git-hash.h \ + lwip2-src/src/include/lwip/def.h lwip2-src/src/include/lwip/ip4_addr.h \ + lwip2-src/src/include/lwip/ip6_addr.h lwip2-src/src/include/lwip/def.h diff --git a/Sming/third-party/lwip2/build/glue-lwip/esp-time.o b/Sming/third-party/lwip2/build/glue-lwip/esp-time.o new file mode 100644 index 0000000000000000000000000000000000000000..61356b59caaab6b31f23ba17af99ce564ccf1fb1 GIT binary patch literal 5916 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 Z@F~dMxN)8G`y6d=^4a*k7bS4^{x2#Wjrjlo literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/glue/doprint.d b/Sming/third-party/lwip2/build/glue/doprint.d new file mode 100644 index 0000000000..429027e92f --- /dev/null +++ b/Sming/third-party/lwip2/build/glue/doprint.d @@ -0,0 +1,10 @@ +build/glue/doprint.o: glue/doprint.c \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + build/user_config.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + glue/doprint.h glue/esp-missing.h diff --git a/Sming/third-party/lwip2/build/glue/doprint.o b/Sming/third-party/lwip2/build/glue/doprint.o new file mode 100644 index 0000000000000000000000000000000000000000..e4a1a43cc6f964d2175b4580a873edeff75937d3 GIT binary patch literal 14632 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 WjXeyh`IUleZxx;k{|w%WwfBGT`?VAR literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/glue/uprint.d b/Sming/third-party/lwip2/build/glue/uprint.d new file mode 100644 index 0000000000..fc118d2eb7 --- /dev/null +++ b/Sming/third-party/lwip2/build/glue/uprint.d @@ -0,0 +1,20 @@ +build/glue/uprint.o: glue/uprint.c glue/uprint.h glue/glue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h \ + build/user_config.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h \ + lwip2-src/src/include/lwip/ip_addr.h lwip2-src/src/include/lwip/opt.h \ + glue-lwip/lwipopts.h lwip2-src/src/include/lwip/debug.h \ + lwip2-src/src/include/lwip/arch.h glue-lwip/arch/cc.h glue/esp-missing.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h \ + glue-lwip/arch/cc.h glue-lwip/lwip-git-hash.h \ + lwip2-src/src/include/lwip/def.h lwip2-src/src/include/lwip/ip4_addr.h \ + lwip2-src/src/include/lwip/ip6_addr.h lwip2-src/src/include/lwip/def.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h \ + /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming/third-party/ESP8266_NONOS_SDK/include/gpio.h \ + glue/esp-missing.h glue/doprint.h diff --git a/Sming/third-party/lwip2/build/glue/uprint.o b/Sming/third-party/lwip2/build/glue/uprint.o new file mode 100644 index 0000000000000000000000000000000000000000..baa860effda741ecf752f962d4932404d9904615 GIT binary patch literal 2036 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/build/user_config.h b/Sming/third-party/lwip2/build/user_config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/README.md b/Sming/third-party/lwip2/glue-esp/include-esp/README.md new file mode 100644 index 0000000000..b1bc616b6d --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/README.md @@ -0,0 +1 @@ +include files from espressif's version of lwIP (should be 1.4RC2, patched) diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/arch/cc.h b/Sming/third-party/lwip2/glue-esp/include-esp/arch/cc.h new file mode 100644 index 0000000000..47413e5b72 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/arch/cc.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __ARCH_CC_H__ +#define __ARCH_CC_H__ + +//#include +#include "c_types.h" +#include "ets_sys.h" +#include "osapi.h" +#define EFAULT 14 + +#undef ICACHE_FLASH_ATTR +#define ICACHE_FLASH_ATTR + +//#define LWIP_PROVIDE_ERRNO + +#if (1) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif + + +typedef unsigned char u8_t; +typedef signed char s8_t; +typedef unsigned short u16_t; +typedef signed short s16_t; +typedef unsigned long u32_t; +typedef signed long s32_t; +typedef unsigned long mem_ptr_t; +typedef signed short sint16_t; + +#define S16_F "d" +#define U16_F "d" +#define X16_F "x" + +#define S32_F "d" +#define U32_F "d" +#define X32_F "x" + + + +//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +//#define LWIP_DEBUG + +#ifdef LWIP_DEBUG +#define LWIP_PLATFORM_DIAG(x) os_printf x +#define LWIP_PLATFORM_ASSERT(x) ETS_ASSERT(x) +#else +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) +#endif + +#define SYS_ARCH_DECL_PROTECT(x) +#define SYS_ARCH_PROTECT(x) +#define SYS_ARCH_UNPROTECT(x) + +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff))) +#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) + +#if LWIP_RAW +extern u8_t memp_memory_RAW_PCB_base[]; +#endif /* LWIP_RAW */ + +#if LWIP_UDP +extern u8_t memp_memory_UDP_PCB_base[]; +#endif /* LWIP_UDP */ + +#if LWIP_TCP +extern u8_t memp_memory_TCP_PCB_base[]; +extern u8_t memp_memory_TCP_PCB_LISTEN_base[]; +extern u8_t memp_memory_TCP_SEG_base[] SHMEM_ATTR; +#endif /* LWIP_TCP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +extern u8_t memp_memory_SYS_TIMEOUT_base[]; +#endif /* LWIP_TIMERS */ + +extern u8_t memp_memory_PBUF_base[]; +extern u8_t memp_memory_PBUF_POOL_base[]; + + + +#endif /* __ARCH_CC_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/arch/perf.h b/Sming/third-party/lwip2/glue-esp/include-esp/arch/perf.h new file mode 100644 index 0000000000..089facac1d --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/arch/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/arch/sys_arch.h b/Sming/third-party/lwip2/glue-esp/include-esp/arch/sys_arch.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api.h new file mode 100644 index 0000000000..91b9e5d243 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores whether to wake up the original application task + if data couldn't be sent in the first try. */ +#define NETCONN_FLAG_WRITE_DELAYED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If this is set, a TCP netconn must call netconn_recved() to update + the TCP receive window (done automatically if not set). */ +#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) (t&0xF0) +#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) + +/** Protocol family and type of the netconn */ +enum netconn_type { + NETCONN_INVALID = 0, + /* NETCONN_TCP Group */ + NETCONN_TCP = 0x10, + /* NETCONN_UDP Group */ + NETCONN_UDP = 0x20, + NETCONN_UDPLITE = 0x21, + NETCONN_UDPNOCHKSUM= 0x22, + /* NETCONN_RAW Group */ + NETCONN_RAW = 0x40 +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Use to inform the callback function about changes */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last error this netconn had */ + err_t last_err; + /** sem that is used to synchroneously execute functions in the core context */ + sys_sem_t op_completed; + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_RCVTIMEO + /** timeout to wait for new data to be received + (or connections to arrive for listening netconns) */ + int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores how much is already sent. */ + size_t write_offset; + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(lev); \ +} while(0); + +/* Network connection functions: */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +void netconn_recved(struct netconn *conn, u32_t length); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags); +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP +err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#endif /* LWIP_DNS */ + +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_set_noautorecved(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) +/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) + +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api_msg.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api_msg.h new file mode 100644 index 0000000000..f99d8c3b71 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/api_msg.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for do_send */ + struct netbuf *b; + /** used for do_newconn */ + struct { + u8_t proto; + } n; + /** used for do_bind and do_connect */ + struct { + ip_addr_t *ipaddr; + u16_t port; + } bc; + /** used for do_getaddr */ + struct { + ip_addr_t *ipaddr; + u16_t *port; + u8_t local; + } ad; + /** used for do_write */ + struct { + const void *dataptr; + size_t len; + u8_t apiflags; + } w; + /** used for do_recv */ + struct { + u32_t len; + } r; + /** used for do_close (/shutdown) */ + struct { + u8_t shut; + } sd; +#if LWIP_IGMP + /** used for do_join_leave_group */ + struct { + ip_addr_t *multiaddr; + ip_addr_t *netif_addr; + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +}; + +/** This struct contains a function to execute in another thread context and + a struct api_msg_msg that serves as an argument for this function. + This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ +struct api_msg { + /** function to execute in tcpip_thread context */ + void (* function)(struct api_msg_msg *msg); + /** arguments for this function */ + struct api_msg_msg msg; +}; + +#if LWIP_DNS +/** As do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ + const char *name; + /** Rhe resolved address is stored here */ + ip_addr_t *addr; + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t *sem; + /** Errors are given back here */ + err_t *err; +}; +#endif /* LWIP_DNS */ + +void do_newconn ( struct api_msg_msg *msg); +void do_delconn ( struct api_msg_msg *msg); +void do_bind ( struct api_msg_msg *msg); +void do_connect ( struct api_msg_msg *msg); +void do_disconnect ( struct api_msg_msg *msg); +void do_listen ( struct api_msg_msg *msg); +void do_send ( struct api_msg_msg *msg); +void do_recv ( struct api_msg_msg *msg); +void do_write ( struct api_msg_msg *msg); +void do_getaddr ( struct api_msg_msg *msg); +void do_close ( struct api_msg_msg *msg); +void do_shutdown ( struct api_msg_msg *msg); +#if LWIP_IGMP +void do_join_leave_group( struct api_msg_msg *msg); +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +void do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/dhcpserver.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/dhcpserver.h new file mode 100644 index 0000000000..63e762c6e0 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/dhcpserver.h @@ -0,0 +1,114 @@ +#ifndef __DHCPS_H__ +#define __DHCPS_H__ + +#define USE_DNS + +typedef struct dhcps_state{ + sint16_t state; +} dhcps_state; + +typedef struct dhcps_msg { + uint8_t op, htype, hlen, hops; + uint8_t xid[4]; + uint16_t secs, flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[312]; +}dhcps_msg; + +#ifndef LWIP_OPEN_SRC +struct dhcps_lease { + bool enable; + struct ip_addr start_ip; + struct ip_addr end_ip; +}; + +enum dhcps_offer_option{ + OFFER_START = 0x00, + OFFER_ROUTER = 0x01, + OFFER_END +}; +#endif + +typedef enum { + DHCPS_TYPE_DYNAMIC, + DHCPS_TYPE_STATIC +} dhcps_type_t; + +typedef enum { + DHCPS_STATE_ONLINE, + DHCPS_STATE_OFFLINE +} dhcps_state_t; + +struct dhcps_pool{ + struct ip_addr ip; + uint8 mac[6]; + uint32 lease_timer; + dhcps_type_t type; + dhcps_state_t state; + +}; + +typedef struct _list_node{ + void *pnode; + struct _list_node *pnext; +}list_node; + +extern uint32 dhcps_lease_time; +#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0 +#define DHCPS_MAX_LEASE 0x64 +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPS_SERVER_PORT 67 +#define DHCPS_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_INTERFACE_MTU 26 +#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP_OPTION_BROADCAST_ADDRESS 28 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +//#define USE_CLASS_B_NET 1 +#define DHCPS_DEBUG 0 +#define MAX_STATION_NUM 8 + +#define DHCPS_STATE_OFFER 1 +#define DHCPS_STATE_DECLINE 2 +#define DHCPS_STATE_ACK 3 +#define DHCPS_STATE_NAK 4 +#define DHCPS_STATE_IDLE 5 +#define DHCPS_STATE_RELEASE 6 + +#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0) + +void dhcps_start(struct ip_info *info); +void dhcps_stop(void); + +#endif + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn.h new file mode 100644 index 0000000000..5167ce1fc5 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn.h @@ -0,0 +1,678 @@ +#ifndef __ESPCONN_H__ +#define __ESPCONN_H__ + +#include "lwip/dns.h" +#include "os_type.h" +#include "lwip/app/espconn_buf.h" + +#if 0 +#define espconn_printf(fmt, args...) os_printf(fmt,## args) +#else +#define espconn_printf(fmt, args...) +#endif + + +typedef void *espconn_handle; +typedef void (* espconn_connect_callback)(void *arg); +typedef void (* espconn_reconnect_callback)(void *arg, sint8 err); + +/* Definitions for error constants. */ + +#define ESPCONN_OK 0 /* No error, everything OK. */ +#define ESPCONN_MEM -1 /* Out of memory error. */ +#define ESPCONN_TIMEOUT -3 /* Timeout. */ +#define ESPCONN_RTE -4 /* Routing problem. */ +#define ESPCONN_INPROGRESS -5 /* Operation in progress */ +#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/ + +#define ESPCONN_ABRT -8 /* Connection aborted. */ +#define ESPCONN_RST -9 /* Connection reset. */ +#define ESPCONN_CLSD -10 /* Connection closed. */ +#define ESPCONN_CONN -11 /* Not connected. */ + +#define ESPCONN_ARG -12 /* Illegal argument. */ +#define ESPCONN_IF -14 /* Low_level error */ +#define ESPCONN_ISCONN -15 /* Already connected. */ +#define ESPCONN_TIME -16 /* Sync Time error */ +#define ESPCONN_NODATA -17 /* No data can be read */ + +#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */ +#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/ +#define ESPCONN_PROTO_MSG -61 /* ssl application invalid */ + +#define ESPCONN_SSL 0x01 +#define ESPCONN_NORM 0x00 + +#define ESPCONN_STA 0x01 +#define ESPCONN_AP 0x02 +#define ESPCONN_AP_STA 0x03 + +#define STA_NETIF 0x00 +#define AP_NETIF 0x01 + +/** Protocol family and type of the espconn */ +enum espconn_type { + ESPCONN_INVALID = 0, + /* ESPCONN_TCP Group */ + ESPCONN_TCP = 0x10, + /* ESPCONN_UDP Group */ + ESPCONN_UDP = 0x20, +}; + +/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */ +enum espconn_state { + ESPCONN_NONE, + ESPCONN_WAIT, + ESPCONN_LISTEN, + ESPCONN_CONNECT, + ESPCONN_WRITE, + ESPCONN_READ, + ESPCONN_CLOSE +}; + +typedef struct _esp_tcp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; + espconn_connect_callback connect_callback; + espconn_reconnect_callback reconnect_callback; + espconn_connect_callback disconnect_callback; + espconn_connect_callback write_finish_fn; +} esp_tcp; + +typedef struct _esp_udp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; +} esp_udp; + +typedef struct _remot_info{ + enum espconn_state state; + int remote_port; + uint8 remote_ip[4]; +}remot_info; + +/** A callback prototype to inform about events for a espconn */ +typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len); +typedef void (* espconn_sent_callback)(void *arg); + +/** A espconn descriptor */ +struct espconn { + /** type of the espconn (TCP, UDP) */ + enum espconn_type type; + /** current state of the espconn */ + enum espconn_state state; + union { + esp_tcp *tcp; + esp_udp *udp; + } proto; + /** A callback function that is informed about events for this espconn */ + espconn_recv_callback recv_callback; + espconn_sent_callback sent_callback; + uint8 link_cnt; + void *reverse; +}; + +enum espconn_option{ + ESPCONN_START = 0x00, + ESPCONN_REUSEADDR = 0x01, + ESPCONN_NODELAY = 0x02, + ESPCONN_COPY = 0x04, + ESPCONN_KEEPALIVE = 0x08, + ESPCONN_END +}; + +enum espconn_level{ + ESPCONN_KEEPIDLE, + ESPCONN_KEEPINTVL, + ESPCONN_KEEPCNT +}; + +enum espconn_mode{ + ESPCONN_NOMODE, + ESPCONN_TCPSERVER_MODE, + ESPCONN_TCPCLIENT_MODE, + ESPCONN_UDP_MODE, + ESPCONN_NUM_MODE +}; + +struct espconn_packet{ + uint16 sent_length; /* sent length successful*/ + uint16 snd_buf_size; /* Available buffer size for sending */ + uint16 snd_queuelen; /* Available buffer space for sending */ + uint16 total_queuelen; /* total Available buffer space for sending */ + uint32 packseqno; /* seqno to be sent */ + uint32 packseq_nxt; /* seqno expected */ + uint32 packnum; +}; + +typedef struct _espconn_buf{ + uint8 *payload; + uint8 *punsent; + uint16 unsent; + uint16 len; + uint16 tot_len; + struct _espconn_buf *pnext; +} espconn_buf; + +typedef struct _comon_pkt{ + void *pcb; + int remote_port; + uint8 remote_ip[4]; + uint32 local_port; + uint32 local_ip; + espconn_buf *pbuf; + espconn_buf *ptail; + uint8* ptrbuf; + uint16 cntr; + sint8 err; + uint32 timeout; + uint32 recv_check; + uint8 pbuf_num; + struct espconn_packet packet_info; + bool write_flag; + enum espconn_option espconn_opt; +}comon_pkt; + +typedef struct _espconn_msg{ + struct espconn *pespconn; + comon_pkt pcommon; + uint8 count_opt; + uint8 espconn_mode; + sint16_t hs_status; //the status of the handshake + void *preverse; + void *pssl; + struct _espconn_msg *pnext; + +//***********Code for WIFI_BLOCK from upper************** + uint8 recv_hold_flag; + uint16 recv_holded_buf_Len; +//******************************************************* + ringbuf *readbuf; +}espconn_msg; + +#ifndef _MDNS_INFO +#define _MDNS_INFO +struct mdns_info { + char *host_name; + char *server_name; + uint16 server_port; + unsigned long ipAddr; + char *txt_data[10]; +}; +#endif + +#define linkMax 15 + +#define espconn_delay_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0) +#define espconn_delay_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0) +#define espconn_reuse_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0) +#define espconn_copy_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0) +#define espconn_copy_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0) +#define espconn_keepalive_disabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0) +#define espconn_keepalive_enabled(espconn) (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0) + +#define espconn_TaskPrio 26 +#define espconn_TaskQueueLen 15 + +enum espconn_sig { + SIG_ESPCONN_NONE, + SIG_ESPCONN_ERRER, + SIG_ESPCONN_LISTEN, + SIG_ESPCONN_CONNECT, + SIG_ESPCONN_WRITE, + SIG_ESPCONN_SEND, + SIG_ESPCONN_READ, + SIG_ESPCONN_CLOSE +}; + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : reconnect with host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source); + +/****************************************************************************** + * FunctionName : espconn_copy_partial + * Description : insert the node to the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert); + +/****************************************************************************** + * FunctionName : espconn_list_delete + * Description : remove the node from the active connection list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ + +void espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete); + +/****************************************************************************** + * FunctionName : espconn_find_connection + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none + *******************************************************************************/ + +bool espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode); + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags); + +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ + +sint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg); + +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_connect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_disconnect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_delete(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_accept(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_create(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_wnd + * Description : get the window size of simulatenously active TCP connections + * Parameters : none + * Returns : the number of TCP_MSS active TCP connections +*******************************************************************************/ +extern uint8 espconn_tcp_get_wnd(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the window size simulatenously active TCP connections + * Parameters : num -- the number of TCP_MSS + * Returns : ESPCONN_ARG -- Illegal argument + * ESPCONN_OK -- No error +*******************************************************************************/ +extern sint8 espconn_tcp_set_wnd(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_con(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : num -- total number + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_retran + * Description : get the Maximum number of retransmissions of data active TCP connections + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ +extern uint8 espconn_tcp_get_max_retran(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_retran + * Description : set the Maximum number of retransmissions of data active TCP connections + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_retran(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_syn + * Description : get the Maximum number of retransmissions of SYN segments + * Parameters : none + * Returns : the Maximum number of retransmissions +*******************************************************************************/ + +extern uint8 espconn_tcp_get_max_syn(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_syn + * Description : set the Maximum number of retransmissions of SYN segments + * Parameters : num -- the Maximum number of retransmissions + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_syn(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_buf_count + * Description : set the total number of espconn_buf on the unsent lists + * Parameters : espconn -- espconn to set the count + * num -- the total number of espconn_buf + * Returns : result +*******************************************************************************/ + +extern sint8 espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : struct espconn *espconn -- espconn to set the sent callback + * espconn_sent_callback sent_cb -- sent callback function to + * call for this espconn when data is successfully sent + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ +extern sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn); + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb); + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ + +extern uint32 espconn_port(void); + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_opt(struct espconn *espconn, uint8 opt); + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ +extern sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg); + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ +extern sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg); + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if + * ESPCONN_OK is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ + +extern sint8 espconn_gethostbyname(struct espconn *pespconn, const char *name, ip_addr_t *addr, dns_found_callback found); + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : register a device with mdns + * Parameters : ipAddr -- the ip address of device + * hostname -- the hostname of device + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_init(struct mdns_info *info); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : close mdns socket + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_close(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : register a server and join a multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_register(void); +/****************************************************************************** + * FunctionName : mdns_server_register + * Description : unregister server and leave multicast group + * Parameters : none + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_server_unregister(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : get server name + * Parameters : none + * Returns : server name +*******************************************************************************/ +extern char* espconn_mdns_get_servername(void); +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : set server name + * Parameters : server name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_servername(const char *name); +/****************************************************************************** + * FunctionName : espconn_mdns_set_hostname + * Description : set host name + * Parameters : host name + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_set_hostname(char *name); +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : get host name + * Parameters : void + * Returns : hostname +*******************************************************************************/ +extern char* espconn_mdns_get_hostname(void); +/****************************************************************************** + * FunctionName : espconn_mdns_disable + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_disable(void); +/****************************************************************************** + * FunctionName : espconn_mdns_enable + * Description : enable mdns + * Parameters : void + * Returns : none +*******************************************************************************/ +extern void espconn_mdns_enable(void); +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +extern void espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +#endif + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_buf.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_buf.h new file mode 100644 index 0000000000..8bdfaa12ab --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_buf.h @@ -0,0 +1,60 @@ +/* + * ringbuf.h + * + * Created on: Apr 22, 2016 + * Author: liuhan + */ + +#ifndef _ESPCONN_BUF_H_ +#define _ESPCONN_BUF_H_ + +/* + * ringbuffer.c + * + * Created on: Apr 22, 2016 + * Author: liuhan + */ +#include "c_types.h" + +#include "ets_sys.h" +#include "os_type.h" + +typedef struct ringbuf_t { + uint8_t *buf; + uint8_t *head, *tail; + size_t size; +} ringbuf, *ringbuf_t; + +ringbuf_t ringbuf_new(size_t capacity); + +size_t ringbuf_buffer_size(const struct ringbuf_t *rb); + +void ringbuf_reset(ringbuf_t rb); + +void ringbuf_free(ringbuf_t *rb); + +size_t ringbuf_capacity(const struct ringbuf_t *rb); + +size_t ringbuf_bytes_free(const struct ringbuf_t *rb); + +size_t ringbuf_bytes_used(const struct ringbuf_t *rb); + +int ringbuf_is_full(const struct ringbuf_t *rb); + +int ringbuf_is_empty(const struct ringbuf_t *rb); + +const void* ringbuf_tail(const struct ringbuf_t *rb); + +const void* ringbuf_head(const struct ringbuf_t *rb); + +static uint8_t *ringbuf_nextp(ringbuf_t rb, const uint8_t *p); + +size_t ringbuf_findchr(const struct ringbuf_t *rb, int c, size_t offset); + +size_t ringbuf_memset(ringbuf_t dst, int c, size_t len); + +void *ringbuf_memcpy_into(ringbuf_t dst, const void *src, size_t count); + +void *ringbuf_memcpy_from(void *dst, ringbuf_t src, size_t count); + +#endif /* RINGBUF_H_ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_tcp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_tcp.h new file mode 100644 index 0000000000..5598a5cd39 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_tcp.h @@ -0,0 +1,55 @@ +#ifndef __ESPCONN_TCP_H__ +#define __ESPCONN_TCP_H__ + +#ifndef ESPCONN_TCP_DEBUG +#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF +#endif +#include "lwip/app/espconn.h" + +#ifndef ESPCONN_TCP_TIMER +#define ESPCONN_TCP_TIMER 40 +#endif + +#define espconn_keepalive_enable(pcb) ((pcb)->so_options |= SOF_KEEPALIVE) +#define espconn_keepalive_disable(pcb) ((pcb)->so_options &= ~SOF_KEEPALIVE) + +/****************************************************************************** + * FunctionName : espconn_kill_oldest_pcb + * Description : A oldest incoming connection has been killed. + * Parameters : none + * Returns : none +*******************************************************************************/ + +extern void espconn_kill_oldest_pcb(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_tcp_disconnect(espconn_msg *pdiscon,u8 type); + +/****************************************************************************** + * FunctionName : espconn_tcp_client + * Description : Initialize the client: set up a connect PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_client(struct espconn* espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_server + * Description : Initialize the server: set up a listening PCB and bind it to + * the defined port + * Parameters : espconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_tcp_server(struct espconn *espconn); + +#endif /* __CLIENT_TCP_H__ */ + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_udp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_udp.h new file mode 100644 index 0000000000..cdb312f73e --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/espconn_udp.h @@ -0,0 +1,64 @@ +#ifndef __ESPCONN_UDP_H__ +#define __ESPCONN_UDP_H__ + +#ifndef ESPCONN_UDP_DEBUG +#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF +#endif + +#include "lwip/app/espconn.h" + +/****************************************************************************** + * FunctionName : espconn_udp_client + * Description : Initialize the client: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build client + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_client(struct espconn *pespconn); + +/****************************************************************************** + * FunctionName : espconn_udp_disconnect + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ + +extern void espconn_udp_disconnect(espconn_msg *pdiscon); + +/****************************************************************************** + * FunctionName : espconn_udp_server + * Description : Initialize the server: set up a PCB and bind it to the port + * Parameters : pespconn -- the espconn used to build server + * Returns : none +*******************************************************************************/ + +extern sint8 espconn_udp_server(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_udp_sent + * Description : sent data for client or server + * Parameters : void *arg -- client or server to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : none +*******************************************************************************/ + +extern err_t espconn_udp_sent(void *arg, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_udp_sendto + * Description : sent data for UDP + * Parameters : void *arg -- UDP to send + * uint8* psent -- Data to send + * uint16 length -- Length of data to send + * Returns : return espconn error code. + * - ESPCONN_OK. Successful. No error occured. + * - ESPCONN_MEM. Out of memory. + * - ESPCONN_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. +*******************************************************************************/ +extern err_t espconn_udp_sendto(void *arg, uint8 *psent, uint16 length); + +#endif /* __ESPCONN_UDP_H__ */ + + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/ping.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/ping.h new file mode 100644 index 0000000000..21e26e9101 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/ping.h @@ -0,0 +1,85 @@ +#ifndef __PING_H__ +#define __PING_H__ +#include "lwip/ip_addr.h" +#include "lwip/icmp.h" +/** + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used + */ +#ifndef PING_USE_SOCKETS +#define PING_USE_SOCKETS LWIP_SOCKET +#endif + +/** + * PING_DEBUG: Enable debugging for PING. + */ +#ifndef PING_DEBUG +#define PING_DEBUG LWIP_DBG_OFF +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_COARSE +#define PING_COARSE 1000 +#endif + +/** ping identifier - must fit on a u16_t */ +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +/** ping additional data size to include in the packet */ +#ifndef PING_DATA_SIZE +#define PING_DATA_SIZE 32 +#endif + +/** ping result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#endif + +#define DEFAULT_PING_MAX_COUNT 4 +#define PING_TIMEOUT_MS 1000 + +typedef void (* ping_recv_function)(void* arg, void *pdata); +typedef void (* ping_sent_function)(void* arg, void *pdata); + +struct ping_option{ + uint32 count; + uint32 ip; + uint32 coarse_time; + ping_recv_function recv_function; + ping_sent_function sent_function; + void* reverse; +}; + +struct ping_msg{ + struct ping_option *ping_opt; + struct raw_pcb *ping_pcb; + uint32 ping_start; + uint32 ping_sent; + uint32 timeout_count; + uint32 max_count; + uint32 sent_count; + uint32 coarse_time; +}; + +struct ping_resp{ + uint32 total_count; + uint32 resp_time; + uint32 seqno; + uint32 timeout_count; + uint32 bytes; + uint32 total_bytes; + uint32 total_time; + sint8 ping_err; +}; + +bool ping_start(struct ping_option *ping_opt); +bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv); +bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent); + +#endif /* __PING_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/time.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/time.h new file mode 100644 index 0000000000..189d7d1f0d --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/app/time.h @@ -0,0 +1,53 @@ +/* + * time.h + * + * Created on: May 31, 2016 + * Author: liuhan + */ + +#ifndef TIME_H_ +#define TIME_H_ +#include "osapi.h" +#include "os_type.h" +#include "lwip/sntp.h" + +struct timeval { + unsigned long tv_sec; /* seconds */ + unsigned long tv_usec; /* and microseconds */ +}; + +/***************************RTC TIME OPTION***************************************/ +// daylight settings +// Base calculated with value obtained from NTP server (64 bits) +#define sntp_base (*((uint64_t*)RTC_STORE0)) +// Timer value when base was obtained +#define TIM_REF_SET(value) WRITE_PERI_REG(RTC_STORE2, value) +#define TIM_REF_GET() READ_PERI_REG(RTC_STORE2) + +// Setters and getters for CAL, TZ and DST. +#define RTC_CAL_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= ((val) & 0x0000FFFF);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) +#define RTC_DST_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= (((val)<<16) & 0x00010000);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) +#define RTC_TZ_SET(val) do {uint32 value = READ_PERI_REG(RTC_STORE3);\ + value |= (((val)<<24) & 0xFF000000);\ + WRITE_PERI_REG(RTC_STORE3, value);\ + }while(0) + +#define RTC_CAL_GET() (READ_PERI_REG(RTC_STORE3) & 0x0000FFFF) +#define RTC_DST_GET() ((READ_PERI_REG(RTC_STORE3) & 0x00010000)>>16) +#define RTC_TZ_GET() ((((int)READ_PERI_REG(RTC_STORE3)) & ((int)0xFF000000))>>24) +void system_update_rtc(time_t t, uint32_t us); +time_t sntp_get_rtc_time(sint32_t *us); + +int gettimeofday(struct timeval* t, void* timezone); +void updateTime(uint32 ms); +bool configTime(int timezone, int daylightOffset, char *server1, char *server2, char *server3, bool enable); +time_t time(time_t *t); +unsigned long millis(void); +unsigned long micros(void); +#endif /* TIME_H_ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/arch.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/arch.h new file mode 100644 index 0000000000..524af6be03 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/arch.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ +/** Temporary upgrade helper: define format string for u8_t as hex if not + defined in cc.h */ +#ifndef X8_F +#define X8_F "02x" +#endif /* X8_F */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + + +#define ENSROK 0 /* DNS server returned answer with no data */ +#define ENSRNODATA 160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162 /* DNS server returned general failure */ +#define ENSRNOTFOUND 163 /* Domain name not found */ +#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166 /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF 172 /* End of file */ +#define ENSRFILE 173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/autoip.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/autoip.h new file mode 100644 index 0000000000..23c264a1e0 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/autoip.h @@ -0,0 +1,119 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF 0 +#define AUTOIP_STATE_PROBING 1 +#define AUTOIP_STATE_ANNOUNCING 2 +#define AUTOIP_STATE_BOUND 3 + +struct autoip +{ + ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ + u8_t state; /* current AutoIP state machine state */ + u8_t sent_num; /* sent number of probes or announces, dependent on state */ + u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u8_t lastconflict; /* ticks until a conflict can be solved by defending */ + u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Set a struct autoip allocated by the application to work with */ +void autoip_set_struct(struct netif *netif, struct autoip *autoip); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ +void autoip_tmr(void); + +/** Handle a possible change in the network configuration */ +void autoip_network_changed(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_AUTOIP */ + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/debug.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/debug.h new file mode 100644 index 0000000000..1950a3e2eb --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/debug.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "lwip/arch.h" + +/** lower two bits indicate debug level + * - 0 all + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_ALL 0x00 +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +#define LWIP_DBG_MASK_LEVEL 0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ + { LWIP_PLATFORM_ASSERT(message); } } while(0) +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +/** if "expression" isn't true, then print "message" and execute "handler" expression */ +#ifndef LWIP_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ASSERT(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + * AND is of correct type AND is at least LWIP_DBG_LEVEL + */ +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/def.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/def.h new file mode 100644 index 0000000000..9b6de6a8b8 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/def.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/** Get the absolute difference between 2 u32_t values (correcting overflows) + * 'a' is expected to be 'higher' (without overflow) than 'b'. */ +#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) + +/* Endianess-optimized shifting of two u8_t to create one u16_t */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define LWIP_MAKE_U16(a, b) ((a << 8) | b) +#else +#define LWIP_MAKE_U16(a, b) ((b << 8) | a) +#endif + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#ifndef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#if LWIP_PLATFORM_BYTESWAP +#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) +#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) +#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) +#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t lwip_htons(u16_t x); +u16_t lwip_ntohs(u16_t x); +u32_t lwip_htonl(u32_t x); +u32_t lwip_ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_DEF_H__ */ + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dhcp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dhcp.h new file mode 100644 index 0000000000..9e8fd0ec28 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dhcp.h @@ -0,0 +1,252 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_LEN 128U + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** our connection to the DHCP server */ + struct udp_pcb *pcb; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ + ip_addr_t offered_ip_addr; + ip_addr_t offered_sn_mask; + ip_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ + /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? + integrate with possible TFTP-client for booting? */ +#define LWIP_DHCP_BOOTP_FILE 0 +#if LWIP_DHCP_BOOTP_FILE + ip_addr_t offered_si_addr; + char boot_file_name[DHCP_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FIELD(u8_t op); + PACK_STRUCT_FIELD(u8_t htype); + PACK_STRUCT_FIELD(u8_t hlen); + PACK_STRUCT_FIELD(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); + PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); + PACK_STRUCT_FIELD(ip_addr_p_t siaddr); + PACK_STRUCT_FIELD(ip_addr_p_t giaddr); + PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); +/** Handle a possible change in the network configuration */ +void dhcp_network_changed(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); + +/** DHCP message item offsets and length */ +#define DHCP_OP_OFS 0 +#define DHCP_HTYPE_OFS 1 +#define DHCP_HLEN_OFS 2 +#define DHCP_HOPS_OFS 3 +#define DHCP_XID_OFS 4 +#define DHCP_SECS_OFS 8 +#define DHCP_FLAGS_OFS 10 +#define DHCP_CIADDR_OFS 12 +#define DHCP_YIADDR_OFS 16 +#define DHCP_SIADDR_OFS 20 +#define DHCP_GIADDR_OFS 24 +#define DHCP_CHADDR_OFS 28 +#define DHCP_SNAME_OFS 44 +#define DHCP_FILE_OFS 108 +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS DHCP_MSG_LEN +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_OFF 0 +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/** DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ +#define DHCP_HTYPE_ETH 1 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/**add options for support more router by liuHan**/ +#define DHCP_OPTION_DOMAIN_NAME 15 +#define DHCP_OPTION_PRD 31 +#define DHCP_OPTION_STATIC_ROUTER 33 +#define DHCP_OPTION_VSN 43 +#define DHCP_OPTION_NB_TINS 44 +#define DHCP_OPTION_NB_TINT 46 +#define DHCP_OPTION_NB_TIS 47 +#define DHCP_OPTION_CLASSLESS_STATIC_ROUTER 121 +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*__LWIP_DHCP_H__*/ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dns.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dns.h new file mode 100644 index 0000000000..6c7d9b0739 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/dns.h @@ -0,0 +1,124 @@ +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_DNS_H__ +#define __LWIP_DNS_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* The size used for the next line is rather a hack, but it prevents including socket.h in all files + that include memp.h, and that would possibly break portability (since socket.h defines some types + and constants possibly already define by the OS). + Calculation rule: + sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ +#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +ip_addr_t dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); + +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/err.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/err.h new file mode 100644 index 0000000000..cb69a9f498 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/err.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/* Definitions for error constants. */ + +#define ERR_OK 0 /* No error, everything OK. */ +#define ERR_MEM -1 /* Out of memory error. */ +#define ERR_BUF -2 /* Buffer error. */ +#define ERR_TIMEOUT -3 /* Timeout. */ +#define ERR_RTE -4 /* Routing problem. */ +#define ERR_INPROGRESS -5 /* Operation in progress */ +#define ERR_VAL -6 /* Illegal value. */ +#define ERR_WOULDBLOCK -7 /* Operation would block. */ + +#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK) + +#define ERR_ABRT -8 /* Connection aborted. */ +#define ERR_RST -9 /* Connection reset. */ +#define ERR_CLSD -10 /* Connection closed. */ +#define ERR_CONN -11 /* Not connected. */ + +#define ERR_ARG -12 /* Illegal argument. */ + +#define ERR_USE -13 /* Address in use. */ + +#define ERR_IF -14 /* Low-level netif error */ +#define ERR_ISCONN -15 /* Already connected. */ + + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err)ICACHE_FLASH_ATTR; +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/icmp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/icmp.h new file mode 100644 index 0000000000..9bcb7bc439 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/icmp.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ + +enum icmp_dur_type { + ICMP_DUR_NET = 0, /* net unreachable */ + ICMP_DUR_HOST = 1, /* host unreachable */ + ICMP_DUR_PROTO = 2, /* protocol unreachable */ + ICMP_DUR_PORT = 3, /* port unreachable */ + ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + ICMP_DUR_SR = 5 /* source route failed */ +}; + +enum icmp_te_type { + ICMP_TE_TTL = 0, /* time to live exceeded in transit */ + ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ +}; + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is splitted to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + * ¶¨ÒåICMP»ØËÍÇëÇó±¨ÎÄÊײ¿½á¹¹£¬ + * ÓÉÓÚËùÓÐICMP±¨ÎÄÊײ¿ÓкܴóÏàËÆÐÔ£¬ + * ¸Ã½á¹¹Í¬ÑùÊÊÓÃÓÚÆäËüICMP±¨ÎÄ¡£ + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +//¶ÁÈ¡ICMPÊײ¿ÖÐ×ֶΠ+#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t ÏòICMP±¨ÎÄÊײ¿×Ö¶ÎÖÐдÈëÏàÓ¦Öµ*/ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)ICACHE_FLASH_ATTR; +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)ICACHE_FLASH_ATTR; + +#endif /* LWIP_ICMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ICMP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/igmp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/igmp.h new file mode 100644 index 0000000000..c90adcdce4 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/igmp.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef __LWIP_IGMP_H__ +#define __LWIP_IGMP_H__ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* MAC Filter Actions, these are passed to a netif's + * igmp_mac_filter callback function. */ +#define IGMP_DEL_MAC_FILTER 0 +#define IGMP_ADD_MAC_FILTER 1 + + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void)ICACHE_FLASH_ATTR; +err_t igmp_start(struct netif *netif)ICACHE_FLASH_ATTR; +err_t igmp_stop(struct netif *netif)ICACHE_FLASH_ATTR; +void igmp_report_groups(struct netif *netif)ICACHE_FLASH_ATTR; +struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLASH_ATTR; +err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +void igmp_tmr(void)ICACHE_FLASH_ATTR; +#define LWIP_RAND() r_rand() +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet.h new file mode 100644 index 0000000000..7bff49b59e --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** For compatibility with BSD code */ +struct in_addr { + u32_t s_addr; +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + +#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ +#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) +#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet_chksum.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet_chksum.h new file mode 100644 index 0000000000..41be6415bc --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/inet_chksum.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_CHKSUM_H__ +#define __LWIP_INET_CHKSUM_H__ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +#ifndef LWIP_CHKSUM_COPY +#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +#ifndef LWIP_CHKSUM_COPY_ALGORITHM +#define LWIP_CHKSUM_COPY_ALGORITHM 1 +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +#endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +#define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pbuf(struct pbuf *p)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo_partial(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len)ICACHE_FLASH_ATTR; +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/init.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/init.h new file mode 100644 index 0000000000..7a58aece9e --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/init.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INIT_H__ +#define __LWIP_INIT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 1U +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 4U +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 0U +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC 2U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT 0U + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ + LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +/* Modules initialization */ +void lwip_init(void) ICACHE_FLASH_ATTR; +//void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip.h new file mode 100644 index 0000000000..1f361fa448 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND LWIP_IGMP + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ +#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { + /* version / header length / type of service */ + PACK_STRUCT_FIELD(u16_t _v_hl_tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FIELD(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FIELD(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(ip_addr_p_t src); + PACK_STRUCT_FIELD(ip_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +/** The interface that provided the packet for the current callback invocation. */ +extern struct netif *current_netif; +/** Header of the input packet currently being processed. */ +extern const struct ip_hdr *current_header; +/** Source IP address of current_header */ +extern ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +extern ip_addr_t current_iphdr_dest; + +#define ip_init() /* Compatibility define, not init needed. */ +struct netif *ip_route(ip_addr_t *dest)ICACHE_FLASH_ATTR; +struct netif *ip_router(ip_addr_t *dest, ip_addr_t *source); + +err_t ip_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto)ICACHE_FLASH_ATTR; +err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, + struct netif *netif)ICACHE_FLASH_ATTR; +#if LWIP_NETIF_HWADDRHINT +err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen)ICACHE_FLASH_ATTR; +#endif /* IP_OPTIONS_SEND */ +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (current_netif) +/** Get the IP header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_header() (current_header) +/** Source IP address of current_header */ +#define ip_current_src_addr() (¤t_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (¤t_iphdr_dest) + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p)ICACHE_FLASH_ATTR; +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_addr.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_addr.h new file mode 100644 index 0000000000..cfc10f8095 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_addr.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the aligned version of ip_addr_t, + used as local variable, on the stack, etc. */ +struct ip_addr { + u32_t addr; +}; + +/* This is the packed version of ip_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** ip_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip_addr_t as well as on ip_addr_p_t. */ +typedef struct ip_addr ip_addr_t; +typedef struct ip_addr_packed ip_addr_p_t; + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Forward declaration to not include netif.h */ +struct netif; + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + * for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + + +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IP address given by the four byte-parts. + Little-endian version that prevents the use of htonl. */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) +#endif + +/** Copy IP address - faster than ip_addr_set: no NULL check */ +#define ip_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for htonl()) */ +#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) + +#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) +u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)ICACHE_FLASH_ATTR; + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask)ICACHE_FLASH_ATTR; + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, \ + ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) + +/* Get one byte from the 4-byte address */ +#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp)ICACHE_FLASH_ATTR; +int ipaddr_aton(const char *cp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +/** returns ptr to static buffer; not reentrant! */ +char *ipaddr_ntoa(const ip_addr_t *addr)ICACHE_FLASH_ATTR; +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)ICACHE_FLASH_ATTR; + +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +#define IPSTR "%d.%d.%d.%d" + +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_frag.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_frag.h new file mode 100644 index 0000000000..df6db5f5c1 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/ip_frag.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/* IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void)ICACHE_FLASH_ATTR; +void ip_reass_tmr(void)ICACHE_FLASH_ATTR; +struct pbuf * ip_reass(struct pbuf *p)ICACHE_FLASH_ATTR; +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)ICACHE_FLASH_ATTR; +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mdns.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mdns.h new file mode 100644 index 0000000000..78546bc8b2 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mdns.h @@ -0,0 +1,114 @@ +/** + * lwip MDNS resolver header file. + * + * Created on: Jul 29, 2010 + * Author: Daniel Toma + + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_MDNS_H__ +#define __LWIP_MDNS_H__ + +#include "lwip/opt.h" + +#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */ + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/** mDNS Address offset flag*/ +#define DNS_OFFSET_FLAG 0xC0 /* the offset flag in the DNS message */ +#define DNS_DEFAULT_OFFSET 0x0C /* the offset is set at the beginning of the DNS message */ + +#define DNS_IP_ADDR_LEN 4 + + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_SRV 33 /* Service record */ +#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */ +#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */ +#define DNS_RRTYPE_ANY 255 /*Not a DNS type, but a DNS query type, meaning "all types"*/ + +/* DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ +#define DNS_RRCLASS_FLUSH_IN 0x8001/* Flush bit and Internet*/ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +#ifndef _MDNS_INFO +#define _MDNS_INFO +struct mdns_info { + char *host_name; + char *server_name; + uint16 server_port; + unsigned long ipAddr; + char *txt_data[10]; +}; +#endif +//void mdns_enable(void); +//void mdns_disable(void); +//void mdns_init(struct mdns_info *info); +//void mdns_close(void); +//char* mdns_get_hostname(void); +//void mdns_set_hostname(char *name); +//void mdns_set_servername(const char *name); +//char* mdns_get_servername(void); +//void mdns_server_unregister(void); +//void mdns_server_register(void) ; +//void mdns_tmr(void); +//void Delay(unsigned long ulSeconds); + +#endif /* LWIP_MDNS */ + +#endif /* __LWIP_MDNS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mem.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mem.h new file mode 100644 index 0000000000..3709bcdaab --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/mem.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" +//#include "mem_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include /* for size_t */ + +typedef size_t mem_size_t; + +/* aliases for C library malloc() */ +#define mem_init() +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_free +#define mem_free(p) vPortFree(p, "", 0) +#endif +#ifndef mem_malloc +#define mem_malloc(s) pvPortMalloc(s, "", 0) +#endif +#ifndef mem_calloc +#define mem_calloc(s) pvPortCalloc(s, "", 0) +#endif +#ifndef mem_realloc +#define mem_realloc(p, s) pvPortRealloc(p, s, "", 0) +#endif +#ifndef mem_zalloc +#define mem_zalloc(s) pvPortZalloc(s, "", 0) +#endif + +#ifndef os_malloc +#define os_malloc(s) mem_malloc((s)) +#endif +#ifndef os_realloc +#define os_realloc(p, s) mem_realloc((p), (s)) +#endif +#ifndef os_zalloc +#define os_zalloc(s) mem_zalloc((s)) +#endif +#ifndef os_free +#define os_free(p) mem_free((p)) +#endif + +/* Since there is no C library allocation function to shrink memory without + moving it, define this to nothing. */ +#ifndef mem_trim +#define mem_trim(mem, size) (mem) +#endif +#else /* MEM_LIBC_MALLOC */ + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ + +#if MEM_USE_POOLS +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_trim is not used when using pools instead of a heap: + we can't free part of a pool element and don't want to copy the rest */ +#define mem_trim(mem, size) (mem) +#else /* MEM_USE_POOLS */ +/* lwIP alternative malloc */ +void mem_init(void)ICACHE_FLASH_ATTR; +void *mem_trim(void *mem, mem_size_t size)ICACHE_FLASH_ATTR; +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size)ICACHE_FLASH_ATTR; +void *mem_calloc(mem_size_t count, mem_size_t size)ICACHE_FLASH_ATTR; +void mem_free(void *mem)ICACHE_FLASH_ATTR; +#endif /* MEM_LIBC_MALLOC */ + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEM_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp.h new file mode 100644 index 0000000000..6a2127db23 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc, attr) MEMP_##name, +#include "lwip/memp_std.h" + MEMP_MAX +} memp_t; + +#if MEM_USE_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC || MEM_USE_POOLS +extern const u32_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#include "mem.h" + +#define memp_init() +#define memp_malloc(type) mem_malloc(memp_sizes[type]) +#define memp_free(type, mem) mem_free(mem) + +#else /* MEMP_MEM_MALLOC */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ + memp_t poolnr; +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void)ICACHE_FLASH_ATTR; + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line)ICACHE_FLASH_ATTR; +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type)ICACHE_FLASH_ATTR; +#endif +void memp_free(memp_t type, void *mem)ICACHE_FLASH_ATTR; + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp_std.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp_std.h new file mode 100644 index 0000000000..b20a240535 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/memp_std.h @@ -0,0 +1,126 @@ +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size, attr) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc, attr) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc, attr) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB", DMEM_ATTR) +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB", DMEM_ATTR) +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB", DMEM_ATTR) +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN", DMEM_ATTR) +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG", DMEM_ATTR) +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA", DMEM_ATTR) +#endif /* IP_REASSEMBLY */ +#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF", DMEM_ATTR) +#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +#if LWIP_NETCONN +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE", DMEM_ATTR) +#endif /* ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP", DMEM_ATTR) +#endif /* LWIP_IGMP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT", DMEM_ATTR) +#endif /* LWIP_TIMERS */ + +#if LWIP_SNMP +LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") +LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") +LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") +LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") +#endif /* LWIP_SNMP */ +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#if PPP_SUPPORT && PPPOE_SUPPORT +LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM", DMEM_ATTR) + +/* XXX: need to align to 4 byte as memp strcut is 4-byte long. otherwise will crash */ +#define LWIP_MEM_ALIGN4_SIZE(size) (((size) + 4 - 1) & ~(4-1)) + +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, LWIP_MEM_ALIGN4_SIZE(PBUF_POOL_BUFSIZE), "PBUF_POOL", DMEM_ATTR) + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netbuf.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netbuf.h new file mode 100644 index 0000000000..b554a579d4 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netbuf.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETBUF_H__ +#define __LWIP_NETBUF_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void)ICACHE_FLASH_ATTR; +void netbuf_delete (struct netbuf *buf)ICACHE_FLASH_ATTR; +void * netbuf_alloc (struct netbuf *buf, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_free (struct netbuf *buf)ICACHE_FLASH_ATTR; +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_chain (struct netbuf *head, + struct netbuf *tail)ICACHE_FLASH_ATTR; + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len)ICACHE_FLASH_ATTR; +s8_t netbuf_next (struct netbuf *buf)ICACHE_FLASH_ATTR; +void netbuf_first (struct netbuf *buf)ICACHE_FLASH_ATTR; + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netdb.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netdb.h new file mode 100644 index 0000000000..7587e2f2d1 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netdb.h @@ -0,0 +1,124 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef __LWIP_NETDB_H__ +#define __LWIP_NETDB_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include /* for size_t */ + +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessable error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +#define gethostbyname(name) lwip_gethostbyname(name) +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* __LWIP_NETDB_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netif.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netif.h new file mode 100644 index 0000000000..04e4f7a0a0 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netif.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths + across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It is set by the startup code (for static IP configuration) or + * by dhcp/autoip when an address has been assigned. + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the netif is one end of a point-to-point connection. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_POINTTOPOINT 0x04U +/** If set, the interface is configured using DHCP. + * Set by the DHCP code when starting or stopping DHCP. */ +#define NETIF_FLAG_DHCP 0x08U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x10U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x20U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x40U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x80U + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr); +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + ip_addr_t *group, u8_t action); + +/*add DHCP event processing by LiuHan*/ +typedef void (*dhcp_event_fn)(void); + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { + /** pointer to next in linked list */ + struct netif *next; + + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; + + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. ÏòIP²ãÊäÈëÊý¾Ý°ü*/ + netif_input_fn input; + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. ·¢ËÍIPÊý¾Ý°ü*/ + netif_output_fn output; + /** This function is called by the ARP module when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. µ×²ãÊý¾Ý°ü·¢ËÍ*/ + netif_linkoutput_fn linkoutput; +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. ×ÔÓÉÉèÖÃ×ֶΣ¬±ÈÈçÖ¸Ïòµ×²ãÉ豸Ïà¹ØÐÅÏ¢*/ + void *state; +#if LWIP_DHCP + /** the DHCP client state information for this netif */ + struct dhcp *dhcp; + struct udp_pcb *dhcps_pcb; //dhcps + dhcp_event_fn dhcp_event; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /** the AutoIP client state information for this netif */ + struct autoip *autoip; +#endif +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ + /** maximum transfer unit (in bytes) ¸Ã½Ó¿ÚÔÊÐíµÄ×î´óÊý¾Ý°ü³¤¶È£¬¶àÊÇ1500*/ + u16_t mtu; + /** number of bytes used in hwaddr¸Ã½Ó¿ÚÎïÀíµØÖ·³¤¶È */ + u8_t hwaddr_len; + /** link level hardware address of this interface ¸Ã½Ó¿ÚÎïÀíµØÖ·*/ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** flags (see NETIF_FLAG_ above) ¸Ã½Ó¿Ú״̬¡¢ÊôÐÔ×Ö¶Î*/ + u8_t flags; + /** descriptive abbreviation ¸Ã½Ó¿ÚµÄÃû×Ö*/ + char name[2]; + /** number of this interface ¸Ã½Ó¿ÚµÄ±àºÅ*/ + u8_t num; +#if LWIP_SNMP + /** link type (from "snmp_ifType" enum from snmp.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + u32_t ifinoctets; + u32_t ifinucastpkts; + u32_t ifinnucastpkts; + u32_t ifindiscards; + u32_t ifoutoctets; + u32_t ifoutucastpkts; + u32_t ifoutnucastpkts; + u32_t ifoutdiscards; +#endif /* LWIP_SNMP */ +#if LWIP_IGMP + /** This function could be called to add or delete a entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. Ö¸Ïò·¢Ë͸ø×Ô¼ºµÄÊý¾Ý°üµÄpbuf*/ + struct pbuf *loop_first;//µÚÒ»¸ö + struct pbuf *loop_last;//×îºóÒ»¸ö +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_SNMP +#define NETIF_INIT_SNMP(netif, type, speed) \ + /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ + (netif)->link_type = (type); \ + /* your link speed here (units: bits per second) */ \ + (netif)->link_speed = (speed); \ + (netif)->ts = 0; \ + (netif)->ifinoctets = 0; \ + (netif)->ifinucastpkts = 0; \ + (netif)->ifinnucastpkts = 0; \ + (netif)->ifindiscards = 0; \ + (netif)->ifoutoctets = 0; \ + (netif)->ifoutucastpkts = 0; \ + (netif)->ifoutnucastpkts = 0; \ + (netif)->ifoutdiscards = 0 +#else /* LWIP_SNMP */ +#define NETIF_INIT_SNMP(netif, type, speed) +#endif /* LWIP_SNMP */ + + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void)ICACHE_FLASH_ATTR; + +struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)ICACHE_FLASH_ATTR; + +void +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw)ICACHE_FLASH_ATTR; +void netif_remove(struct netif * netif)ICACHE_FLASH_ATTR; + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(char *name)ICACHE_FLASH_ATTR; + +void netif_set_default(struct netif *netif)ICACHE_FLASH_ATTR; + +void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +void netif_set_netmask(struct netif *netif, ip_addr_t *netmask)ICACHE_FLASH_ATTR; +void netif_set_gw(struct netif *netif, ip_addr_t *gw)ICACHE_FLASH_ATTR; + +void netif_set_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if an interface is up */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +void netif_set_link_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_link_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip)ICACHE_FLASH_ATTR; +void netif_poll(struct netif *netif)ICACHE_FLASH_ATTR; +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void)ICACHE_FLASH_ATTR; +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETIF_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netifapi.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netifapi.h new file mode 100644 index 0000000000..33318efaf6 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/netifapi.h @@ -0,0 +1,108 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef __LWIP_NETIFAPI_H__ +#define __LWIP_NETIFAPI_H__ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg_msg { +#if !LWIP_TCPIP_CORE_LOCKING + sys_sem_t sem; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + err_t err; + struct netif *netif; + union { + struct { + ip_addr_t *ipaddr; + ip_addr_t *netmask; + ip_addr_t *gw; + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + } msg; +}; + +struct netifapi_msg { + void (* function)(struct netifapi_msg_msg *msg); + struct netifapi_msg_msg msg; +}; + + +/* API for application */ +err_t netifapi_netif_add ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, + void *state, + netif_init_fn init, + netif_input_fn input); + +err_t netifapi_netif_set_addr ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw ); + +err_t netifapi_netif_common ( struct netif *netif, + netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/opt.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/opt.h new file mode 100644 index 0000000000..0d2b3fcc5f --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/opt.h @@ -0,0 +1,2043 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you dont like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 1 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 0 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 0 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 3 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 50 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 30 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 2 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 3 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 16 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 0 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 0 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 0 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 0 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + * Does not have to be changed unless external MIBs answer request asynchronously + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 1 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * SNMP_PRIVATE_MIB: + * When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 256 +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +//#ifndef LWIP_EVENT_API +//#define LWIP_EVENT_API 0 +//#define LWIP_CALLBACK_API 1 +//#else +//#define LWIP_EVENT_API 1 +//#define LWIP_CALLBACK_API 0 +//#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 1 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 1 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else + +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/pbuf.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/pbuf.h new file mode 100644 index 0000000000..3d24db4d4b --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/pbuf.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG */ +#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN 20 + +typedef enum { + PBUF_TRANSPORT, + PBUF_IP, + PBUF_LINK, + PBUF_RAW +} pbuf_layer; + +typedef enum { + PBUF_RAM, /* pbuf data is stored in RAM */ + PBUF_ROM, /* pbuf data is stored in ROM */ + PBUF_REF, /* pbuf comes from the pbuf pool */ + PBUF_POOL, /* pbuf payload refers to RAM */ +#ifdef EBUF_LWIP + PBUF_ESF_RX /* pbuf payload is from WLAN */ +#endif /* ESF_LWIP */ +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a + a pbuf differently */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U + +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** pbuf_type as u8_t instead of enum to save space */ + u8_t /*pbuf_type*/ type; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; + + /* add a pointer for esf_buf */ + void * eb; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)ICACHE_FLASH_ATTR; +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len)ICACHE_FLASH_ATTR; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size)ICACHE_FLASH_ATTR; +u8_t pbuf_header(struct pbuf *p, s16_t header_size)ICACHE_FLASH_ATTR; +void pbuf_ref(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_free(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_clen(struct pbuf *p)ICACHE_FLASH_ATTR; +void pbuf_cat(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +void pbuf_chain(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_dechain(struct pbuf *p)ICACHE_FLASH_ATTR; +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)ICACHE_FLASH_ATTR; +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)ICACHE_FLASH_ATTR; +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)ICACHE_FLASH_ATTR; +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +u8_t pbuf_get_at(struct pbuf* p, u16_t offset)ICACHE_FLASH_ATTR; +u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)ICACHE_FLASH_ATTR; +u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)ICACHE_FLASH_ATTR; +u16_t pbuf_strstr(struct pbuf* p, const char* substr)ICACHE_FLASH_ATTR; + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/puck_def.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/puck_def.h new file mode 100644 index 0000000000..c20027a15c --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/puck_def.h @@ -0,0 +1,44 @@ +/* + * puck_def.h + * + * Created on: Jul 22, 2010 + * Author: dtoma + */ + +#ifndef PUCK_DEF_H_ +#define PUCK_DEF_H_ + + + +#define INSTRUMENT_PORT 8760 + +#define INSTRUMENT_LENGTH 80 + +#define MDNS_NAME_LENGTH 68 //68 + +char* PUCK_SERVICE = NULL; +//#define PUCK_SERVICE "_Escpressif._tcp.local" +#define DNS_SD_SERVICE "_services._dns-sd._udp.local" +#define SERVICE_DESCRIPTION "PUCK PROTOCOL" +#define PUCK_SERVICE_LENGTH 30 + +#define UUID_LEN 16 +#define DS_VERS_LEN 2 +#define DS_SIZE_LEN 2 +#define MAN_ID_LEN 4 +#define MAN_MODEL_LEN 2 +#define MAN_VERS_LEN 2 +#define SER_NUM_LEN 4 +#define NAME_LEN 64 +#define PUCK_DATASHEET_SIZE 96 + +#define UUID_OFFSET 0 +#define DS_VERS_OFFSET UUID_LEN + UUID_OFFSET +#define DS_SIZE_OFFSET DS_VERS_LEN + DS_VERS_OFFSET +#define MAN_ID_OFFSET DS_SIZE_LEN + DS_SIZE_OFFSET +#define MAN_MODEL_OFFSET MAN_ID_LEN + MAN_ID_OFFSET +#define MAN_VERS_OFFSET MAN_MODEL_LEN + MAN_MODEL_OFFSET +#define SER_NUM_OFFSET MAN_VERS_LEN + MAN_VERS_OFFSET +#define NAME_OFFSET SER_NUM_LEN + SER_NUM_OFFSET + +#endif /* __PUCK_DEF_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/raw.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/raw.h new file mode 100644 index 0000000000..c9c40871b1 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/raw.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip_addr_t *addr); + +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto)ICACHE_FLASH_ATTR; +void raw_remove (struct raw_pcb *pcb)ICACHE_FLASH_ATTR; +err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)ICACHE_FLASH_ATTR; +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +#define raw_init() /* Compatibility define, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sio.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sio.h new file mode 100644 index 0000000000..228c857772 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sio.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef __SIO_H__ +#define __SIO_H__ + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __SIO_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp.h new file mode 100644 index 0000000000..2ed043dd5f --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/ip_addr.h" + +struct udp_pcb; +struct netif; + +/** + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** SNMP "sysuptime" Interval */ +#define SNMP_SYSUPTIME_INTERVAL 10 + +/** fixed maximum length for object identifier type */ +#define LWIP_SNMP_OBJ_ID_LEN 32 + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + s32_t id[LWIP_SNMP_OBJ_ID_LEN]; +}; + +/* system */ +void snmp_set_sysdesr(u8_t* str, u8_t* len); +void snmp_set_sysobjid(struct snmp_obj_id *oid); +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); +void snmp_inc_sysuptime(void); +void snmp_add_sysuptime(u32_t value); +void snmp_get_sysuptime(u32_t *value); +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); + +/* network interface */ +void snmp_add_ifinoctets(struct netif *ni, u32_t value); +void snmp_inc_ifinucastpkts(struct netif *ni); +void snmp_inc_ifinnucastpkts(struct netif *ni); +void snmp_inc_ifindiscards(struct netif *ni); +void snmp_add_ifoutoctets(struct netif *ni, u32_t value); +void snmp_inc_ifoutucastpkts(struct netif *ni); +void snmp_inc_ifoutnucastpkts(struct netif *ni); +void snmp_inc_ifoutdiscards(struct netif *ni); +void snmp_inc_iflist(void); +void snmp_dec_iflist(void); + +/* ARP (for atTable and ipNetToMediaTable) */ +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipinhdrerrors(void); +void snmp_inc_ipinaddrerrors(void); +void snmp_inc_ipforwdatagrams(void); +void snmp_inc_ipinunknownprotos(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutnoroutes(void); +void snmp_inc_ipreasmreqds(void); +void snmp_inc_ipreasmoks(void); +void snmp_inc_ipreasmfails(void); +void snmp_inc_ipfragoks(void); +void snmp_inc_ipfragfails(void); +void snmp_inc_ipfragcreates(void); +void snmp_inc_iproutingdiscards(void); +void snmp_insert_ipaddridx_tree(struct netif *ni); +void snmp_delete_ipaddridx_tree(struct netif *ni); +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void); +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); +void snmp_insert_udpidx_tree(struct udp_pcb *pcb); +void snmp_delete_udpidx_tree(struct udp_pcb *pcb); + +/* SNMP */ +void snmp_inc_snmpinpkts(void); +void snmp_inc_snmpoutpkts(void); +void snmp_inc_snmpinbadversions(void); +void snmp_inc_snmpinbadcommunitynames(void); +void snmp_inc_snmpinbadcommunityuses(void); +void snmp_inc_snmpinasnparseerrs(void); +void snmp_inc_snmpintoobigs(void); +void snmp_inc_snmpinnosuchnames(void); +void snmp_inc_snmpinbadvalues(void); +void snmp_inc_snmpinreadonlys(void); +void snmp_inc_snmpingenerrs(void); +void snmp_add_snmpintotalreqvars(u8_t value); +void snmp_add_snmpintotalsetvars(u8_t value); +void snmp_inc_snmpingetrequests(void); +void snmp_inc_snmpingetnexts(void); +void snmp_inc_snmpinsetrequests(void); +void snmp_inc_snmpingetresponses(void); +void snmp_inc_snmpintraps(void); +void snmp_inc_snmpouttoobigs(void); +void snmp_inc_snmpoutnosuchnames(void); +void snmp_inc_snmpoutbadvalues(void); +void snmp_inc_snmpoutgenerrs(void); +void snmp_inc_snmpoutgetrequests(void); +void snmp_inc_snmpoutgetnexts(void); +void snmp_inc_snmpoutsetrequests(void); +void snmp_inc_snmpoutgetresponses(void); +void snmp_inc_snmpouttraps(void); +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); +void snmp_set_snmpenableauthentraps(u8_t *value); +void snmp_get_snmpenableauthentraps(u8_t *value); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* system */ +#define snmp_set_sysdesr(str, len) +#define snmp_set_sysobjid(oid); +#define snmp_get_sysobjid_ptr(oid) +#define snmp_inc_sysuptime() +#define snmp_add_sysuptime(value) +#define snmp_get_sysuptime(value) +#define snmp_set_syscontact(ocstr, ocstrlen); +#define snmp_set_sysname(ocstr, ocstrlen); +#define snmp_set_syslocation(ocstr, ocstrlen); + +/* network interface */ +#define snmp_add_ifinoctets(ni,value) +#define snmp_inc_ifinucastpkts(ni) +#define snmp_inc_ifinnucastpkts(ni) +#define snmp_inc_ifindiscards(ni) +#define snmp_add_ifoutoctets(ni,value) +#define snmp_inc_ifoutucastpkts(ni) +#define snmp_inc_ifoutnucastpkts(ni) +#define snmp_inc_ifoutdiscards(ni) +#define snmp_inc_iflist() +#define snmp_dec_iflist() + +/* ARP */ +#define snmp_insert_arpidx_tree(ni,ip) +#define snmp_delete_arpidx_tree(ni,ip) + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipinhdrerrors() +#define snmp_inc_ipinaddrerrors() +#define snmp_inc_ipforwdatagrams() +#define snmp_inc_ipinunknownprotos() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutnoroutes() +#define snmp_inc_ipreasmreqds() +#define snmp_inc_ipreasmoks() +#define snmp_inc_ipreasmfails() +#define snmp_inc_ipfragoks() +#define snmp_inc_ipfragfails() +#define snmp_inc_ipfragcreates() +#define snmp_inc_iproutingdiscards() +#define snmp_insert_ipaddridx_tree(ni) +#define snmp_delete_ipaddridx_tree(ni) +#define snmp_insert_iprteidx_tree(dflt, ni) +#define snmp_delete_iprteidx_tree(dflt, ni) + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors() +#define snmp_inc_icmpindestunreachs() +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs() +#define snmp_inc_icmpinsrcquenchs() +#define snmp_inc_icmpinredirects() +#define snmp_inc_icmpinechos() +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps() +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs() +#define snmp_inc_icmpouttimeexcds() +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects() +#define snmp_inc_icmpoutechos() +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() +#define snmp_insert_udpidx_tree(pcb) +#define snmp_delete_udpidx_tree(pcb) + +/* SNMP */ +#define snmp_inc_snmpinpkts() +#define snmp_inc_snmpoutpkts() +#define snmp_inc_snmpinbadversions() +#define snmp_inc_snmpinbadcommunitynames() +#define snmp_inc_snmpinbadcommunityuses() +#define snmp_inc_snmpinasnparseerrs() +#define snmp_inc_snmpintoobigs() +#define snmp_inc_snmpinnosuchnames() +#define snmp_inc_snmpinbadvalues() +#define snmp_inc_snmpinreadonlys() +#define snmp_inc_snmpingenerrs() +#define snmp_add_snmpintotalreqvars(value) +#define snmp_add_snmpintotalsetvars(value) +#define snmp_inc_snmpingetrequests() +#define snmp_inc_snmpingetnexts() +#define snmp_inc_snmpinsetrequests() +#define snmp_inc_snmpingetresponses() +#define snmp_inc_snmpintraps() +#define snmp_inc_snmpouttoobigs() +#define snmp_inc_snmpoutnosuchnames() +#define snmp_inc_snmpoutbadvalues() +#define snmp_inc_snmpoutgenerrs() +#define snmp_inc_snmpoutgetrequests() +#define snmp_inc_snmpoutgetnexts() +#define snmp_inc_snmpoutsetrequests() +#define snmp_inc_snmpoutgetresponses() +#define snmp_inc_snmpouttraps() +#define snmp_get_snmpgrpid_ptr(oid) +#define snmp_set_snmpenableauthentraps(value) +#define snmp_get_snmpenableauthentraps(value) + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_asn1.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_asn1.h new file mode 100644 index 0000000000..605fa3f16c --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_asn1.h @@ -0,0 +1,101 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_ASN1_H__ +#define __LWIP_SNMP_ASN1_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" + +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ +#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ +#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ + +#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ +#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ + +/* universal tags */ +#define SNMP_ASN1_INTEG 2 +#define SNMP_ASN1_OC_STR 4 +#define SNMP_ASN1_NUL 5 +#define SNMP_ASN1_OBJ_ID 6 +#define SNMP_ASN1_SEQ 16 + +/* application specific (SNMP) tags */ +#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */ +#define SNMP_ASN1_COUNTER 1 /* u32_t */ +#define SNMP_ASN1_GAUGE 2 /* u32_t */ +#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ +#define SNMP_ASN1_OPAQUE 4 /* octet string */ + +/* context specific (SNMP) tags */ +#define SNMP_ASN1_PDU_GET_REQ 0 +#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_PDU_GET_RESP 2 +#define SNMP_ASN1_PDU_SET_REQ 3 +#define SNMP_ASN1_PDU_TRAP 4 + +err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); +err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); +err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); +err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); +err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); +err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); +err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_msg.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_msg.h new file mode 100644 index 0000000000..1183e3a95b --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_msg.h @@ -0,0 +1,315 @@ +/** + * @file + * SNMP Agent message handling structures. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_MSG_H__ +#define __LWIP_SNMP_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/snmp.h" +#include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#if LWIP_SNMP + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to + this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't + work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +#define SNMP_ES_NOERROR 0 +#define SNMP_ES_TOOBIG 1 +#define SNMP_ES_NOSUCHNAME 2 +#define SNMP_ES_BADVALUE 3 +#define SNMP_ES_READONLY 4 +#define SNMP_ES_GENERROR 5 + +#define SNMP_GENTRAP_COLDSTART 0 +#define SNMP_GENTRAP_WARMSTART 1 +#define SNMP_GENTRAP_AUTHFAIL 4 +#define SNMP_GENTRAP_ENTERPRISESPC 6 + +struct snmp_varbind +{ + /* next pointer, NULL for last in list */ + struct snmp_varbind *next; + /* previous pointer, NULL for first in list */ + struct snmp_varbind *prev; + + /* object identifier length (in s32_t) */ + u8_t ident_len; + /* object identifier array */ + s32_t *ident; + + /* object value ASN1 type */ + u8_t value_type; + /* object value length (in u8_t) */ + u8_t value_len; + /* object value */ + void *value; + + /* encoding varbind seq length length */ + u8_t seqlenlen; + /* encoding object identifier length length */ + u8_t olenlen; + /* encoding object value length length */ + u8_t vlenlen; + /* encoding varbind seq length */ + u16_t seqlen; + /* encoding object identifier length */ + u16_t olen; + /* encoding object value length */ + u16_t vlen; +}; + +struct snmp_varbind_root +{ + struct snmp_varbind *head; + struct snmp_varbind *tail; + /* number of variable bindings in list */ + u8_t count; + /* encoding varbind-list seq length length */ + u8_t seqlenlen; + /* encoding varbind-list seq length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_resp_header_lengths +{ + /* encoding error-index length length */ + u8_t erridxlenlen; + /* encoding error-status length length */ + u8_t errstatlenlen; + /* encoding request id length length */ + u8_t ridlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding error-index length */ + u16_t erridxlen; + /* encoding error-status length */ + u16_t errstatlen; + /* encoding request id length */ + u16_t ridlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_trap_header_lengths +{ + /* encoding timestamp length length */ + u8_t tslenlen; + /* encoding specific-trap length length */ + u8_t strplenlen; + /* encoding generic-trap length length */ + u8_t gtrplenlen; + /* encoding agent-addr length length */ + u8_t aaddrlenlen; + /* encoding enterprise-id length length */ + u8_t eidlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding timestamp length */ + u16_t tslen; + /* encoding specific-trap length */ + u16_t strplen; + /* encoding generic-trap length */ + u16_t gtrplen; + /* encoding agent-addr length */ + u16_t aaddrlen; + /* encoding enterprise-id length */ + u16_t eidlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/* Accepting new SNMP messages. */ +#define SNMP_MSG_EMPTY 0 +/* Search for matching object for variable binding. */ +#define SNMP_MSG_SEARCH_OBJ 1 +/* Perform SNMP operation on in-memory object. + Pass-through states, for symmetry only. */ +#define SNMP_MSG_INTERNAL_GET_OBJDEF 2 +#define SNMP_MSG_INTERNAL_GET_VALUE 3 +#define SNMP_MSG_INTERNAL_SET_TEST 4 +#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 +#define SNMP_MSG_INTERNAL_SET_VALUE 6 +/* Perform SNMP operation on object located externally. + In theory this could be used for building a proxy agent. + Practical use is for an enterprise spc. app. gateway. */ +#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7 +#define SNMP_MSG_EXTERNAL_GET_VALUE 8 +#define SNMP_MSG_EXTERNAL_SET_TEST 9 +#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 +#define SNMP_MSG_EXTERNAL_SET_VALUE 11 + +#define SNMP_COMMUNITY_STR_LEN 64 +struct snmp_msg_pstat +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* source IP address */ + ip_addr_t sip; + /* source UDP port */ + u16_t sp; + /* request type */ + u8_t rt; + /* request ID */ + s32_t rid; + /* error status */ + s32_t error_status; + /* error index */ + s32_t error_index; + /* community name (zero terminated) */ + u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; + /* community string length (exclusive zero term) */ + u8_t com_strlen; + /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ + u8_t state; + /* saved arguments for MSG_EXTERNAL_x */ + struct mib_external_node *ext_mib_node; + struct snmp_name_ptr ext_name_ptr; + struct obj_def ext_object_def; + struct snmp_obj_id ext_oid; + /* index into input variable binding list */ + u8_t vb_idx; + /* ptr into input variable binding list */ + struct snmp_varbind *vb_ptr; + /* list of variable bindings from input */ + struct snmp_varbind_root invb; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output response lengths used in ASN encoding */ + struct snmp_resp_header_lengths rhl; +}; + +struct snmp_msg_trap +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* destination IP address in network order */ + ip_addr_t dip; + + /* source enterprise ID (sysObjectID) */ + struct snmp_obj_id *enterprise; + /* source IP address, raw network order format */ + u8_t sip_raw[4]; + /* generic trap code */ + u32_t gen_trap; + /* specific trap code */ + u32_t spc_trap; + /* timestamp */ + u32_t ts; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output trap lengths used in ASN encoding */ + struct snmp_trap_header_lengths thl; +}; + +/** Agent Version constant, 0 = v1 oddity */ +extern const s32_t snmp_version; +/** Agent default "public" community string */ +extern const char snmp_publiccommunity[7]; + +extern struct snmp_msg_trap trap_msg; + +/** Agent setup, start listening to port 161. */ +void snmp_init(void); +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); + +/** Varbind-list functions. */ +struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); +void snmp_varbind_free(struct snmp_varbind *vb); +void snmp_varbind_list_free(struct snmp_varbind_root *root); +void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); +struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); + +/** Handle an internal (recv) or external (private response) event. */ +void snmp_msg_event(u8_t request_id); +err_t snmp_send_response(struct snmp_msg_pstat *m_stat); +err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_structs.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_structs.h new file mode 100644 index 0000000000..0d3b46a928 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/snmp_structs.h @@ -0,0 +1,268 @@ +/** + * @file + * Generic MIB tree structures. + * + * @todo namespace prefixes + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_STRUCTS_H__ +#define __LWIP_SNMP_STRUCTS_H__ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MIB object instance */ +#define MIB_OBJECT_NONE 0 +#define MIB_OBJECT_SCALAR 1 +#define MIB_OBJECT_TAB 2 + +/* MIB access types */ +#define MIB_ACCESS_READ 1 +#define MIB_ACCESS_WRITE 2 + +/* MIB object access */ +#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ +#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) +#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE +#define MIB_OBJECT_NOT_ACCESSIBLE 0 + +/** object definition returned by (get_object_def)() */ +struct obj_def +{ + /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ + u8_t instance; + /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ + u8_t access; + /* ASN type for this object */ + u8_t asn_type; + /* value length (host length) */ + u16_t v_len; + /* length of instance part of supplied object identifier */ + u8_t id_inst_len; + /* instance part of supplied object identifier */ + s32_t *id_inst_ptr; +}; + +struct snmp_name_ptr +{ + u8_t ident_len; + s32_t *ident; +}; + +/** MIB const scalar (.0) node */ +#define MIB_NODE_SC 0x01 +/** MIB const array node */ +#define MIB_NODE_AR 0x02 +/** MIB array node (mem_malloced from RAM) */ +#define MIB_NODE_RA 0x03 +/** MIB list root node (mem_malloced from RAM) */ +#define MIB_NODE_LR 0x04 +/** MIB node for external objects */ +#define MIB_NODE_EX 0x05 + +/** node "base class" layout, the mandatory fields for a node */ +struct mib_node +{ + /** returns struct obj_def for the given object identifier */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + /** returns object value for the given object identifier, + @note the caller must allocate at least len bytes for the value */ + void (*get_value)(struct obj_def *od, u16_t len, void *value); + /** tests length and/or range BEFORE setting */ + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + /** sets object value, only to be called when set_test() */ + void (*set_value)(struct obj_def *od, u16_t len, void *value); + /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ + u8_t node_type; + /* array or max list length */ + u16_t maxlength; +}; + +/** derived node for scalars .0 index */ +typedef struct mib_node mib_scalar_node; + +/** derived node, points to a fixed size const array + of sub-identifiers plus a 'child' pointer */ +struct mib_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + const s32_t *objid; + struct mib_node* const *nptr; +}; + +/** derived node, points to a fixed size mem_malloced array + of sub-identifiers plus a 'child' pointer */ +struct mib_ram_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* aditional struct members */ + s32_t *objid; + struct mib_node **nptr; +}; + +struct mib_list_node +{ + struct mib_list_node *prev; + struct mib_list_node *next; + s32_t objid; + struct mib_node *nptr; +}; + +/** derived node, points to a doubly linked list + of sub-identifiers plus a 'child' pointer */ +struct mib_list_rootnode +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + struct mib_list_node *head; + struct mib_list_node *tail; + /* counts list nodes in list */ + u16_t count; +}; + +/** derived node, has access functions for mib object in external memory or device + using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ +struct mib_external_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + /** points to an external (in memory) record of some sort of addressing + information, passed to and interpreted by the funtions below */ + void* addr_inf; + /** tree levels under this node */ + u8_t tree_levels; + /** number of objects at this level */ + u16_t (*level_length)(void* addr_inf, u8_t level); + /** compares object sub identifier with external id + return zero when equal, nonzero when unequal */ + s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); + void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); + + /** async Questions */ + void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_q)(u8_t rid, struct obj_def *od); + void (*set_test_q)(u8_t rid, struct obj_def *od); + void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Answers */ + void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Panic Close (agent returns error reply, + e.g. used for external transaction cleanup) */ + void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_pc)(u8_t rid, struct obj_def *od); + void (*set_test_pc)(u8_t rid, struct obj_def *od); + void (*set_value_pc)(u8_t rid, struct obj_def *od); +}; + +/** export MIB tree from mib2.c */ +extern const struct mib_array_node internet; + +/** dummy function pointers for non-leaf MIB nodes from mib2.c */ +void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +void noleafs_get_value(struct obj_def *od, u16_t len, void *value); +u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); +void noleafs_set_value(struct obj_def *od, u16_t len, void *value); + +void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); +void snmp_iptooid(ip_addr_t *ip, s32_t *ident); +void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); +void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); + +struct mib_list_node* snmp_mib_ln_alloc(s32_t id); +void snmp_mib_ln_free(struct mib_list_node *ln); +struct mib_list_rootnode* snmp_mib_lrn_alloc(void); +void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); + +s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); +s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); +struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); + +struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); +struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); +u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); +u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sntp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sntp.h new file mode 100644 index 0000000000..e0d523be1e --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sntp.h @@ -0,0 +1,60 @@ +#ifndef LWIP_SNTP_H +#define LWIP_SNTP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long time_t; + +/** The maximum number of SNTP servers that can be set */ +#ifndef SNTP_MAX_SERVERS +#define SNTP_MAX_SERVERS 3 +#endif + +/** Set this to 1 to implement the callback function called by dhcp when + * NTP servers are received. */ +#ifndef SNTP_GET_SERVERS_FROM_DHCP +#define SNTP_GET_SERVERS_FROM_DHCP 0//LWIP_DHCP_GET_NTP_SRV +#endif + +/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */ +#ifndef SNTP_SERVER_DNS +#define SNTP_SERVER_DNS 1 +#endif + +bool sntp_get_timetype(void); +void sntp_set_receive_time_size(void); +/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * #define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +uint32 sntp_get_current_timestamp(); +char* sntp_get_real_time(long t); + +void sntp_init(void); +void sntp_stop(void); + +sint8 sntp_get_timezone(void); +bool sntp_set_timezone(sint8 timezone); +void sntp_setserver(u8_t idx, ip_addr_t *addr); +ip_addr_t sntp_getserver(u8_t idx); + +#if SNTP_SERVER_DNS +void sntp_setservername(u8_t idx, char *server); +char *sntp_getservername(u8_t idx); +#endif /* SNTP_SERVER_DNS */ + +#if SNTP_GET_SERVERS_FROM_DHCP +void sntp_servermode_dhcp(int set_servers_from_dhcp); +#else /* SNTP_GET_SERVERS_FROM_DHCP */ +#define sntp_servermode_dhcp(x) +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNTP_H */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sockets.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sockets.h new file mode 100644 index 0000000000..3c8fed24e6 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sockets.h @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + u8_t sin_family; + u16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr { + u8_t sa_len; + u8_t sa_family; + char sa_data[14]; +}; + +#ifndef socklen_t +# define socklen_t u32_t +#endif + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ + +#define SO_DONTLINGER ((int)(~SO_LINGER)) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define IPPROTO_UDPLITE 136 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET + #undef FD_SETSIZE + /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ + #define FD_SETSIZE MEMP_NUM_NETCONN + #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) + #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) + #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) + #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) + + typedef struct fd_set { + unsigned char fd_bits [(FD_SETSIZE+7)/8]; + } fd_set; + +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define shutdown(a,b) lwip_shutdown(a,b) +#define closesocket(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#define getsockname(a,b,c) lwip_getsockname(a,b,c) +#define getpeername(a,b,c) lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b) lwip_listen(a,b) +#define recv(a,b,c,d) lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket(a,b,c) +#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c) lwip_read(a,b,c) +#define write(a,b,c) lwip_write(a,b,c) +#define close(s) lwip_close(s) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/stats.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/stats.h new file mode 100644 index 0000000000..43883217ec --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/stats.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +struct stats_mem { +#ifdef LWIP_DEBUG + const char *name; +#endif /* LWIP_DEBUG */ + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER err; + STAT_COUNTER illegal; +}; + +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +struct stats_ { +#if LINK_STATS + struct stats_proto link; +#endif +#if ETHARP_STATS + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + struct stats_proto ip_frag; +#endif +#if IP_STATS + struct stats_proto ip; +#endif +#if ICMP_STATS + struct stats_proto icmp; +#endif +#if IGMP_STATS + struct stats_igmp igmp; +#endif +#if UDP_STATS + struct stats_proto udp; +#endif +#if TCP_STATS + struct stats_proto tcp; +#endif +#if MEM_STATS + struct stats_mem mem; +#endif +#if MEMP_STATS + struct stats_mem memp[MEMP_MAX]; +#endif +#if SYS_STATS + struct stats_sys sys; +#endif +}; + +extern struct stats_ lwip_stats; + +void stats_init(void)ICACHE_FLASH_ATTR; + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void)ICACHE_FLASH_ATTR; +void stats_display_proto(struct stats_proto *proto, char *name)ICACHE_FLASH_ATTR; +void stats_display_igmp(struct stats_igmp *igmp)ICACHE_FLASH_ATTR; +void stats_display_mem(struct stats_mem *mem, char *name)ICACHE_FLASH_ATTR; +void stats_display_memp(struct stats_mem *mem, int index)ICACHE_FLASH_ATTR; +void stats_display_sys(struct stats_sys *sys)ICACHE_FLASH_ATTR; +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_STATS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sys.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sys.h new file mode 100644 index 0000000000..31a9dea741 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/sys.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "lwip/opt.h" + +#include "eagle_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** Set a mutex invalid so that sys_mutex_valid returns 0 */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** Signals a semaphore + * @param sem the semaphore to signal */ +void sys_sem_signal(sys_sem_t *sem); +/** Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** Delete a semaphore + * @param sem semaphore to delete */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** Set a semaphore invalid so that sys_sem_valid returns 0 */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif + +/* Mailbox functions. */ + +/** Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (miminum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** For now, we map straight to sys_arch implementation. */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** Delete an mbox + * @param mbox mbox to delete */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** Set an mbox invalid so that sys_mbox_valid returns 0 */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif + +/** The only thread function: + * Creates a new thread + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/* sys_init() must be called before anthing else. */ +void sys_init(void)ICACHE_FLASH_ATTR; + +#ifndef sys_jiffies +/** Ticks/jiffies since power up. */ +u32_t sys_jiffies(void)ICACHE_FLASH_ATTR; +#endif + +/** Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. */ +static inline u32_t sys_now(void) ICACHE_FLASH_ATTR; +static inline u32_t sys_now(void) +{ + return NOW()/(TIMER_CLK_FREQ/1000); +} + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void)ICACHE_FLASH_ATTR; +void sys_arch_unprotect(sys_prot_t pval)ICACHE_FLASH_ATTR; + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) lev = os_intr_lock() //fix by ives at 2014.3.24 +#define SYS_ARCH_UNPROTECT(lev) lev = os_intr_unlock() + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SYS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp.h new file mode 100644 index 0000000000..909ff9b70b --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) TODO! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. + * @param arg user-supplied argument (tcp_pcb.callback_arg) + * @param pcb a new tcp_pcb that now is connected + * @param err an error argument (TODO: that is current always ERR_OK?) + * @return ERR_OK: accept the new connection, + * any other err_t abortsthe new connection + */ +#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + void *callback_arg; \ + /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ + DEF_ACCEPT_CALLBACK \ + /* ports are in host byte order */ \ + u16_t local_port + + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + u8_t flags; +#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */ +#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ +#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ +#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ +#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */ +#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + u16_t rcv_wnd; /* receiver window available */ + u16_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + + /* Timers */ + u32_t tmr; + u8_t polltmr, pollinterval; + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + s16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u32_t lastack; /* Highest acknowledged seqno. */ + u8_t dupacks; + + /* congestion avoidance/control variables */ + u16_t cwnd; + u16_t ssthresh; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u16_t snd_wnd; /* sender window */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + + u16_t acked; + + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) + u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u32_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; +}; + +struct tcp_pcb_listen { +/* Common members of all PCB types */ + IP_PCB; +/* Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void)ICACHE_FLASH_ATTR; + +void tcp_arg (struct tcp_pcb *pcb, void *arg) ICACHE_FLASH_ATTR; +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept) ICACHE_FLASH_ATTR; +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv) ICACHE_FLASH_ATTR; +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent)ICACHE_FLASH_ATTR; +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)ICACHE_FLASH_ATTR; +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err)ICACHE_FLASH_ATTR; + +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#define tcp_sndbuf(pcb) ((pcb)->snd_buf) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) + +#if TCP_LISTEN_BACKLOG +#define tcp_accepted(pcb) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ + (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ + pcb->state == LISTEN) +#endif /* TCP_LISTEN_BACKLOG */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len)ICACHE_FLASH_ATTR; +err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected)ICACHE_FLASH_ATTR; + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)ICACHE_FLASH_ATTR; +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_close (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)ICACHE_FLASH_ATTR; + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags)ICACHE_FLASH_ATTR; + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio)ICACHE_FLASH_ATTR; + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +extern err_t tcp_output(struct tcp_pcb *pcb); + + +const char* tcp_debug_state_str(enum tcp_state s)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp_impl.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp_impl.h new file mode 100644 index 0000000000..f6778700af --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcp_impl.h @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_IMPL_H__ +#define __LWIP_TCP_IMPL_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, no init needed. */ +void tcp_tmr (void)ICACHE_FLASH_ATTR; /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void)ICACHE_FLASH_ATTR; +void tcp_fasttmr (void)ICACHE_FLASH_ATTR; + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio)ICACHE_FLASH_ATTR; +void tcp_abandon (struct tcp_pcb *pcb, int reset)ICACHE_FLASH_ATTR; +err_t tcp_send_empty_ack(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_rto (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_fast (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 125 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 120000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 10000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); //Դ�˿� + PACK_STRUCT_FIELD(u16_t dest); //Ŀ�Ķ˿� + PACK_STRUCT_FIELD(u32_t seqno); //��� + PACK_STRUCT_FIELD(u32_t ackno); //Ӧ����� + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//�ײ�����+����λ+��־λ + PACK_STRUCT_FIELD(u16_t wnd); //���ڴ�С + PACK_STRUCT_FIELD(u16_t chksum); //��� + PACK_STRUCT_FIELD(u16_t urgp); //����ָ�� +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ + LWIP_EVENT_ERR, NULL, 0, (err)) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + do { \ + if((pcb)->accept != NULL) \ + (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(errf,arg,err) \ + do { \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segements on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + void *dataptr; /* pointer to the TCP data in the pbuf */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversized only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ + (flags & TF_SEG_OPTS_TS ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ + ((u32_t)4 << 16) | \ + (((u32_t)TCP_MSS / 256) << 8) | \ + (TCP_MSS & 255)) + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for(tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + +#define TCP_TW_LIMIT(l) \ + do { \ + u32_t tcp_tmp_pcbs_count = 0; \ + tcp_tmp_pcb = tcp_tw_pcbs; \ + while(tcp_tmp_pcb != NULL) { \ + if(++tcp_tmp_pcbs_count == (l)) { \ + struct tcp_pcb *_tcp_tmp_pcb = tcp_tmp_pcb->next; \ + tcp_tmp_pcb->next = NULL; \ + tcp_tmp_pcb = _tcp_tmp_pcb; \ + while(tcp_tmp_pcb != NULL) { \ + _tcp_tmp_pcb = tcp_tmp_pcb; \ + tcp_pcb_purge(tcp_tmp_pcb); \ + tcp_tmp_pcb = tcp_tmp_pcb->next; \ + memp_free(MEMP_TCP_PCB, _tcp_tmp_pcb); \ + } \ + break; \ + } \ + tcp_tmp_pcb = tcp_tmp_pcb->next; \ + } \ + } while(0) + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_purge(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +void tcp_segs_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +void tcp_seg_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)ICACHE_FLASH_ATTR; + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +void tcp_rst(u32_t seqno, u32_t ackno, + ip_addr_t *local_ip, ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port)ICACHE_FLASH_ATTR; + +u32_t tcp_next_iss(void)ICACHE_FLASH_ATTR; + +void tcp_keepalive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_zero_window_probe(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)ICACHE_FLASH_ATTR; +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)ICACHE_FLASH_ATTR; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr)ICACHE_FLASH_ATTR; +void tcp_debug_print_flags(u8_t flags)ICACHE_FLASH_ATTR; +void tcp_debug_print_state(enum tcp_state s)ICACHE_FLASH_ATTR; +void tcp_debug_print_pcbs(void)ICACHE_FLASH_ATTR; +s16_t tcp_pcbs_sane(void)ICACHE_FLASH_ATTR; +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcpip.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcpip.h new file mode 100644 index 0000000000..995ba8ad00 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/tcpip.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" +#include "lwip/netifapi.h" +#include "lwip/pbuf.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. */ +#ifndef LWIP_TCPIP_THREAD_ALIVE +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m) +#define TCPIP_APIMSG_ACK(m) +#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) +#define TCPIP_NETIFAPI_ACK(m) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#define TCPIP_APIMSG(m) tcpip_apimsg(m) +#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) +#define TCPIP_NETIFAPI(m) tcpip_netifapi(m) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_apimsg_lock(struct api_msg *apimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +#if LWIP_NETIF_API +err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT */ + +enum tcpip_msg_type { +#if LWIP_NETCONN + TCPIP_MSG_API, +#endif /* LWIP_NETCONN */ + TCPIP_MSG_INPKT, +#if LWIP_NETIF_API + TCPIP_MSG_NETIFAPI, +#endif /* LWIP_NETIF_API */ +#if LWIP_TCPIP_TIMEOUT + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT */ + TCPIP_MSG_CALLBACK +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + sys_sem_t *sem; + union { +#if LWIP_NETCONN + struct api_msg *apimsg; +#endif /* LWIP_NETCONN */ +#if LWIP_NETIF_API + struct netifapi_msg *netifapimsg; +#endif /* LWIP_NETIF_API */ + struct { + struct pbuf *p; + struct netif *netif; + } inp; + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/timers.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/timers.h new file mode 100644 index 0000000000..e9db02a2f4 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/timers.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef __LWIP_TIMERS_H__ +#define __LWIP_TIMERS_H__ + +#include "lwip/opt.h" + +/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) + +#if LWIP_TIMERS + +#include "lwip/err.h" +#include "lwip/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void)ICACHE_FLASH_ATTR; + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)ICACHE_FLASH_ATTR; +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#if NO_SYS +void sys_check_timeouts(void)ICACHE_FLASH_ATTR; +void sys_restart_timeouts(void)ICACHE_FLASH_ATTR; +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TIMERS */ +#endif /* __LWIP_TIMERS_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwip/udp.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/udp.h new file mode 100644 index 0000000000..2e4b57ae75 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwip/udp.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf + * makes 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *addr, u16_t port); + + +struct udp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_IGMP + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; +#ifndef LWIP_MAYBE_XCC + /** TTL for outgoing multicast packets */ + u8_t mcast_ttl; +#endif /* LWIP_MAYBE_XCC */ +#endif /* LWIP_IGMP */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void)ICACHE_FLASH_ATTR; +void udp_remove (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +void udp_disconnect (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg)ICACHE_FLASH_ATTR; +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif)ICACHE_FLASH_ATTR; +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port)ICACHE_FLASH_ATTR; +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p)ICACHE_FLASH_ATTR; + +#if LWIP_CHECKSUM_ON_COPY +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; + +#define udp_init() /* Compatibility define, not init needed. */ + +#if LWIP_IGMP +#define udp_set_multicast_netif_addr(pcb, ipaddr) ip_addr_copy((pcb)->multicast_ip, (ipaddr)) +#define udp_get_multicast_netif_addr(pcb) ((pcb)->multicast_ip) +#ifndef LWIP_MAYBE_XCC +#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) +#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) +#endif /* LWIP_MAYBE_XCC */ +#endif /* LWIP_IGMP */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr)ICACHE_FLASH_ATTR; +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/lwipopts.h b/Sming/third-party/lwip2/glue-esp/include-esp/lwipopts.h new file mode 100644 index 0000000000..19841c2374 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/lwipopts.h @@ -0,0 +1,2083 @@ + +// do not modify this file +// it reflects espressifs data structures used in blobs +// to which we are linked + +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#define PBUF_RSV_FOR_WLAN +#define EBUF_LWIP + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 0 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 1 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 1 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 16000 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 1 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 1 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 10 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#endif + +/** + * MEMP_NUM_TCP_PCB_TIME_WAIT: the number of TCP pcbs in TIME_WAIT state. + * (requires the LWIP_TCP option, 0 = disabled) + */ +#ifndef MEMP_NUM_TCP_PCB_TIME_WAIT +#define MEMP_NUM_TCP_PCB_TIME_WAIT 5 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 0 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 0 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 10 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 8 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 0 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 0 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 4 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 0 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 0 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 0 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 0 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 0 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 0 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 0 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 10 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 1 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 1 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 0 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 1 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 128 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 1 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * DHCP_MAXRTX: Maximum number of retries of current request. + */ +#ifndef DHCP_MAXRTX +#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 0 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 0 +#endif + +/** + * SNMP_PRIVATE_MIB: + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 0 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 1 +#endif +/* + ---------------------------------- + ---------- MDNS options ---------- + ---------------------------------- +*/ +/** + * LWIP_MDNS==1: Turn on MDNS module. + */ +#ifndef LWIP_MDNS +#define LWIP_MDNS 1 +#endif + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 1 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (*(volatile uint32*)0x600011F0) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) +#endif + +/** + * TCP_MAXRTO: Maximum retransmission timeout of data segments. + */ +#ifndef TCP_MAXRTO +#define TCP_MAXRTO 10 +#endif + +/** + * TCP_MINRTO: Minimum retransmission timeout of data segments. + */ +#ifndef TCP_MINRTO +#define TCP_MINRTO 2 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 1 +#endif + +#if 1 +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 1460 +#endif +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 2 * TCP_MSS +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#define LWIP_EVENT_API 1 +#define LWIP_CALLBACK_API 0 +#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 1 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 0 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 0 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 1 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 1 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 0 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else +#define ETHARP_STATS 0 +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/netif/etharp.h b/Sming/third-party/lwip2/glue-esp/include-esp/netif/etharp.h new file mode 100644 index 0000000000..2092ab7a1c --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/netif/etharp.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN 6 +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** Ethernet header */ +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#if ETHARP_SUPPORT_VLAN + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ +struct eth_vlan_hdr { + PACK_STRUCT_FIELD(u16_t tpid); + PACK_STRUCT_FIELD(u16_t prio_vid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF) + +#endif /* ETHARP_SUPPORT_VLAN */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message, see RFC 826 ("Packet format") */ +struct etharp_hdr { + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FIELD(u8_t hwlen); + PACK_STRUCT_FIELD(u8_t protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FIELD(struct eth_addr shwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); + PACK_STRUCT_FIELD(struct eth_addr dhwaddr); + PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETHARP_HDR 28 +#define SIZEOF_ETHARP_MINSIZE 46 +#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) +#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE) + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP 0x0806 +#define ETHTYPE_IP 0x0800 +#define ETHTYPE_VLAN 0x8100 +#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHTYPE_PAE 0x888e + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables + * or known to be 32-bit aligned within the protocol header. */ +#ifndef ETHADDR32_COPY +#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local + * variables and known to be 16-bit aligned within the protocol header. */ +#ifndef ETHADDR16_COPY +#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +/** ARP message types (opcodes) */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct etharp_q_entry { + struct etharp_q_entry *next; + struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, not init needed. */ +void etharp_tmr(void)ICACHE_FLASH_ATTR; +s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR; +err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR; +err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) +void etharp_cleanup_netif(struct netif *netif); + +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR; +err_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, + const u16_t opcode)ICACHE_FLASH_ATTR; +#endif /* LWIP_AUTOIP */ + +#endif /* LWIP_ARP */ + +err_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR; + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) + +extern const struct eth_addr ethbroadcast, ethzero; + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#if 0 +/** Ethernet header */ +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN 6 +#endif + + +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; + + +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_ARP_H__ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/netif/if_llc.h b/Sming/third-party/lwip2/glue-esp/include-esp/netif/if_llc.h new file mode 100644 index 0000000000..ca09b38687 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/netif/if_llc.h @@ -0,0 +1,173 @@ +/* $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ */ + +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_llc.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD$ + */ + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcommings in many + * compilers. + */ + +struct llc { + uint8_t llc_dsap; + uint8_t llc_ssap; + union { + struct { + uint8_t control; + uint8_t format_id; + uint8_t class; + uint8_t window_x2; + } __packed type_u; + struct { + uint8_t num_snd_x2; + uint8_t num_rcv_x2; + } __packed type_i; + struct { + uint8_t control; + uint8_t num_rcv_x2; + } __packed type_s; + struct { + uint8_t control; + /* + * We cannot put the following fields in a structure because + * the structure rounding might cause padding. + */ + uint8_t frmr_rej_pdu0; + uint8_t frmr_rej_pdu1; + uint8_t frmr_control; + uint8_t frmr_control_ext; + uint8_t frmr_cause; + } __packed type_frmr; + struct { + uint8_t control; + uint8_t org_code[3]; + uint16_t ether_type; + } __packed type_snap; + struct { + uint8_t control; + uint8_t control_ext; + } __packed type_raw; + } __packed llc_un; +} __packed; + +struct frmrinfo { + uint8_t frmr_rej_pdu0; + uint8_t frmr_rej_pdu1; + uint8_t frmr_control; + uint8_t frmr_control_ext; + uint8_t frmr_cause; +} __packed; + +#define llc_control llc_un.type_u.control +#define llc_control_ext llc_un.type_raw.control_ext +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmr_cause +#define llc_snap llc_un.type_snap + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 +#define LLC_SNAPFRAMELEN 8 + +#ifdef CTASSERT +CTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN); +#endif + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_8021D_LSAP 0x42 +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +#define RFC1042_LEN 6 +#define RFC1042 {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00} +#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8} + +/* + * copied from sys/net/ethernet.h + */ +#define ETHERTYPE_AARP 0x80F3 /* AppleTalk AARP */ +#define ETHERTYPE_IPX 0x8137 /* Novell (old) NetWare IPX (ECONFIG E option) */ + + + +#endif /* _NET_IF_LLC_H_ */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/netif/ppp_oe.h b/Sming/third-party/lwip2/glue-esp/include-esp/netif/ppp_oe.h new file mode 100644 index 0000000000..e1cdfa5199 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/netif/ppp_oe.h @@ -0,0 +1,190 @@ +/***************************************************************************** +* ppp_oe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT > 0 + +#include "netif/etharp.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { + PACK_STRUCT_FIELD(u8_t vertype); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +#define PPPOE_STATE_CLOSING 4 +/* passive */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +#ifndef ETHERMTU +#define ETHERMTU 1500 +#endif + +/* two byte PPP protocol discriminator, then IP data */ +#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2) + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif + +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + int sc_pd; /* ppp unit number */ + void (*sc_linkStatusCB)(int pd, int up); + + int sc_state; /* discovery phase or session connected */ + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + +#ifdef PPPOE_TODO + char *sc_service_name; /* if != NULL: requested name of service */ + char *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_TODO */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + size_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + size_t sc_hunique_len; /* length of host unique */ +#endif + int sc_padi_retried; /* number of PADI retries already done */ + int sc_padr_retried; /* number of PADR retries already done */ +}; + + +#define pppoe_init() /* compatibility define, no initialization needed */ + +err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); +err_t pppoe_destroy(struct netif *ifp); + +int pppoe_connect(struct pppoe_softc *sc); +void pppoe_disconnect(struct pppoe_softc *sc); + +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); + +/** used in ppp.c */ +#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN) + +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_OE_H */ diff --git a/Sming/third-party/lwip2/glue-esp/include-esp/netif/wlan_lwip_if.h b/Sming/third-party/lwip2/glue-esp/include-esp/netif/wlan_lwip_if.h new file mode 100644 index 0000000000..ed9c477562 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/include-esp/netif/wlan_lwip_if.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010-2011 Espressif System + * +*/ + +#ifndef _WLAN_LWIP_IF_H_ +#define _WLAN_LWIP_IF_H_ + +#define LWIP_IF0_PRIO 28 +#define LWIP_IF1_PRIO 29 + +enum { + SIG_LWIP_RX = 0, +}; + +struct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info); +struct netif * eagle_lwip_getif(uint8 index); + +#ifndef IOT_SIP_MODE +sint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb); +#else +sint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb); +#endif + +#endif /* _WLAN_LWIP_IF_H_ */ diff --git a/Sming/third-party/lwip2/glue-esp/lwip-esp.c b/Sming/third-party/lwip2/glue-esp/lwip-esp.c new file mode 100644 index 0000000000..7e2cd4add8 --- /dev/null +++ b/Sming/third-party/lwip2/glue-esp/lwip-esp.c @@ -0,0 +1,956 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + +// esp(lwip1.4) side of glue for esp8266 +// - sdk-2.0.0(656edbf) +// - sdk-2.1.0(116b762) + +// todo: get rid of esp_guess_netif_idx() + +#include "arch/cc.h" +#include "lwip/timers.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" +#include "netif/etharp.h" +#include "lwip/mem.h" + +#include "glue.h" + +#define DBG "lwESP: " +#define STUB(x) do { uerror("STUB: " #x "\n"); } while (0) + +// guessed interface, esp blobs +void system_pp_recycle_rx_pkt (void*); +void system_station_got_ip_set(ip_addr_t* ip, ip_addr_t* mask, ip_addr_t* gw); + +// ethbroadcast linked from blobs +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +// linked from blobs +struct netif *netif_default; + +/////////////////////////////////////// +// from pbuf.c +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) +// from pbuf.h +#ifndef PBUF_RSV_FOR_WLAN +#error PBUF_RSV_FOR_WLAN should be defined +#endif +#ifndef EBUF_LWIP +#error EBUF_LWIP should be defined +#endif +#define EP_OFFSET 36 + +/////////////////////////////////////// +// netif + +#define netif_sta netif_esp[STATION_IF] // hardly used +#define netif_ap netif_esp[SOFTAP_IF] // hardly used +static struct netif* netif_esp[2] = { NULL, NULL }; + +/////////////////////////////////////// +// glue converters + +err_t glue2esp_err (err_glue_t err) +{ + switch (err) + { + case GLUE_ERR_OK : return ERR_OK; + case GLUE_ERR_MEM : return ERR_MEM; + case GLUE_ERR_BUF : return ERR_BUF; + case GLUE_ERR_TIMEOUT : return ERR_TIMEOUT; + case GLUE_ERR_RTE : return ERR_RTE; + case GLUE_ERR_INPROGRESS : return ERR_INPROGRESS; + case GLUE_ERR_VAL : return ERR_VAL; + case GLUE_ERR_WOULDBLOCK : return ERR_WOULDBLOCK; + case GLUE_ERR_ABRT : return ERR_ABRT; + case GLUE_ERR_RST : return ERR_RST; + case GLUE_ERR_CLSD : return ERR_CLSD; + case GLUE_ERR_CONN : return ERR_CONN; + case GLUE_ERR_ARG : return ERR_ARG; + case GLUE_ERR_USE : return ERR_USE; + case GLUE_ERR_IF : return ERR_IF; + case GLUE_ERR_ISCONN : return ERR_ISCONN; + + /* old does not have: */ + case GLUE_ERR_ALREADY : return ERR_ABRT; + + default: return ERR_ABRT; + } +}; + +err_glue_t esp2glue_err (err_glue_t err) +{ + switch (err) + { + case ERR_OK : return GLUE_ERR_OK; + case ERR_MEM : return GLUE_ERR_MEM; + case ERR_BUF : return GLUE_ERR_BUF; + case ERR_TIMEOUT : return GLUE_ERR_TIMEOUT; + case ERR_RTE : return GLUE_ERR_RTE; + case ERR_INPROGRESS : return GLUE_ERR_INPROGRESS; + case ERR_VAL : return GLUE_ERR_VAL; + case ERR_WOULDBLOCK : return GLUE_ERR_WOULDBLOCK; + case ERR_ABRT : return GLUE_ERR_ABRT; + case ERR_RST : return GLUE_ERR_RST; + case ERR_CLSD : return GLUE_ERR_CLSD; + case ERR_CONN : return GLUE_ERR_CONN; + case ERR_ARG : return GLUE_ERR_ARG; + case ERR_USE : return GLUE_ERR_USE; + case ERR_IF : return GLUE_ERR_IF; + case ERR_ISCONN : return GLUE_ERR_ISCONN; + + default: return GLUE_ERR_ABRT; + } +}; + + +glue_netif_flags_t esp2glue_netif_flags (u8_t flags) +{ + +//XXXFIXME this is the paranoia mode +// make it simpler in non-debug mode + + u8_t copy = flags; + glue_netif_flags_t gf = 0; + #define CF(x) do { if (flags & NETIF_FLAG_##x) { gf |= GLUE_NETIF_FLAG_##x; flags &= ~NETIF_FLAG_##x; } } while (0) + CF(UP); + CF(BROADCAST); + //CF(POINTTOPOINT); + //CF(DHCP); + CF(LINK_UP); + CF(ETHARP); + //CF(ETHERNET); + CF(IGMP); + #undef CF + + if (flags) + uerror("ERROR: esp2glue_netif_flags: remaining flags not converted (0x%x->0x%x)\n", copy, flags); + return gf; +} + +/////////////////////////////////////// +// display helpers + +#if UDEBUG + +#define stub_display_ip(pre,ip) display_ip32(pre, (ip).addr) + +static void stub_display_netif_flags (int flags) +{ + #define IFF(x) do { if (flags & NETIF_FLAG_##x) uprint("|" #x); } while (0) + IFF(UP); + IFF(BROADCAST); + IFF(POINTTOPOINT); + IFF(DHCP); + IFF(LINK_UP); + IFF(ETHARP); + IFF(ETHERNET); + IFF(IGMP); + #undef IFF +} + +static void stub_display_netif (struct netif* netif) +{ + uprint("esp-@%p idx=%d %s name=%c%c%d state=%p ", + netif, netif->num, + netif->num == SOFTAP_IF? "AP": netif->num == STATION_IF? "STA": "???", + netif->name[0], netif->name[1], netif->num, + netif->state); + if (netif->hwaddr_len == 6) + display_mac(netif->hwaddr); + else + uprint("(no mac?)"); + stub_display_netif_flags(netif->flags); + display_ip32(" ip=", netif->ip_addr.addr); + display_ip32(" mask=", netif->netmask.addr); + display_ip32(" gw=", netif->gw.addr); + uprint("\n"); +} + +void pbuf_info (const char* what, pbuf_layer layer, u16_t length, pbuf_type type) +{ + uerror(DBG "%s layer=%s(%d) len=%d type=%s(%d)\n", + what, + layer==PBUF_TRANSPORT? "transport": + layer==PBUF_IP? "ip": + layer==PBUF_LINK? "link": + layer==PBUF_RAW? "raw": + "???", (int)layer, + length, + type==PBUF_RAM? "ram": + type==PBUF_ROM? "rom": + type==PBUF_REF? "ref": + type==PBUF_POOL? "pool": + type==PBUF_ESF_RX? "esp-wlan": + "???", (int)type); +} + +#else // !UDEBUG + +#define stub_display_netif_flags(x) do { (void)0; } while (0) +#define stub_display_netif(x) do { (void)0; } while (0) +#define pbuf_info(x,y,z,w) do { (void)0; } while (0) + +#endif // !UDEBUG + +/////////////////////////////////////// +// quick pool to store references to data sent + +#define PBUF_CUSTOM_TYPE_POOLED 0x42 // must not conflict with PBUF_* (pbuf types) +#define PBUF_WRAPPER_BLOCK 8 + +struct pbuf_wrapper +{ + struct pbuf pbuf; // must be first in pbuf_wrapper + void* ref2save; // pointer to keep aside this pbuf + struct pbuf_wrapper* next; // chain of unused +}; + +struct pbuf_wrapper* pbuf_wrapper_head = NULL; // first free + +struct pbuf_wrapper* pbuf_wrapper_get (void) +{ + ets_intr_lock(); + + if (!pbuf_wrapper_head) + { + struct pbuf_wrapper* p = (struct pbuf_wrapper*)os_malloc(sizeof(struct pbuf_wrapper) * PBUF_WRAPPER_BLOCK); + if (!p) + { + ets_intr_unlock(); + return NULL; + } + for (int i = 0; i < PBUF_WRAPPER_BLOCK; i++) + { + p->pbuf.type = PBUF_CUSTOM_TYPE_POOLED; // constant + p->pbuf.flags = 0; // constant + p->pbuf.next = NULL; // constant + p->pbuf.eb = NULL; // constant + p->next = i? p - 1: NULL; + p++; + } + pbuf_wrapper_head = p - 1; + } + struct pbuf_wrapper* ret = pbuf_wrapper_head; + pbuf_wrapper_head = pbuf_wrapper_head->next; + + ets_intr_unlock(); + + return ret; +} + +static void pbuf_wrapper_release (struct pbuf_wrapper* p) +{ + // make it the new head in the chain of unused + ets_intr_lock(); + + p->next = pbuf_wrapper_head; + pbuf_wrapper_head = p; + + ets_intr_unlock(); +} + +err_glue_t glue2esp_linkoutput (int netif_idx, void* ref2save, void* data, size_t size) +{ + struct pbuf_wrapper* p = pbuf_wrapper_get(); + if (!p) + return GLUE_ERR_MEM; + + uassert(p->pbuf.type == PBUF_CUSTOM_TYPE_POOLED); + uassert(p->pbuf.flags == 0); + uassert(p->pbuf.next == NULL); + uassert(p->pbuf.eb == NULL); + + p->pbuf.payload = data; + p->pbuf.len = p->pbuf.tot_len = size; + p->pbuf.ref = 0; + p->ref2save = ref2save; + + uprint(DBG "LINKOUTPUT: real pbuf sent to wilderness (len=%dB esp-pbuf=%p glue-pbuf=%p netifidx=%d)\n", + p->pbuf.len, + &p->pbuf, + ref2save, + netif_idx); + + // call blobs + // blobs will call pbuf_free() back later + // we will retrieve our ref2save and give it back to glue + + struct netif* netif = netif_esp[netif_idx]; + err_t err = netif->linkoutput(netif, &p->pbuf); + if (err != ERR_OK) + // blob/phy is exhausted, release memory + pbuf_wrapper_release(p); + return esp2glue_err(err); +} + +#if 1 +#define esp_guess_netif_idx(netif) ((netif)->num) +#else +int esp_guess_netif_idx (struct netif* netif) +{ + struct netif* test_netif_sta = eagle_lwip_getif(STATION_IF); + struct netif* test_netif_ap = eagle_lwip_getif(SOFTAP_IF); + int ret = netif->num; + + if (test_netif_sta) + { + uassert(!netif_sta || test_netif_sta == netif_sta); + uassert(test_netif_sta->input == ethernet_input); + uassert(test_netif_sta->output == etharp_output); + if (netif == test_netif_sta) + ret = STATION_IF; + } + + if (test_netif_ap) + { + uassert(!netif_ap || test_netif_ap == netif_ap); + uassert(test_netif_ap->input == ethernet_input); + uassert(test_netif_ap->output == etharp_output); + if (netif == test_netif_ap) + ret = SOFTAP_IF; + } + + if (ret < 0 || ret > 1) + { + uerror(DBG "guess netif: ERROR default STA"); + ret = STATION_IF; + } + return ret; +} +#endif + +/////////////////////////////////////// +// STUBS / wrappers + +void lwip_init (void) +{ + uprint(DBG "lwip_init\n"); + esp2glue_lwip_init(); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t etharp_output (struct netif* netif, struct pbuf* q, ip_addr_t* ipaddr) +{ + (void)netif; (void)q; (void)ipaddr; + uerror("ERROR: STUB etharp_output should not be called\n"); + return ERR_ABRT; +} + + /** + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access. + * + * @param p the recevied packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + */ +// this is called maybe through netif->input() +// maybe we could try to short-circuit netif->input +// but so far ethernet_input() is fine with AP and STA +err_t ethernet_input (struct pbuf* p, struct netif* netif) +{ + uprint(DBG "received pbuf@%p (pbuf: %dB ref=%d eb=%p) on netif ", p, p->tot_len, p->ref, p->eb); + stub_display_netif(netif); + + uassert(p->tot_len == p->len && p->ref == 1); + +#if UDUMP + // dump packets for me (direct or broadcast) + if ( memcmp((const char*)p->payload, netif->hwaddr, 6) == 0 + || memcmp((const char*)p->payload, ethbroadcast.addr, 6) == 0) + { + dump("ethinput", p->payload, p->len); + } +#endif + + // copy esp pbuf to glue pbuf + + void* glue_pbuf; + void* glue_data; + + // ask glue for space to store payload into + esp2glue_alloc_for_recv(p->len, &glue_pbuf, &glue_data); + + if (glue_pbuf) + // copy data + os_memcpy(glue_data, p->payload, p->len); + + // release blob's buffer asap + pbuf_free(p); + + if (!glue_pbuf) + // packet lost + return ERR_MEM; + + // pass to new ip stack + uassert(netif->num == 0 || netif->num == 1); + return glue2esp_err(esp2glue_ethernet_input(netif->num, glue_pbuf)); +} + +void dhcps_start (struct ip_info* info) +{ + uprint(DBG "dhcps_start "); + display_ip_info(info); + uprint("\n"); + + if (netif_ap) + ///XXX this is mandatory for blobs to be happy + // but we should get this info back through glue + netif_ap->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; + + esp2glue_dhcps_start(info); +} + +void dhcps_stop (void) +{ + // not implemented yet + STUB(dhcps_stop); +} + +void espconn_init (void) +{ + // not implemented yet + // called at boot/reset + // annoying message to hide: + //STUB(espconn_init); +} + +void dhcp_cleanup (struct netif* netif) +{ + // not implemented yet + (void)netif; + STUB(dhcp_cleanup); +} + +err_t dhcp_release (struct netif* netif) +{ + // not implemented yet + (void)netif; + STUB(dhcp_release); + return ERR_ABRT; +} + +/** + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + */ +err_t dhcp_start (struct netif* netif) +{ + uprint(DBG "dhcp_start "); + stub_display_netif(netif); + + return glue2esp_err(esp2glue_dhcp_start(esp_guess_netif_idx(netif))); +} + +void dhcp_stop (struct netif* netif) +{ + (void)netif; + // not implemented yet + STUB(dhcp_stop); +} + +/** + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack. + * + * @return netif, or NULL if failed. + */ + +static int esp_netif_num = 0; +static struct netif* esp_netif_list = NULL; + +struct netif* netif_add ( + struct netif* netif, + ip_addr_t* ipaddr, + ip_addr_t* netmask, + ip_addr_t* gw, + void* state, + netif_init_fn init, + netif_input_fn packet_incoming) +{ + uprint(DBG "netif_add "); + stub_display_netif(netif); + + ////////////////////////////// + // this is revisited ESP lwip implementation + netif->ip_addr.addr = 0; + netif->netmask.addr = 0; + netif->gw.addr = 0; + netif->flags = 0; + #if LWIP_DHCP + // ok + netif->dhcp = NULL; + netif->dhcps_pcb = NULL; + #endif /* LWIP_DHCP */ + #if LWIP_AUTOIP + #error + netif->autoip = NULL; + #endif /* LWIP_AUTOIP */ + #if LWIP_NETIF_STATUS_CALLBACK + #error + netif->status_callback = NULL; + #endif /* LWIP_NETIF_STATUS_CALLBACK */ + #if LWIP_NETIF_LINK_CALLBACK + #error + netif->link_callback = NULL; + #endif /* LWIP_NETIF_LINK_CALLBACK */ + #if LWIP_IGMP + // ok + netif->igmp_mac_filter = NULL; + #endif /* LWIP_IGMP */ + #if ENABLE_LOOPBACK + #error + netif->loop_first = NULL; + netif->loop_last = NULL; + #endif /* ENABLE_LOOPBACK */ + netif->state = state; + + uassert(packet_incoming = ethernet_input); + netif->input = ethernet_input; + + #if LWIP_NETIF_HWADDRHINT + #error + netif->addr_hint = NULL; + #endif /* LWIP_NETIF_HWADDRHINT*/ + #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS + #error + netif->loop_cnt_current = 0; + #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ + + //XXX init() is from blobs to call blobs, unknown effect yet + if (init(netif) != ERR_OK) + { + uprint("ERROR netif_add: caller's init() failed\n"); + return NULL; + } + + if (esp_netif_num == 2) + { + if (netif == netif_sta) + { + uprint(DBG "esp trying to re-add STA\n"); + uassert(netif->num == STATION_IF); + } + else if (netif == netif_ap) + { + uprint(DBG "esp trying to re-add AP\n"); + uassert(netif->num == SOFTAP_IF); + } + else + uerror(DBG "esp is messing with me\n"); + + // assume hwaddr has not changed + esp2glue_netif_set_addr(netif->num, ipaddr->addr, netmask->addr, gw->addr); + } + else + { + netif->num = esp_netif_num++; + netif->next = esp_netif_list; + esp_netif_list = netif; + + uassert(!netif_esp[netif->num]); + netif_esp[netif->num] = netif; + + esp2glue_netif_add(netif->num, ipaddr->addr, netmask->addr, gw->addr, netif->hwaddr_len, netif->hwaddr, netif->mtu); + } + + ////////////////////////////// + + netif->flags |= NETIF_FLAG_LINK_UP; + netif_set_addr(netif, ipaddr, netmask, gw); + + return netif; +} + + +/** + * Remove a network interface from the list of lwIP netifs. + * + * @param netif the network interface to remove + */ +void netif_remove (struct netif* netif) +{ + (void)netif; + uprint(DBG "trying to remove netif "); + stub_display_netif(netif); + + // don't, see netif_set_down() + //esp2glue_netif_set_updown(netif->num, 0); + //netif->flags &= ~NETIF_FLAG_LINK_UP; + (void)netif; +} + +/** + * Change IP address configuration for a network interface (including netmask + * and default gateway). + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * @param netmask the new netmask + * @param gw the new default gateway + */ +void netif_set_addr (struct netif* netif, ip_addr_t* ipaddr, ip_addr_t* netmask, ip_addr_t* gw) +{ + netif->ip_addr.addr = ipaddr->addr; + netif->netmask.addr = netmask->addr; + netif->gw.addr = gw->addr; + int netif_idx = esp_guess_netif_idx(netif); + + // tell blobs + struct ip_info set; + set.ip.addr = ipaddr->addr; + set.netmask.addr = netmask->addr; + set.gw.addr = gw->addr; + wifi_set_ip_info(netif_idx, &set); + + uprint(DBG "netif_set_addr "); + stub_display_netif(netif); + + esp2glue_netif_set_addr(netif_idx, ipaddr->addr, netmask->addr, gw->addr); +} + +/** + * Set a network interface as the default network interface + * (used to output all packets for which no specific route is found) + * + * @param netif the default network interface + */ +void netif_set_default (struct netif* netif) +{ + uprint(DBG "netif_set_default %d\n", esp_guess_netif_idx(netif)); + netif_default = netif; + esp2glue_netif_set_default(esp_guess_netif_idx(netif)); +} + +/** + * Bring an interface down, disabling any traffic processing. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_down (struct netif* netif) +{ + uprint(DBG "netif_set_down "); + stub_display_netif(netif); + + // dont set down. some esp8266 (wemos D1 not mini) will: + // * esp2glue_netif_set_updown + // * restart dhcp-client _without_ netif_set_up. + // another one (D1 mini) does not call set_down() + + // netif->flags &= ~(NETIF_FLAG_UP | NETIF_FLAG_LINK_UP); + // esp2glue_netif_set_updown(netif->num, 0); + (void)netif; +} + +/** + * Bring an interface up, available for processing + * traffic. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + * + * @see dhcp_start() + */ +void netif_set_up (struct netif* netif) +{ + uerror(DBG "netif_set_up is called??"); + stub_display_netif(netif); + + netif->flags |= (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP); + esp2glue_netif_set_updown(netif->num, 1); +} + +/** + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + * chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + * protocol headers. Additional headers must be prepended + * by allocating another pbuf and chain in to the front of + * the ROM pbuf. It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + * protocol headers. It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ + +struct pbuf* pbuf_alloc (pbuf_layer layer, u16_t length, pbuf_type type) +{ + // pbuf creation from blobs + // copy parts of original code matching specific requests + + //STUB(pbuf_alloc); + //pbuf_info("pbuf_alloc", layer, length, type); + + u16_t offset = 0; + if (layer == PBUF_RAW && type == PBUF_RAM) + { + offset += EP_OFFSET; + + /* If pbuf is to be allocated in RAM, allocate memory for it. */ + size_t alloclen = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length); + struct pbuf* p = (struct pbuf*)mem_malloc(alloclen); + if (p == NULL) + return NULL; + /* Set up internal structure of the pbuf. */ + p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + p->eb = NULL; + p->ref = 1; + p->flags = 0; + uprint(DBG "pbuf_alloc(RAW/RAM)-> %p %dB type=%d\n", p, alloclen, type); + return p; + } + + if (layer == PBUF_RAW && type == PBUF_REF) + { + //unused: offset += EP_OFFSET; + size_t alloclen = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF); + struct pbuf* p = (struct pbuf*)mem_malloc(alloclen); + if (p == NULL) + return NULL; + p->payload = NULL; + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + p->eb = NULL; + p->ref = 1; + p->flags = 0; + uprint(DBG "pbuf_alloc(RAW/REF)-> %p %dB type=%d\n", p, alloclen, type); + return p; + } + + uerror(DBG "pbuf_alloc BAD CASE\n"); + + return NULL; +} + +/** + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param p The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + * + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ + +u8_t pbuf_free (struct pbuf *p) +{ + //STUB(pbuf_free); + uprint(DBG "pbuf_free(%p) ref=%d type=%d\n", p, p->ref, p->type); + //pbuf_info("pbuf_free", -1, p->len, p->type); + //uprint("pbuf@%p ref=%d tot_len=%d eb=%p\n", p, p->ref, p->tot_len, p->eb); + + #if LWIP_SUPPORT_CUSTOM_PBUF + #error LWIP_SUPPORT_CUSTOM_PBUF is defined + #endif + + uassert(p->ref == 1); + + if (p->type == PBUF_CUSTOM_TYPE_POOLED) + { + // allocated by glue for sending packets + uassert(!p->eb); + // retrieve glue structure to be freed + struct pbuf_wrapper* pw = (struct pbuf_wrapper*)p; + // pw->ref2save is the glue structure to release + uprint(DBG "pbuf_free chain release glue-pbuf %p lwip1-pbuf %p\n", pw->ref2save, (char*)p); + uassert(pw->ref2save); + esp2glue_pbuf_freed(pw->ref2save); + pbuf_wrapper_release(pw); + + return 1; + } + + if ( !p->next + && p->ref == 1 + && ( + p->type == PBUF_RAM + || p->type == PBUF_REF + //|| p->type == PBUF_ESF_RX + )) + { + if (p->eb) + system_pp_recycle_rx_pkt(p->eb); + // allocated by blobs for received packets + mem_free(p); + return 1; + } + + uerror("BAD CASE %p ref=%d tot_len=%d eb=%p\n", p, p->ref, p->tot_len, p->eb); + return 0; +} + +/** + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void pbuf_ref (struct pbuf *p) +{ + uprint(DBG "pbuf_ref(%p) ref=%d->%d\n", p, p->ref, p->ref + 1); + ++(p->ref); +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_timeouts_mbox_fetch() + * - by calling sys_check_timeouts() (NO_SYS==1 only) + * + * @param msecs time in milliseconds after that the timer should expire + * @param handler callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +{ + (void)msecs; (void)handler; (void)arg; + STUB(sys_timeout); +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry, even though the timeout has not triggered yet. + * + * @note This function only works as expected if there is only one timeout + * calling 'handler' in the list of timeouts. + * + * @param handler callback function that would be called by the timeout + * @param arg callback argument that would be passed to handler +*/ +void sys_untimeout(sys_timeout_handler handler, void *arg) +{ + (void)handler; (void)arg; + STUB(sys_untimeout); +} + +void glue2esp_ifup (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw) +{ + struct netif* netif = netif_esp[netif_idx]; + + // backup old esp ips + ip_addr_t oldip, oldmask, oldgw; + oldip = netif->ip_addr; + oldmask = netif->netmask; + oldgw = netif->gw; + + // change ips + netif->ip_addr.addr = ip; + netif->netmask.addr = mask; + netif->gw.addr = gw; + // set up + netif->flags |= NETIF_FLAG_UP; + + // tell esp to check it has changed (by giving old ones) + system_station_got_ip_set(&oldip, &oldmask, &oldgw); +} diff --git a/Sming/third-party/lwip2/glue-lwip/arch/cc.h b/Sming/third-party/lwip2/glue-lwip/arch/cc.h new file mode 100644 index 0000000000..5f100ebce0 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/arch/cc.h @@ -0,0 +1,141 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + +// version for esp8266 sdk-2.0.0(656edbf) + +#ifndef LWIP2_ARCH_CC_H +#define LWIP2_ARCH_CC_H + +#include "stdint.h" + +typedef signed short sint16_t; + +#ifdef LWIP_BUILD + +// define LWIP_BUILD only when building LWIP +// otherwise include files below would conflict +// with standard headers like atoi() +#include "ets_sys.h" +#include "osapi.h" +#include "esp-missing.h" + +void sntp_set_system_time (uint32_t t); + +#endif // defined(LWIP_BUILD) + +#include "mem.h" // useful for os_malloc used in esp-arduino's mDNS + +typedef int sys_prot_t; // not really used +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) os_intr_lock() +#define SYS_ARCH_UNPROTECT(lev) os_intr_unlock() + +/////////////////////////////// +//// DEBUG +#if 0 // debug 1:on or 0 + +//#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH) +//#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON) + +#define LWIP_DEBUG 1 + +//int doprint (const char* format, ...) __attribute__ ((format (printf, 1, 2))); +extern int os_printf_plus(const char * format, ...) __attribute__ ((format (printf, 1, 2))); +#define LWIP_PLATFORM_DIAG(x) do { os_printf x;} while(0) + +#else +#define LWIP_NOASSERT 1 +#endif // debug + +/////////////////////////////// +//// MISSING + +#define sys_now millis // arduino wire millis() definition returns 32 bits like sys_now() does +#define LWIP_RAND r_rand // old lwip uses this useful undocumented function +#define IPSTR "%d.%d.%d.%d" +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +// ip_addr / ip_info: do not exist in lwip2 (only in lwip1.4) +struct ip_addr { + uint32_t addr; +}; +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; + +/////////////////////////////// +//// PROVIDED TO USER + +typedef struct ip4_addr ip4_addr_t; +extern int ntp_servers_number; +extern ip4_addr_t* ntp_servers; + +/////////////////////////////// +//// STUBS + +// these symbols must be renamed in the new implementation +// because they are known/used in blobs + +#define dhcp_cleanup dhcp_cleanup_LWIP2 +#define dhcp_release dhcp_release_LWIP2 +#define dhcp_start dhcp_start_LWIP2 +#define dhcp_stop dhcp_stop_LWIP2 +#define dhcps_start dhcps_start_LWIP2 +#define dhcps_stop dhcps_stop_LWIP2 +#define espconn_init espconn_init_LWIP2 +#define etharp_output etharp_output_LWIP2 +#define ethbroadcast ethbroadcast_LWIP2 +#define ethernet_input ethernet_input_LWIP2 +#define lwip_init lwip_init_LWIP2 +#define netif_add netif_add_LWIP2 +#define netif_default netif_default_LWIP2 +#define netif_remove netif_remove_LWIP2 +#define netif_set_addr netif_set_addr_LWIP2 +#define netif_set_default netif_set_default_LWIP2 +#define netif_set_down netif_set_down_LWIP2 +#define netif_set_up netif_set_up_LWIP2 +#define pbuf_alloc pbuf_alloc_LWIP2 +#define pbuf_free pbuf_free_LWIP2 +#define pbuf_ref pbuf_ref_LWIP2 +//#define sys_check_timeouts sys_check_timeouts_LWIP2 // void(void) + +#if !defined(LWIP_DEBUG) || !SYS_DEBUG +#define sys_timeout sys_timeout_LWIP2 +#endif + +#define sys_untimeout sys_untimeout_LWIP2 + +/////////////////////////////// +#endif // LWIP2_ARCH_CC_H diff --git a/Sming/third-party/lwip2/glue-lwip/arch/sys_arch.h b/Sming/third-party/lwip2/glue-lwip/arch/sys_arch.h new file mode 100644 index 0000000000..abcf8afd02 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/arch/sys_arch.h @@ -0,0 +1,5 @@ + +#ifndef MYSYSARCH_H +#define MYSYSARCH_H + +#endif // MYSYSARCH_H \ No newline at end of file diff --git a/Sming/third-party/lwip2/glue-lwip/esp-dhcpserver.c b/Sming/third-party/lwip2/glue-lwip/esp-dhcpserver.c new file mode 100644 index 0000000000..244df1d0f2 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/esp-dhcpserver.c @@ -0,0 +1,1204 @@ + +// adapted from dhcpserver.c distributed in esp8266 sdk 2.0.0 +// same license may apply + +#include "lwip/inet.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "osapi.h" + +#include "lwip/apps-esp/dhcpserver.h" + +#ifndef LWIP_OPEN_SRC +#include "net80211/ieee80211_var.h" +#endif + +#include "user_interface.h" +#include "mem.h" + +#include "glue.h" +#include "lwip-helper.h" + +#ifdef MEMLEAK_DEBUG +static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#endif + +//////////////////////////////////////////////////////////////////////////////////// +//static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +//static u8_t old_xid[4] = {0}; +static const uint32 magic_cookie ICACHE_RODATA_ATTR = 0x63538263; +static struct udp_pcb *pcb_dhcps = NULL; +static ip_addr_t broadcast_dhcps; +static struct ip_addr server_address; +static struct ip_addr client_address;//added + +static struct dhcps_lease dhcps_lease; +//static bool dhcps_lease_flag = true; +static list_node *plist = NULL; +static uint8 offer = 0xFF; +static bool renew = false; +#define DHCPS_LEASE_TIME_DEF (120) +uint32 dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute + +void wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force); +uint32 wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip); + +/****************************************************************************** + * FunctionName : node_insert_to_list + * Description : insert the node to the list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR node_insert_to_list(list_node **phead, list_node* pinsert) +{ + list_node *plist = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + struct dhcps_pool *pdhcps_node = NULL; + if (*phead == NULL) + *phead = pinsert; + else { + plist = *phead; + pdhcps_node = pinsert->pnode; + pdhcps_pool = plist->pnode; + + if(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist; + *phead = pinsert; + } else { + while (plist->pnext != NULL) { + pdhcps_pool = plist->pnext->pnode; + if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist->pnext; + plist->pnext = pinsert; + break; + } + plist = plist->pnext; + } + + if(plist->pnext == NULL) { + plist->pnext = pinsert; + } + } + } +// pinsert->pnext = NULL; +} + +/****************************************************************************** + * FunctionName : node_delete_from_list + * Description : remove the node from list + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR node_remove_from_list(list_node **phead, list_node* pdelete) +{ + list_node *plist = NULL; + + plist = *phead; + if (plist == NULL){ + *phead = NULL; + } else { + if (plist == pdelete){ + *phead = plist->pnext; + pdelete->pnext = NULL; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete){ + plist->pnext = pdelete->pnext; + pdelete->pnext = NULL; + } + plist = plist->pnext; + } + } + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg��Ϣ�ṹ���������� + * + * @param optptr -- DHCP msg��Ϣλ�� + * @param type -- Ҫ��ӵ�����option + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_msg_type(uint8_t *optptr, uint8_t type) +{ + + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg�ṹ������offerӦ������ + * + * @param optptr -- DHCP msg��Ϣλ�� + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_offer_options(uint8_t *optptr) +{ + struct ip_addr ipadd; + + ipadd.addr = *( (uint32_t *) &server_address); + + struct ip_info if_ip; + os_bzero(&if_ip, sizeof(struct ip_info)); + wifi_get_ip_info(SOFTAP_IF, &if_ip); + + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = 4; + *optptr++ = ip4_addr1( &if_ip.netmask); + *optptr++ = ip4_addr2( &if_ip.netmask); + *optptr++ = ip4_addr3( &if_ip.netmask); + *optptr++ = ip4_addr4( &if_ip.netmask); + + *optptr++ = DHCP_OPTION_LEASE_TIME; + *optptr++ = 4; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF; + *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF; + + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = ip4_addr4( &ipadd); + + if (dhcps_router_enabled(offer)){ + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = 4; + *optptr++ = ip4_addr1( &if_ip.gw); + *optptr++ = ip4_addr2( &if_ip.gw); + *optptr++ = ip4_addr3( &if_ip.gw); + *optptr++ = ip4_addr4( &if_ip.gw); + } + +#ifdef USE_DNS + *optptr++ = DHCP_OPTION_DNS_SERVER; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = ip4_addr4( &ipadd); +#endif + +#ifdef CLASS_B_NET + *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = 255; + *optptr++ = 255; + *optptr++ = 255; +#else + *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; + *optptr++ = 4; + *optptr++ = ip4_addr1( &ipadd); + *optptr++ = ip4_addr2( &ipadd); + *optptr++ = ip4_addr3( &ipadd); + *optptr++ = 255; +#endif + + *optptr++ = DHCP_OPTION_INTERFACE_MTU; + *optptr++ = 2; +#ifdef CLASS_B_NET + *optptr++ = 0x05; + *optptr++ = 0xdc; +#else + *optptr++ = 0x02; + *optptr++ = 0x40; +#endif + + *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY; + *optptr++ = 1; + *optptr++ = 0x00; + + *optptr++ = 43; + *optptr++ = 6; + + *optptr++ = 0x01; + *optptr++ = 4; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x02; + + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ��DHCP msg�ṹ����ӽ����־���� + * + * @param optptr -- DHCP msg��Ϣλ�� + * + * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t* ICACHE_FLASH_ATTR add_end(uint8_t *optptr) +{ + + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR create_msg(struct dhcps_msg *m) +{ + struct ip_addr client; + + client.addr = client_address.addr; + + m->op = DHCP_REPLY; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = 6; + m->hops = 0; +// os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid)); + m->secs = 0; + m->flags = htons(BOOTP_BROADCAST); + + os_memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); + + os_memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); + os_memset((char *) m->siaddr, 0, sizeof(m->siaddr)); + os_memset((char *) m->giaddr, 0, sizeof(m->giaddr)); + os_memset((char *) m->sname, 0, sizeof(m->sname)); + os_memset((char *) m->file, 0, sizeof(m->file)); + + os_memset((char *) m->options, 0, sizeof(m->options)); + +//For xiaomi crash bug + uint32 magic_cookie1 = magic_cookie; + os_memcpy((char *) m->options, &magic_cookie1, sizeof(magic_cookie1)); +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��OFFER + * + * @param -- m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m) +{ + uint8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPOFFER); + end = add_offer_options(end); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_offer>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_offer>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>pbuf_alloc failed\n"); +#endif + return; + } + if (!lwiperr_check("send_offer", udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ))){ +#if DHCPS_DEBUG + os_printf("dhcps: send_offer>>udp_sendto\n"); +#endif + } + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_offer>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��NAK��Ϣ + * + * @param m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_nak(struct dhcps_msg *m) +{ + + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPNAK); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_nak>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_nak>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_nak>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_nak>>pbuf_alloc failed\n"); +#endif + return; + } + lwiperr_check("dhcps send nak", udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT )); + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_nak>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����һ��ACK��DHCP�ͻ��� + * + * @param m ָ����Ҫ���͵�DHCP msg���� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m) +{ + + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt=0; + u16_t i; + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPACK); + end = add_offer_options(end); + end = add_end(end); + + p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM); +#if DHCPS_DEBUG + os_printf("udhcp: send_ack>>p->ref = %d\n", p->ref); +#endif + if(p != NULL){ + +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>pbuf_alloc succeed\n"); + os_printf("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len); + os_printf("dhcps: send_ack>>p->len = %d\n", p->len); +#endif + q = p; + while(q != NULL){ + data = (u8_t *)q->payload; + for(i=0; ilen; i++) + { + data[i] = ((u8_t *) m)[cnt++]; + } + + q = q->next; + } + }else{ + +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>pbuf_alloc failed\n"); +#endif + return; + } + if (!lwiperr_check("dhcps send ack", udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT ))){ +#if DHCPS_DEBUG + os_printf("dhcps: send_ack>>udp_sendto\n"); +#endif + } + + if(p->ref != 0){ +#if DHCPS_DEBUG + os_printf("udhcp: send_ack>>free pbuf\n"); +#endif + pbuf_free(p); + } +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ�� + * + * @param optptr DHCP msg��������� + * @param len ��������Ĵ��?(byte) + * + * @return uint8_t ���ش�����DHCP Server״ֵ̬ + */ +/////////////////////////////////////////////////////////////////////////////////// +static uint8_t ICACHE_FLASH_ATTR parse_options(uint8_t *optptr, sint16_t len) +{ + struct ip_addr client; + bool is_dhcp_parse_end = false; + struct dhcps_state s; + + client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP + + u8_t *end = optptr + len; + u16_t type = 0; + + s.state = DHCPS_STATE_IDLE; + + while (optptr < end) { +#if DHCPS_DEBUG + os_printf("dhcps: (sint16_t)*optptr = %d\n", (sint16_t)*optptr); +#endif + switch ((sint16_t) *optptr) { + + case DHCP_OPTION_MSG_TYPE: //53 + type = *(optptr + 2); + break; + + case DHCP_OPTION_REQ_IPADDR://50 + //os_printf("dhcps:0x%08x,0x%08x\n",client.addr,*(uint32*)(optptr+2)); + if( os_memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) { +#if DHCPS_DEBUG + os_printf("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); +#endif + s.state = DHCPS_STATE_ACK; + }else { +#if DHCPS_DEBUG + os_printf("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); +#endif + s.state = DHCPS_STATE_NAK; + } + break; + case DHCP_OPTION_END: + { + is_dhcp_parse_end = true; + } + break; + } + + if(is_dhcp_parse_end){ + break; + } + + optptr += optptr[1] + 2; + } + + switch (type){ + case DHCPDISCOVER://1 + s.state = DHCPS_STATE_OFFER; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_OFFER\n"); +#endif + break; + + case DHCPREQUEST://3 + if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) { + if(renew == true) { + s.state = DHCPS_STATE_ACK; + } else { + s.state = DHCPS_STATE_NAK; + } +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_NAK\n"); +#endif + } + break; + + case DHCPDECLINE://4 + s.state = DHCPS_STATE_IDLE; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + + case DHCPRELEASE://7 + s.state = DHCPS_STATE_RELEASE; +#if DHCPS_DEBUG + os_printf("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + } +#if DHCPS_DEBUG + os_printf("dhcps: return s.state = %d\n", s.state); +#endif + return s.state; +} +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +static sint16_t ICACHE_FLASH_ATTR parse_msg(struct dhcps_msg *m, u16_t len) +{ + if(os_memcmp((char *)m->options, + &magic_cookie, + sizeof(magic_cookie)) == 0){ + struct ip_addr ip; + os_memcpy(&ip.addr,m->ciaddr,sizeof(ip.addr)); + client_address.addr = wifi_softap_dhcps_client_update(m->chaddr,&ip); + + sint16_t ret = parse_options(&m->options[4], len); + + if(ret == DHCPS_STATE_RELEASE) { + wifi_softap_dhcps_client_leave(m->chaddr,&ip,TRUE); // force to delete + client_address.addr = ip.addr; + } + + return ret; + } + return 0; +} +/////////////////////////////////////////////////////////////////////////////////// +/* + * DHCP ��������ݰ���մ���ص�����˺�����LWIP UDPģ������ʱ������ + * ��Ҫ����udp_recv()������LWIP����ע��. + * + * @param arg + * @param pcb ���յ�UDP��Ŀ��ƿ�? + * @param p ���յ���UDP��������? + * @param addr ���ʹ�UDP���Դ�����IP��ַ + * @param port ���ʹ�UDP���Դ�����UDPͨ���˿ں� + */ +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR handle_dhcp(void *arg, + struct udp_pcb *pcb, + struct pbuf *p, + const ip_addr_t *addr, + uint16_t port) +{ + (void)arg; + (void)pcb; + (void)addr; + (void)port; + + struct dhcps_msg *pmsg_dhcps = NULL; + sint16_t tlen = 0; + u16_t i = 0; + u16_t dhcps_msg_cnt = 0; + u8_t *p_dhcps_msg = NULL; + u8_t *data = NULL; + +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> receive a packet\n"); +#endif + if (p==NULL) return; + + pmsg_dhcps = (struct dhcps_msg *)os_zalloc(sizeof(struct dhcps_msg)); + if (NULL == pmsg_dhcps){ + pbuf_free(p); + return; + } + p_dhcps_msg = (u8_t *)pmsg_dhcps; + tlen = p->tot_len; + data = p->payload; + +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen); + os_printf("dhcps: handle_dhcp-> p->len = %d\n", p->len); +#endif + + for(i=0; ilen; i++){ + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; + } + + if(p->next != NULL) { +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> p->next != NULL\n"); + os_printf("dhcps: handle_dhcp-> p->next->tot_len = %d\n",p->next->tot_len); + os_printf("dhcps: handle_dhcp-> p->next->len = %d\n",p->next->len); +#endif + + data = p->next->payload; + for(i=0; inext->len; i++){ + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; + } + } + + /* + * DHCP �ͻ���������Ϣ���� + */ +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> parse_msg(p)\n"); +#endif + + switch(parse_msg(pmsg_dhcps, tlen - 240)) { + + case DHCPS_STATE_OFFER://1 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n"); +#endif + send_offer(pmsg_dhcps); + break; + case DHCPS_STATE_ACK://3 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n"); +#endif + send_ack(pmsg_dhcps); + break; + case DHCPS_STATE_NAK://4 +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n"); +#endif + send_nak(pmsg_dhcps); + break; + default : + break; + } +#if DHCPS_DEBUG + os_printf("dhcps: handle_dhcp-> pbuf_free(p)\n"); +#endif + pbuf_free(p); + os_free(pmsg_dhcps); + pmsg_dhcps = NULL; +} +/////////////////////////////////////////////////////////////////////////////////// +static void ICACHE_FLASH_ATTR wifi_softap_init_dhcps_lease(uint32 ip) +{ + uint32 softap_ip = 0,local_ip = 0; + uint32 start_ip = 0; + uint32 end_ip = 0; +// if (dhcps_lease_flag) { + if (dhcps_lease.enable == TRUE) { + softap_ip = htonl(ip); + start_ip = htonl(dhcps_lease.start_ip.addr); + end_ip = htonl(dhcps_lease.end_ip.addr); + /*config ip information can't contain local ip*/ + if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) { + dhcps_lease.enable = FALSE; + } else { + /*config ip information must be in the same segment as the local ip*/ + softap_ip >>= 8; + if (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip)) + || (end_ip - start_ip > DHCPS_MAX_LEASE)) { + dhcps_lease.enable = FALSE; + } + } + } + + if (dhcps_lease.enable == FALSE) { + local_ip = softap_ip = htonl(ip); + softap_ip &= 0xFFFFFF00; + local_ip &= 0xFF; + if (local_ip >= 0x80) + local_ip -= DHCPS_MAX_LEASE; + else + local_ip ++; + + os_bzero(&dhcps_lease, sizeof(dhcps_lease)); + dhcps_lease.start_ip.addr = softap_ip | local_ip; + dhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1); + dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); + dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); + } +// dhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr); +// dhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr); +// os_printf("start_ip = 0x%x, end_ip = 0x%x\n",dhcps_lease.start_ip, dhcps_lease.end_ip); +} +/////////////////////////////////////////////////////////////////////////////////// +void ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info) +{ + // was: struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); + // but we are now in the lwip2 side so we deal with lwip2 structs + // where netif->dhcps_pcb does not exist + // we can use netif->state which is unused + + struct netif * apnetif = netif_ap; + + //uprint("dhcps_start: apnetif=%p state/dhcps_pcb=%p\n", apnetif, apnetif->state); + + //if(apnetif->dhcps_pcb != NULL) { + // udp_remove(apnetif->dhcps_pcb); + //} + if(apnetif->state != NULL) { + udp_remove((struct udp_pcb*)apnetif->state); + } + + pcb_dhcps = udp_new(); + if (pcb_dhcps == NULL || info ==NULL) { + os_printf("dhcps_start(): could not obtain pcb\n"); + } + + //apnetif->dhcps_pcb = pcb_dhcps; + apnetif->state = pcb_dhcps; + + +// wrong: answer will go to sta IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255); +// good: going to ap IP4_ADDR(&broadcast_dhcps, 192, 168, 4, 255); +// semi proper way: + broadcast_dhcps = apnetif->ip_addr; + broadcast_dhcps.addr &= apnetif->netmask.addr; + broadcast_dhcps.addr |= ~apnetif->netmask.addr; + + server_address = info->ip; + wifi_softap_init_dhcps_lease(server_address.addr); + + udp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT); + udp_recv(pcb_dhcps, handle_dhcp, NULL); +#if DHCPS_DEBUG + os_printf("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n"); +#endif + + wifi_set_ip_info(SOFTAP_IF, info); // added for lwip-git, not sure whether useful + netif_ap->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; // added for lwip-git + // useless and wrong. default should be sta. netif_set_default(netif_ap); +} + +void ICACHE_FLASH_ATTR dhcps_stop(void) +{ + //struct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01); + struct netif * apnetif = netif_ap; + + udp_disconnect(pcb_dhcps); +// dhcps_lease_flag = true; + //if(apnetif->dhcps_pcb != NULL) { + // udp_remove(apnetif->dhcps_pcb); + // apnetif->dhcps_pcb = NULL; + //} + if(apnetif->state != NULL) { + udp_remove((struct udp_pcb*)apnetif->state); + apnetif->state = NULL; + } + + //udp_remove(pcb_dhcps); + list_node *pnode = NULL; + list_node *pback_node = NULL; + struct dhcps_pool* dhcp_node = NULL; + struct ip_addr ip_zero; + + os_memset(&ip_zero,0x0,sizeof(ip_zero)); + pnode = plist; + while (pnode != NULL) { + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&plist, pback_node); + dhcp_node = (struct dhcps_pool*)pback_node->pnode; + //wifi_softap_dhcps_client_leave(dhcp_node->mac,&dhcp_node->ip,TRUE); // force to delete + wifi_softap_set_station_info(dhcp_node->mac, &ip_zero); + os_free(pback_node->pnode); + pback_node->pnode = NULL; + os_free(pback_node); + pback_node = NULL; + } +} + +/****************************************************************************** + * FunctionName : wifi_softap_set_dhcps_lease + * Description : set the lease information of DHCP server + * Parameters : please -- Additional argument to set the lease information, + * Little-Endian. + * Returns : true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease(struct dhcps_lease *please) +{ + struct ip_info info; + uint32 softap_ip = 0; + uint32 start_ip = 0; + uint32 end_ip = 0; + + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (please == NULL || wifi_softap_dhcps_status() == DHCP_STARTED) + return false; + + if(please->enable) { + os_bzero(&info, sizeof(struct ip_info)); + wifi_get_ip_info(SOFTAP_IF, &info); + softap_ip = htonl(info.ip.addr); + start_ip = htonl(please->start_ip.addr); + end_ip = htonl(please->end_ip.addr); + + /*config ip information can't contain local ip*/ + if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) + return false; + + /*config ip information must be in the same segment as the local ip*/ + softap_ip >>= 8; + if ((start_ip >> 8 != softap_ip) + || (end_ip >> 8 != softap_ip)) { + return false; + } + + if (end_ip - start_ip > DHCPS_MAX_LEASE) + return false; + + os_bzero(&dhcps_lease, sizeof(dhcps_lease)); +// dhcps_lease.start_ip.addr = start_ip; +// dhcps_lease.end_ip.addr = end_ip; + dhcps_lease.start_ip.addr = please->start_ip.addr; + dhcps_lease.end_ip.addr = please->end_ip.addr; + } + dhcps_lease.enable = please->enable; +// dhcps_lease_flag = false; + return true; +} + +/****************************************************************************** + * FunctionName : wifi_softap_get_dhcps_lease + * Description : get the lease information of DHCP server + * Parameters : please -- Additional argument to get the lease information, + * Little-Endian. + * Returns : true or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease(struct dhcps_lease *please) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (NULL == please) + return false; + +// if (dhcps_lease_flag){ + if (dhcps_lease.enable == FALSE){ + if (wifi_softap_dhcps_status() == DHCP_STOPPED) + return false; + } else { +// os_bzero(please, sizeof(dhcps_lease)); +// if (wifi_softap_dhcps_status() == DHCP_STOPPED){ +// please->start_ip.addr = htonl(dhcps_lease.start_ip.addr); +// please->end_ip.addr = htonl(dhcps_lease.end_ip.addr); +// } + } + +// if (wifi_softap_dhcps_status() == DHCP_STARTED){ +// os_bzero(please, sizeof(dhcps_lease)); +// please->start_ip.addr = dhcps_lease.start_ip.addr; +// please->end_ip.addr = dhcps_lease.end_ip.addr; +// } + please->start_ip.addr = dhcps_lease.start_ip.addr; + please->end_ip.addr = dhcps_lease.end_ip.addr; + return true; +} + +static void ICACHE_FLASH_ATTR kill_oldest_dhcps_pool(void) +{ + list_node *pre = NULL, *p = NULL; + list_node *minpre = NULL, *minp = NULL; + struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; + pre = plist; + p = pre->pnext; + minpre = pre; + minp = p; + while (p != NULL){ + pdhcps_pool = p->pnode; + pmin_pool = minp->pnode; + if (pdhcps_pool->lease_timer < pmin_pool->lease_timer){ + minp = p; + minpre = pre; + } + pre = p; + p = p->pnext; + } + minpre->pnext = minp->pnext;pdhcps_pool->state = DHCPS_STATE_OFFLINE; + os_free(minp->pnode); + minp->pnode = NULL; + os_free(minp); + minp = NULL; +} + +void ICACHE_FLASH_ATTR dhcps_coarse_tmr(void) +{ + uint8 num_dhcps_pool = 0; + list_node *pback_node = NULL; + list_node *pnode = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + pnode = plist; + while (pnode != NULL) { + pdhcps_pool = pnode->pnode; + if ( pdhcps_pool->type == DHCPS_TYPE_DYNAMIC) { + pdhcps_pool->lease_timer --; + } + if (pdhcps_pool->lease_timer == 0){ + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&plist,pback_node); + os_free(pback_node->pnode); + pback_node->pnode = NULL; + os_free(pback_node); + pback_node = NULL; + } else { + pnode = pnode ->pnext; + num_dhcps_pool ++; + } + } + + if (num_dhcps_pool >= MAX_STATION_NUM) + kill_oldest_dhcps_pool(); +} + +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg) +{ + bool offer_flag = true; + //uint8 option = 0; + if (optarg == NULL && wifi_softap_dhcps_status() == false) + return false; + + if (level <= OFFER_START || level >= OFFER_END) + return false; + + switch (level){ + case OFFER_ROUTER: + offer = (*(uint8 *)optarg) & 0x01; + offer_flag = true; + break; + default : + offer_flag = false; + break; + } + return offer_flag; +} + +bool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease_time(uint32 minute) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (wifi_softap_dhcps_status() == DHCP_STARTED) { + return false; + } + + if(minute == 0) { + return false; + } + dhcps_lease_time = minute; + return true; +} + +bool ICACHE_FLASH_ATTR wifi_softap_reset_dhcps_lease_time(void) +{ + uint8 opmode = wifi_get_opmode(); + + if (opmode == STATION_MODE || opmode == NULL_MODE) { + return false; + } + + if (wifi_softap_dhcps_status() == DHCP_STARTED) { + return false; + } + dhcps_lease_time = DHCPS_LEASE_TIME_DEF; + return true; +} + +uint32 ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease_time(void) // minute +{ + return dhcps_lease_time; +} + +void ICACHE_FLASH_ATTR wifi_softap_dhcps_client_leave(u8 *bssid, struct ip_addr *ip,bool force) +{ + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pback_node = NULL; + + if ((bssid == NULL) || (ip == NULL)) { + return; + } + + for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ + if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { + if ((pdhcps_pool->type == DHCPS_TYPE_STATIC) || (force)) { + if(pback_node != NULL) { + node_remove_from_list(&plist,pback_node); + os_free(pback_node); + pback_node = NULL; + } + + if (pdhcps_pool != NULL) { + os_free(pdhcps_pool); + pdhcps_pool = NULL; + } + } else { + pdhcps_pool->state = DHCPS_STATE_OFFLINE; + } + + struct ip_addr ip_zero; + os_memset(&ip_zero,0x0,sizeof(ip_zero)); + wifi_softap_set_station_info(bssid, &ip_zero); + break; + } + } + } +} + +uint32 ICACHE_FLASH_ATTR wifi_softap_dhcps_client_update(u8 *bssid, struct ip_addr *ip) +{ + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pback_node = NULL; + list_node *pmac_node = NULL; + list_node *pip_node = NULL; + bool flag = FALSE; + uint32 start_ip = dhcps_lease.start_ip.addr; + uint32 end_ip = dhcps_lease.end_ip.addr; + dhcps_type_t type = DHCPS_TYPE_DYNAMIC; + if (bssid == NULL) { + return IPADDR_ANY; + } + + if (ip) { + if (IPADDR_BROADCAST == ip->addr) { + return IPADDR_ANY; + } else if (IPADDR_ANY == ip->addr) { + ip = NULL; + } else { + type = DHCPS_TYPE_STATIC; + } + } + + renew = FALSE; + for (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + //os_printf("mac:"MACSTR"bssid:"MACSTR"\r\n",MAC2STR(pdhcps_pool->mac),MAC2STR(bssid)); + if (os_memcmp(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)) == 0){ + pmac_node = pback_node; + if (ip == NULL) { + flag = TRUE; + break; + } + } + if (ip != NULL) { + if (os_memcmp(&pdhcps_pool->ip.addr, &ip->addr, sizeof(pdhcps_pool->ip.addr)) == 0) { + pip_node = pback_node; + } + } else if (flag == FALSE){ + if (os_memcmp(&pdhcps_pool->ip.addr, &start_ip, sizeof(pdhcps_pool->ip.addr)) != 0) { + flag = TRUE; + } else { + start_ip = htonl((ntohl(start_ip) + 1)); + } + } + } + + if ((ip == NULL) && (flag == FALSE)) { + if (plist == NULL) { + if (start_ip <= end_ip) { + flag = TRUE; + } else { + return IPADDR_ANY; + } + } else { + if (start_ip > end_ip) { + return IPADDR_ANY; + } + //start_ip = htonl((ntohl(start_ip) + 1)); + flag = TRUE; + } + } + + if (pmac_node != NULL) { // update new ip + if (pip_node != NULL){ + pdhcps_pool = pip_node->pnode; + + if (pip_node != pmac_node) { + if(pdhcps_pool->state != DHCPS_STATE_OFFLINE) { // ip is used + return IPADDR_ANY; + } + + // mac exists and ip exists in other node,delete mac + node_remove_from_list(&plist,pmac_node); + os_free(pmac_node->pnode); + pmac_node->pnode = NULL; + os_free(pmac_node); + pmac_node = pip_node; + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + } else { + renew = true; + type = DHCPS_TYPE_DYNAMIC; + } + + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + + } else { + pdhcps_pool = pmac_node->pnode; + if (ip != NULL) { + pdhcps_pool->ip.addr = ip->addr; + } else if (flag == TRUE) { + pdhcps_pool->ip.addr = start_ip; + } else { // no ip to distribute + return IPADDR_ANY; + } + + node_remove_from_list(&plist,pmac_node); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + node_insert_to_list(&plist,pmac_node); + } + } else { // new station + if (pip_node != NULL) { // maybe ip has used + pdhcps_pool = pip_node->pnode; + if (pdhcps_pool->state != DHCPS_STATE_OFFLINE) { + return IPADDR_ANY; + } + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + } else { + pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool)); + if (ip != NULL) { + pdhcps_pool->ip.addr = ip->addr; + } else if (flag == TRUE) { + pdhcps_pool->ip.addr = start_ip; + } else { // no ip to distribute + os_free(pdhcps_pool); + return IPADDR_ANY; + } + if (pdhcps_pool->ip.addr > end_ip) { + os_free(pdhcps_pool); + return IPADDR_ANY; + } + os_memcpy(pdhcps_pool->mac, bssid, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER; + pdhcps_pool->type = type; + pdhcps_pool->state = DHCPS_STATE_ONLINE; + pback_node = (list_node *)os_zalloc(sizeof(list_node )); + pback_node->pnode = pdhcps_pool; + pback_node->pnext = NULL; + node_insert_to_list(&plist,pback_node); + } + } + wifi_softap_set_station_info(bssid, &pdhcps_pool->ip); + + return pdhcps_pool->ip.addr; +} diff --git a/Sming/third-party/lwip2/glue-lwip/esp-sntp.c b/Sming/third-party/lwip2/glue-lwip/esp-sntp.c new file mode 100644 index 0000000000..3a7a6fb041 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/esp-sntp.c @@ -0,0 +1,411 @@ + +// this is from lwip1.4-espressif's sntp.c which was a patched version of a former lwip's sntp +// patch is extracted for the new lwip2's sntp + +#include "lwip/apps/sntp.h" +#include "osapi.h" +#include "os_type.h" + +static uint32 realtime_stamp = 0; +static sint8 time_zone = 8; +static bool sntp_time_flag = false; +static uint32 sntp_update_delay = SNTP_UPDATE_DELAY; +static uint8 sntp_receive_time_size = 1; +LOCAL os_timer_t sntp_timer; + +/*****************************************/ +#define SECSPERMIN 60L +#define MINSPERHOUR 60L +#define HOURSPERDAY 24L +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERWEEK 7 +#define MONSPERYEAR 12 + +#define YEAR_BASE 1900 +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY 4 +#define EPOCH_YEARS_SINCE_LEAP 2 +#define EPOCH_YEARS_SINCE_CENTURY 70 +#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +int __tznorth; +int __tzyear; +char reult[100]; +static const int mon_lengths[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +} ; + +static const int year_lengths[2] = { + 365, + 366 +} ; +struct tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct tm res_buf; +typedef struct __tzrule_struct +{ + char ch; + int m; + int n; + int d; + int s; + time_t change; + int offset; +} __tzrule_type; + +__tzrule_type sntp__tzrule[2]; +struct tm * +sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime) +{ + long days, rem; + time_t lcltime; + int y; + int yleap; + const int *ip; + + /* base decision about std/dst time on current time */ + lcltime = *tim_p; + + days = ((long)lcltime) / SECSPERDAY; + rem = ((long)lcltime) % SECSPERDAY; + while (rem < 0) + { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) + { + rem -= SECSPERDAY; + ++days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int) (rem / SECSPERMIN); + res->tm_sec = (int) (rem % SECSPERMIN); + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + res->tm_wday += DAYSPERWEEK; + + /* compute year & day of year */ + y = EPOCH_YEAR; + if (days >= 0) + { + for (;;) + { + yleap = isleap(y); + if (days < year_lengths[yleap]) + break; + y++; + days -= year_lengths[yleap]; + } + } + else + { + do + { + --y; + yleap = isleap(y); + days += year_lengths[yleap]; + } while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = mon_lengths[yleap]; + for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) + days -= ip[res->tm_mon]; + res->tm_mday = days + 1; + + if (!is_gmtime) + { + int offset; + int hours, mins, secs; + +// TZ_LOCK; +// if (_daylight) +// { +// if (y == __tzyear || __tzcalc_limits (y)) +// res->tm_isdst = (__tznorth +// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) +// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); +// else +// res->tm_isdst = -1; +// } +// else + res->tm_isdst = -1; + + offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); + + hours = offset / SECSPERHOUR; + offset = offset % SECSPERHOUR; + + mins = offset / SECSPERMIN; + secs = offset % SECSPERMIN; + + res->tm_sec -= secs; + res->tm_min -= mins; + res->tm_hour -= hours; + + if (res->tm_sec >= SECSPERMIN) + { + res->tm_min += 1; + res->tm_sec -= SECSPERMIN; + } + else if (res->tm_sec < 0) + { + res->tm_min -= 1; + res->tm_sec += SECSPERMIN; + } + if (res->tm_min >= MINSPERHOUR) + { + res->tm_hour += 1; + res->tm_min -= MINSPERHOUR; + } + else if (res->tm_min < 0) + { + res->tm_hour -= 1; + res->tm_min += MINSPERHOUR; + } + if (res->tm_hour >= HOURSPERDAY) + { + ++res->tm_yday; + ++res->tm_wday; + if (res->tm_wday > 6) + res->tm_wday = 0; + ++res->tm_mday; + res->tm_hour -= HOURSPERDAY; + if (res->tm_mday > ip[res->tm_mon]) + { + res->tm_mday -= ip[res->tm_mon]; + res->tm_mon += 1; + if (res->tm_mon == 12) + { + res->tm_mon = 0; + res->tm_year += 1; + res->tm_yday = 0; + } + } + } + else if (res->tm_hour < 0) + { + res->tm_yday -= 1; + res->tm_wday -= 1; + if (res->tm_wday < 0) + res->tm_wday = 6; + res->tm_mday -= 1; + res->tm_hour += 24; + if (res->tm_mday == 0) + { + res->tm_mon -= 1; + if (res->tm_mon < 0) + { + res->tm_mon = 11; + res->tm_year -= 1; + res->tm_yday = 365 + isleap(res->tm_year); + } + res->tm_mday = ip[res->tm_mon]; + } + } +// TZ_UNLOCK; + } + else + res->tm_isdst = 0; +// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour); + return (res); +} +struct tm * +sntp_localtime_r(const time_t * tim_p , + struct tm *res) +{ + return sntp_mktm_r (tim_p, res, 0); +} + +struct tm * +sntp_localtime(const time_t * tim_p) +{ + return sntp_localtime_r (tim_p, &res_buf); +} + + +int +sntp__tzcalc_limits(int year) +{ + int days, year_days, years; + int i, j; + + if (year < EPOCH_YEAR) + return 0; + + __tzyear = year; + + years = (year - EPOCH_YEAR); + + year_days = years * 365 + + (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + + (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; + + for (i = 0; i < 2; ++i) + { + if (sntp__tzrule[i].ch == 'J') + days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); + else if (sntp__tzrule[i].ch == 'D') + days = year_days + sntp__tzrule[i].d; + else + { + int yleap = isleap(year); + int m_day, m_wday, wday_diff; + const int *ip = mon_lengths[yleap]; + + days = year_days; + + for (j = 1; j < sntp__tzrule[i].m; ++j) + days += ip[j-1]; + + m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; + + wday_diff = sntp__tzrule[i].d - m_wday; + if (wday_diff < 0) + wday_diff += DAYSPERWEEK; + m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; + + while (m_day >= ip[j-1]) + m_day -= DAYSPERWEEK; + + days += m_day; + } + + /* store the change-over time in GMT form by adding offset */ + sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset; + } + + __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); + + return 1; +} + +char * +sntp_asctime_r(struct tm *tim_p ,char *result) +{ + static const char day_name[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n", + day_name[tim_p->tm_wday], + mon_name[tim_p->tm_mon], + tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, + tim_p->tm_sec, 1900 + tim_p->tm_year); + return result; +} +char * +sntp_asctime(struct tm *tim_p) +{ + + return sntp_asctime_r (tim_p, reult); +} + +uint32 sntp_get_current_timestamp() +{ +#if 0 + if(realtime_stamp == 0){ + os_printf("please start sntp first !\n"); + return 0; + } else +#endif + return realtime_stamp; +} + +char* sntp_get_real_time(time_t t) +{ + return sntp_asctime(sntp_localtime (&t)); +} +/** + * SNTP get time_zone default GMT + 8 + */ +sint8 +sntp_get_timezone(void) +{ + return time_zone; +} +/** + * SNTP set time_zone default GMT + 8 + */ + +bool +sntp_set_timezone(sint8 timezone) +{ + if(timezone >= -11 || timezone <= 13) { + time_zone = timezone; + return true; + } else { + return false; + } + +} + +void sntp_set_daylight(int daylight) +{ +#if 0 + if (sntp_get_timetype()) // always false in espressif's lwip1.4 + RTC_DST_SET(daylight); +#else + (void)daylight; +#endif +} + +void sntp_time_inc (void) +{ + realtime_stamp++; +} + +void sntp_set_system_time (uint32_t t) +{ + realtime_stamp = t; + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); + os_timer_arm(&sntp_timer, 1000, 1); +} + +void sntp_set_update_delay (uint32 ms) +{ + sntp_update_delay = ms > 15000? ms: 15000; +} + +void sntp_set_timetype (bool type) +{ + sntp_time_flag = type; +} + +bool sntp_get_timetype(void) +{ + return sntp_time_flag; +} + +void sntp_set_receive_time_size(void) +{ + if (sntp_get_timetype()) + sntp_receive_time_size = 2; + else + sntp_receive_time_size = 1; +} diff --git a/Sming/third-party/lwip2/glue-lwip/esp-time.c b/Sming/third-party/lwip2/glue-lwip/esp-time.c new file mode 100644 index 0000000000..25e05952c7 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/esp-time.c @@ -0,0 +1,109 @@ +/* + * time.c - ESP8266-specific functions for SNTP + * Copyright (c) 2015 Peter Dobler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * This library 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 Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include "sntp.h" + + +#ifndef _TIMEVAL_DEFINED +#define _TIMEVAL_DEFINED +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; +#endif + +extern char* sntp_asctime(const struct tm *t); +extern struct tm* sntp_localtime(const time_t *clock); + +// time gap in seconds from 01.01.1900 (NTP time) to 01.01.1970 (UNIX time) +#define DIFF1900TO1970 2208988800UL + +static int s_daylightOffset_sec = 0; +static long s_timezone_sec = 0; +static time_t s_bootTime = 0; + +// calculate offset used in gettimeofday +static void ensureBootTimeIsSet() +{ + if (!s_bootTime) + { + time_t now = sntp_get_current_timestamp(); + if (now) + { + s_bootTime = now - millis() / 1000; + } + } +} + +#if 0 +static void setServer(int id, const char* name_or_ip) +{ + if (name_or_ip) + { + //TODO: check whether server is given by name or IP + sntp_setservername(id, (char*) name_or_ip); + } +} + +void configTime(int timezone, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) +{ + sntp_stop(); + + setServer(0, server1); + setServer(1, server2); + setServer(2, server3); + + s_timezone_sec = timezone; + s_daylightOffset_sec = daylightOffset_sec; + sntp_set_timezone(timezone/3600); + sntp_init(); +} + +int clock_gettime(clockid_t unused, struct timespec *tp) +{ + (void) unused; + tp->tv_sec = millis() / 1000; + tp->tv_nsec = micros() * 1000; + return 0; +} + +time_t time(time_t * t) +{ + time_t seconds = sntp_get_current_timestamp(); + if (t) + { + *t = seconds; + } + return seconds; +} +#endif +//int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) +int gettimeofday(struct timeval *tp, void *tzp) +{ + (void) tzp; + if (tp) + { + ensureBootTimeIsSet(); + tp->tv_sec = s_bootTime + millis() / 1000; + tp->tv_usec = micros() * 1000; + } + return 0; +} + diff --git a/Sming/third-party/lwip2/glue-lwip/lwip-git-hash.h b/Sming/third-party/lwip2/glue-lwip/lwip-git-hash.h new file mode 100644 index 0000000000..35807ca22d --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/lwip-git-hash.h @@ -0,0 +1,6 @@ +// generated by makefiles/make-lwip2-hash +#ifndef LWIP_HASH_H +#define LWIP_HASH_H +#define LWIP_HASH 0xc0862d6 +#define LWIP_HASH_STR "c0862d6(tag:STABLE-2_0_2_RELEASE_VER)" +#endif // LWIP_HASH_H diff --git a/Sming/third-party/lwip2/glue-lwip/lwip-git.c b/Sming/third-party/lwip2/glue-lwip/lwip-git.c new file mode 100644 index 0000000000..853ca1fb67 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/lwip-git.c @@ -0,0 +1,398 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + +// lwip2(git) side of glue + +#include "lwipopts.h" +#include "lwip/err.h" +#include "lwip/init.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/etharp.h" +#include "netif/ethernet.h" +#include "lwip/apps/sntp.h" + +// this is dhcpserver taken from lwip-1.4-espressif +#include "lwip/apps-esp/dhcpserver.h" + +#include "glue.h" +#include "lwip-helper.h" + +#define DBG "GLUE: " + +static char hostname[32]; +static char hostname[32]; + +#define netif_sta (&netif_git[STATION_IF]) +#define netif_ap (&netif_git[SOFTAP_IF]) +struct netif netif_git[2]; +const char netif_name[2][8] = { "station", "soft-ap" }; + +int doprint_allow = 0; // for doprint() + +err_t glue2git_err (err_glue_t err) +{ + switch (err) + { + case GLUE_ERR_OK : return ERR_OK; + case GLUE_ERR_MEM : return ERR_MEM; + case GLUE_ERR_BUF : return ERR_BUF; + case GLUE_ERR_TIMEOUT : return ERR_TIMEOUT; + case GLUE_ERR_RTE : return ERR_RTE; + case GLUE_ERR_INPROGRESS : return ERR_INPROGRESS; + case GLUE_ERR_VAL : return ERR_VAL; + case GLUE_ERR_WOULDBLOCK : return ERR_WOULDBLOCK; + case GLUE_ERR_USE : return ERR_USE; + case GLUE_ERR_ALREADY : return ERR_ALREADY; + case GLUE_ERR_ISCONN : return ERR_ISCONN; + case GLUE_ERR_CONN : return ERR_CONN; + case GLUE_ERR_IF : return ERR_IF; + case GLUE_ERR_ABRT : return ERR_ABRT; + case GLUE_ERR_RST : return ERR_RST; + case GLUE_ERR_CLSD : return ERR_CLSD; + case GLUE_ERR_ARG : return ERR_ARG; + + default: return ERR_ABRT; + } +}; + +err_glue_t git2glue_err (err_t err) +{ + switch (err) + { + case ERR_OK : return GLUE_ERR_OK; + case ERR_MEM : return GLUE_ERR_MEM; + case ERR_BUF : return GLUE_ERR_BUF; + case ERR_TIMEOUT : return GLUE_ERR_TIMEOUT; + case ERR_RTE : return GLUE_ERR_RTE; + case ERR_INPROGRESS : return GLUE_ERR_INPROGRESS; + case ERR_VAL : return GLUE_ERR_VAL; + case ERR_WOULDBLOCK : return GLUE_ERR_WOULDBLOCK; + case ERR_USE : return GLUE_ERR_USE; + case ERR_ALREADY : return GLUE_ERR_ALREADY; + case ERR_ISCONN : return GLUE_ERR_ISCONN; + case ERR_CONN : return GLUE_ERR_CONN; + case ERR_IF : return GLUE_ERR_IF; + case ERR_ABRT : return GLUE_ERR_ABRT; + case ERR_RST : return GLUE_ERR_RST; + case ERR_CLSD : return GLUE_ERR_CLSD; + case ERR_ARG : return GLUE_ERR_ARG; + + default: return GLUE_ERR_ABRT; + } +}; + +u8_t glue2git_netif_flags (glue_netif_flags_t flags) +{ + +//XXXFIXME this is the paranoia mode +// make it simpler in non-debug mode + + glue_netif_flags_t copy = flags; + u8_t nf = 0; + #define CF(x) do { if (flags & GLUE_NETIF_FLAG_##x) { nf |= NETIF_FLAG_##x; flags &= ~GLUE_NETIF_FLAG_##x; } } while (0) + CF(UP); + CF(BROADCAST); + //CF(POINTTOPOINT); + //CF(DHCP); + CF(LINK_UP); + CF(ETHARP); + //CF(ETHERNET); + CF(IGMP); + #undef CF + if (flags) + uerror("ERROR: glue2git_netif_flags: remaining flags not converted (0x%x->0x%x)\n", copy, flags); + return nf; +} + +#if UDEBUG + +static void new_display_netif_flags (int flags) +{ + #define IFF(x) do { if (flags & NETIF_FLAG_##x) uprint("|" #x); } while (0) + IFF(UP); + IFF(BROADCAST); + IFF(LINK_UP); + IFF(ETHARP); + IFF(ETHERNET); + IFF(IGMP); + IFF(MLD6); + #undef IFF +} + +static const char* new_netif_name (struct netif* netif) +{ + uassert(netif == netif_sta || netif == netif_ap); + return netif == netif_ap? "AP": "STA"; +} + +static void new_display_netif (struct netif* netif) +{ + + uprint("lwip-@%p idx=%d %s name=%c%c%d mtu=%d state=%p ", + netif, + netif == netif_ap? SOFTAP_IF: STATION_IF, + new_netif_name(netif), + netif->name[0], netif->name[1], netif->num, + netif->mtu, + netif->state); + if (netif->hwaddr_len == 6) + display_mac(netif->hwaddr); + new_display_netif_flags(netif->flags); + display_ip32(" ip=", netif->ip_addr.addr); + display_ip32(" mask=", netif->netmask.addr); + display_ip32(" gw=", netif->gw.addr); + uprint("\n"); +} + +#else // !UDEBUG + +#define new_display_netif_flags(x) do { (void)0; } while (0) +#define new_display_netif(x) do { (void)0; } while (0) + +#endif // !UDEBUG + +int lwiperr_check (const char* what, err_t err) +{ + if (err != ERR_OK) + { + uerror("ERROR: %s (error %d)\n", what, err); + return 0; + } + return 1; +} + +err_glue_t esp2glue_dhcp_start (int netif_idx) +{ + uprint(DBG "dhcp_start netif: "); + new_display_netif(&netif_git[netif_idx]); + err_t err = dhcp_start(&netif_git[netif_idx]); + uprint(DBG "new_dhcp_start returns %d\n", err); + return git2glue_err(err); +} + +err_t new_linkoutput (struct netif* netif, struct pbuf* p) +{ + #if !LWIP_NETIF_TX_SINGLE_PBUF + #warning ESP netif->linkoutput cannot handle pbuf chains. + #error LWIP_NETIF_TX_SINGLE_PBUF must be 1 in lwipopts.h + #endif + uassert(p->next == NULL); + uassert(p->len == p->tot_len); + + // protect pbuf, so lwip2(git) won't free it before phy(esp) finishes sending + pbuf_ref(p); + + uassert(netif->num == STATION_IF || netif->num == SOFTAP_IF); + + uprint(DBG "linkoutput: netif@%p (%s)\n", netif, netif_name[netif->num]); + uprint(DBG "linkoutput default netif was: %d\n", netif_default? netif_default->num: -1); + + err_t err = glue2git_err(glue2esp_linkoutput( + netif->num, + p, p->payload, p->len)); + + if (err != ERR_OK) + { + pbuf_free(p); + uprint(DBG "linkoutput error sending pbuf@%p\n", p); + } + + return err; +} + +void esp2glue_pbuf_freed (void* pbuf) +{ + uprint(DBG "blobs release lwip-pbuf (ref=%d) @%p\n", ((struct pbuf*)pbuf)->ref, pbuf); + pbuf_free((struct pbuf*)pbuf); +} + +static err_t new_input (struct pbuf *p, struct netif *inp) +{ + (void)p; + (void)inp; + uerror("internal error, new-netif->input() cannot be called\n"); + return ERR_ABRT; +} + +void esp2glue_netif_set_default (int netif_idx) +{ + uprint(DBG "netif set default %s\n", netif_name[netif_idx]); + netif_set_default(netif_idx == STATION_IF || netif_idx == SOFTAP_IF? &netif_git[netif_idx]: NULL); +} + +static void netif_sta_status_callback (struct netif* netif) +{ + uprint(DBG "netif status callback "); + new_display_netif(netif); + + if (netif->flags & NETIF_FLAG_LINK_UP) + { + // tell ESP that link is up + glue2esp_ifup(netif == netif_sta? STATION_IF: SOFTAP_IF, netif->ip_addr.addr, netif->netmask.addr, netif->gw.addr); + + if (netif == netif_sta) + { + // this is our default route + netif_set_default(netif); + + // start sntp + sntp_init(); + } + } +} + +static void netif_init_common (struct netif* netif) +{ + netif->flags |= NETIF_FLAG_IGMP; + // irrelevant,not used since esp-lwip receive data and call esp2glue_ethernet_input() + netif->input = new_input; + // meaningfull: + netif->output = etharp_output; + netif->linkoutput = new_linkoutput; + + netif->hostname = hostname; + netif->chksum_flags = NETIF_CHECKSUM_ENABLE_ALL; + // netif->mtu given by glue + //netif->mtu = 1500;//TCP_MSS + 40; +} + +static err_t netif_init_sta (struct netif* netif) +{ + uprint(DBG "netif_sta_init\n"); + + netif->name[0] = 's'; + netif->name[1] = 't'; + netif->status_callback = netif_sta_status_callback; // need to tell esp-netif-sta is up + + netif_init_common(netif); + + return ERR_OK; +} + +static err_t netif_init_ap (struct netif* netif) +{ + uprint(DBG "netif_ap_init\n"); + + netif->name[0] = 'a'; + netif->name[1] = 'p'; + netif->status_callback = NULL; // esp-netif-ap is made up by esp + + netif_init_common(netif); + + return ERR_OK; +} + +void esp2glue_netif_add (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw, size_t hwlen, const uint8_t* hwaddr, uint16_t mtu) +{ + static int check_idx = 0; + uassert(netif_idx == check_idx); + check_idx++; + + struct netif* netif = &netif_git[netif_idx]; + netif->hwaddr_len = hwlen; + if (hwlen && hwlen <= sizeof(netif->hwaddr)) + memcpy(netif->hwaddr, hwaddr, netif->hwaddr_len = hwlen); + netif->mtu = mtu; + + ip4_addr_t aip = { ip }, amask = { mask }, agw = { gw }; + netif_add( + &netif_git[netif_idx], + &aip, &amask, &agw, /*state*/NULL, + netif_idx == STATION_IF? netif_init_sta: netif_init_ap, + /*useless input*/NULL); + + //XXX get these through esp2glue~flags() ? + netif_git[netif_idx].flags |= NETIF_FLAG_ETHARP; + netif_git[netif_idx].flags |= NETIF_FLAG_BROADCAST; + + // this was not done in old lwip and is needed at least for lwip2 dhcp client +#if 0 + uprint(DBG "set up now idx=%d\n", netif_idx); + netif_set_link_up(&netif_git[netif_idx]); + netif_set_up(&netif_git[netif_idx]); +#else + netif_git[netif_idx].flags |= NETIF_FLAG_UP; + netif_git[netif_idx].flags |= NETIF_FLAG_LINK_UP; +#endif +} + +void esp2glue_netif_set_addr (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw) +{ + ip4_addr_t aip = { ip }, amask = { mask }, agw = { gw }; + netif_set_addr(&netif_git[netif_idx], &aip, &amask, &agw); +} + +void esp2glue_lwip_init (void) +{ + lwip_init(); + + sntp_servermode_dhcp(1); /* get SNTP server via DHCP */ + sntp_setoperatingmode(SNTP_OPMODE_POLL); + // do not start sntp here, but when we got our address + //sntp_init(); +} + +void esp2glue_alloc_for_recv (size_t len, void** pbuf, void** data) +{ + *pbuf = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); + if (*pbuf) + *data = ((struct pbuf*)*pbuf)->payload; +} + +err_glue_t esp2glue_ethernet_input (int netif_idx, void* received) +{ + // this input is allocated by esp2glue_alloc_for_recv() + + //uprint(DBG "input idx=%d netif-flags=0x%x ", netif_idx, netif_git[netif_idx].flags); + //display_ip32(" ip=", netif_git[netif_idx].ip_addr.addr); + //nl(); + + return git2glue_err(ethernet_input((struct pbuf*)received, &netif_git[netif_idx])); +} + +void esp2glue_dhcps_start (struct ip_info* info) +{ + dhcps_start(info); +} + +void esp2glue_netif_set_updown (int netif_idx, int up1_or_down0) +{ + struct netif* netif = &netif_git[netif_idx]; + if (up1_or_down0) + { + netif_set_link_up(netif); + netif_set_up(netif); + } + else + { + netif_set_link_down(netif); + netif_set_down(netif); + } +} diff --git a/Sming/third-party/lwip2/glue-lwip/lwip-helper.h b/Sming/third-party/lwip2/glue-lwip/lwip-helper.h new file mode 100644 index 0000000000..cb4a851db5 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/lwip-helper.h @@ -0,0 +1,17 @@ + +#ifndef LWIP_HELPER_H +#define LWIP_HELPER_H + +#include "lwip/err.h" +#include "lwip/netif.h" + +#define netif_sta (&netif_git[STATION_IF]) +#define netif_ap (&netif_git[SOFTAP_IF]) +extern struct netif netif_git[2]; +extern int netif_git_initialized[2]; +extern const char netif_name[2][8]; + +// return 1 if OK, 0 if bad and display message +int lwiperr_check (const char* what, err_t err); + +#endif // LWIP_HELPER_H \ No newline at end of file diff --git a/Sming/third-party/lwip2/glue-lwip/lwip/apps-esp/dhcpserver.h b/Sming/third-party/lwip2/glue-lwip/lwip/apps-esp/dhcpserver.h new file mode 100644 index 0000000000..655f49aba4 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/lwip/apps-esp/dhcpserver.h @@ -0,0 +1,120 @@ + +// adapted from dhcpserver.c distributed in esp8266 sdk 2.0.0 +// same license may apply + +#ifndef __DHCPS_H__ +#define __DHCPS_H__ + +#include "glue.h" // for UDEBUG + +#define USE_DNS + +typedef struct dhcps_state{ + sint16_t state; +} dhcps_state; + +typedef struct dhcps_msg { + uint8_t op, htype, hlen, hops; + uint8_t xid[4]; + uint16_t secs, flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[312]; +}dhcps_msg; + +#ifndef LWIP_OPEN_SRC +struct dhcps_lease { + bool enable; + struct ip_addr start_ip; + struct ip_addr end_ip; +}; + +enum dhcps_offer_option{ + OFFER_START = 0x00, + OFFER_ROUTER = 0x01, + OFFER_END +}; +#endif + +typedef enum { + DHCPS_TYPE_DYNAMIC, + DHCPS_TYPE_STATIC +} dhcps_type_t; + +typedef enum { + DHCPS_STATE_ONLINE, + DHCPS_STATE_OFFLINE +} dhcps_state_t; + +struct dhcps_pool{ + struct ip_addr ip; + uint8 mac[6]; + uint32 lease_timer; + dhcps_type_t type; + dhcps_state_t state; + +}; + +typedef struct _list_node{ + void *pnode; + struct _list_node *pnext; +}list_node; + +extern uint32 dhcps_lease_time; +#define DHCPS_LEASE_TIMER dhcps_lease_time //0x05A0 +#define DHCPS_MAX_LEASE 0x64 +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPS_SERVER_PORT 67 +#define DHCPS_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_INTERFACE_MTU 26 +#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP_OPTION_BROADCAST_ADDRESS 28 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +//#define USE_CLASS_B_NET 1 +#define DHCPS_DEBUG UDEBUG +#define MAX_STATION_NUM 8 + +#define DHCPS_STATE_OFFER 1 +#define DHCPS_STATE_DECLINE 2 +#define DHCPS_STATE_ACK 3 +#define DHCPS_STATE_NAK 4 +#define DHCPS_STATE_IDLE 5 +#define DHCPS_STATE_RELEASE 6 + +#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0) + +void dhcps_start(struct ip_info *info); +void dhcps_stop(void); + +#endif + diff --git a/Sming/third-party/lwip2/glue-lwip/lwipopts.h b/Sming/third-party/lwip2/glue-lwip/lwipopts.h new file mode 100644 index 0000000000..fbb0bde317 --- /dev/null +++ b/Sming/third-party/lwip2/glue-lwip/lwipopts.h @@ -0,0 +1,2991 @@ + +#ifndef MYLWIPOPTS_H +#define MYLWIPOPTS_H + +// opt.h version lwip-2.0.3 for esp8266 + +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - + * without this, doxygen does not see the actual #define + */ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +//#include "lwip/debug.h" // done at end of this file + +/** + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts + */ + + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ +#define NO_SYS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif + +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * MEMMOVE: override this if you have a faster implementation at hand than the + * one included in your C library. lwIP currently uses MEMMOVE only when IPv6 + * fragmentation support is enabled. + */ +#if !defined MEMMOVE || defined __DOXYGEN__ +#define MEMMOVE(dst,src,len) os_memmove(dst,src,len) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 1 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 1 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 + */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 16000 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_PBUF 10 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ +//#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) // 5 +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 16 // 5 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 0 // 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 0 // 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 10 // 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ +#define MEMP_NUM_NETBUF 0 // 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 0 // 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 4 // 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 4 // 8 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 0 // 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 10 // 16 +#endif + +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#if !defined LWIP_ARP || defined __DOXYGEN__ +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 10 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 1 // 0 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 3 // 0 // 3 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#if !defined IP_FORWARD || defined __DOXYGEN__ +#define IP_FORWARD 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ +#define IP_REASSEMBLY 0 // 1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#if !defined IP_FRAG || defined __DOXYGEN__ +#define IP_FRAG 0 // 1 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 1 // 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL (IP_DEFAULT_TTL) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ +#define LWIP_DHCP 1 // 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK 0 // ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has + * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and + * netif drivers might not set this flag, the default is off. If enabled, + * netif_set_link_up() must be called to continue dhcp starting. + */ +#if !defined LWIP_DHCP_CHECK_LINK_UP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#endif + +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 1 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DHCP servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ +#define LWIP_AUTOIP 0 +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + -------- Multicast options ------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_multicast Multicast + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP, as well as (currently only) + * core support for the corresponding IPv6 options. + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ +#define LWIP_IGMP 1 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#if !defined LWIP_DNS || defined __DOXYGEN__ +#define LWIP_DNS 1 // 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#if !defined LWIP_UDP || defined __DOXYGEN__ +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 1 // 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +//#define TCP_WND (*(volatile uint32*)0x600011F0) // (4 * TCP_MSS) +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +//#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) // 12 +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +//#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) // 6 +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ 0 // (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF (2 * TCP_MSS) +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 36 // 0u # 36 is EP_OFFSET from original esp implementation +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif + +/** + * LWIP_PBUF_REF_T: Refcount type in pbuf. + * Default width of u8_t can be increased if 255 refs are not enough for you. + */ +#ifndef LWIP_PBUF_REF_T +#define LWIP_PBUF_REF_T u8_t +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for + * small real-life targets. Some code like routing etc. can be left out. + */ +#if !defined LWIP_SINGLE_NETIF || defined __DOXYGEN__ +#define LWIP_SINGLE_NETIF 0 // AP+STA = 2 different netif +#endif + +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 1 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 1 +#endif + +/** + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * for several netif related event that supports multiple subscribers. + * @see netif_ext_status_callback + */ +#if !defined LWIP_NETIF_EXT_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 // MANDATORY FOR ESP8266 BLOBS !! +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif. + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 0 // 1 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 0 // 1 +#endif + +/** LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete + * successfully, as required by POSIX. Default is POSIX-compliant. + */ +#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ +#define LWIP_SOCKET_SET_ERRNO 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 // 1 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 1 // 0 +#endif + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 1 // 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 0 +#endif + +/** + * LWIP_SOCKET_SELECT==1 (default): enable select() for sockets (uses a netconn + * callback to keep track of events). + * This saves RAM (counters per socket) and code (netconn event callback), which + * should improve performance a bit). + */ +#if !defined LWIP_SOCKET_SELECT || defined __DOXYGEN__ +#define LWIP_SOCKET_SELECT 1 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 0 // 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} + */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 // 0 +#endif + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_SCOPES==1: Enable support for IPv6 address scopes, ensuring that + * e.g. link-local addresses are really treated as link-local. Disable this + * setting only for single-interface configurations. + */ +#if !defined LWIP_IPV6_SCOPES || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_IPV6_SCOPES_DEBUG==1: Perform run-time checks to verify that addresses + * are properly zoned (see ip6_zone.h on what that means) where it matters. + * Enabling this setting is highly recommended when upgrading from an existing + * installation that is not yet scope-aware; otherwise it may be too expensive. + */ +#if !defined LWIP_IPV6_SCOPES_DEBUG || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES_DEBUG 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT (LWIP_IPV6) // 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each + * IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled + * otherwise, in which case the application may assign address lifetimes with + * the appropriate macros. Addresses with no lifetime are assumed to be static. + * If this option is disabled, all addresses are assumed to be static. + */ +#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__ +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to \#include in files that provide hooks. + * Declare your hook function prototypes in there, you may also \#include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(dest, src): + * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * - called from etharp_output() (IPv4) + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Returns the IPv4 address of the gateway to handle the specified destination + * IPv4 address. If NULL is returned, the netif's default gateway is used. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * - called from ip6_input() (IPv6) + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * - called from ip6_route() (IPv6) + * - src: sourc IPv6 address + * - dest: destination IPv6 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * - called from nd6_get_next_hop_entry() (IPv6) + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Returns the IPv6 address of the next hop to handle the specified destination + * IPv6 address. If NULL is returned, a NDP-discovered router is used instead. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * - called from ethernet_input() if VLAN support is enabled + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature: s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * - called from memp_free() when a memp pool was empty and an item is now available + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Return ERR_OK if packet is accepted, any error code otherwise. + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH) +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif +/** + * @} + */ + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + + +/* + -------------------------------------------------- + ------------------ SNTP options ------------------ + -------------------------------------------------- +*/ +#define SNTP_SERVER_DNS 1 // SNTP support DNS names through sntp_setservername / sntp_getservername +#define SNTP_SERVER_ADDRESS "pool.ntp.org" // default +#define SNTP_GET_SERVERS_FROM_DHCP 1 +#define SNTP_SET_SYSTEM_TIME(t) (sntp_set_system_time(t)) // implemented in lwip2-sntp.c + +/* + -------------------------------------------------- + -------------------------------------------------- +*/ + +#include "lwip/debug.h" +#include "arch/cc.h" +#include "lwip-git-hash.h" + +#endif // MYLWIPOPTS_H diff --git a/Sming/third-party/lwip2/glue/doprint.c b/Sming/third-party/lwip2/glue/doprint.c new file mode 100644 index 0000000000..68d194bb38 --- /dev/null +++ b/Sming/third-party/lwip2/glue/doprint.c @@ -0,0 +1,179 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + + +#include +#include +#include +#include +#include + +#include "doprint.h" +#include "esp-missing.h" + +extern int doprint_allow; + +#if 0 + +// do not bufferize + +int doprint (const char* format, ...) +{ + va_list ap; + va_start(ap, format); + int ret = ets_vprintf(ets_putc, format, ap); + va_end(ap); + return ret; +} + +#else + +// bufferize + +#define ROTBUFLEN_BIT 10 // 11=2048 +#define ROTBUFLEN (1 << (ROTBUFLEN_BIT)) +#define ROTBUFLEN_MASK ((ROTBUFLEN) - 1) + +static int nl = 0; + +static int rotin = 0; +static int rotout = 0; +static int rotsmall = 0; +static char* rotbuf = NULL; +static int bufputc (int c) +{ + rotbuf[rotout] = c; + rotout = (rotout + 1) & ROTBUFLEN_MASK; + if (rotout == rotin) + { + rotin = (rotin + 1) & ROTBUFLEN_MASK; + rotsmall++; + } + return c; +} + +//#define PUTC ets_putc // no line number +#define PUTC nl_putc // show line number + +static int nl_putc (int c); + +static int doprint_direct (const char* format, ...) +{ + va_list ap; + va_start(ap, format); + int ret = ets_vprintf(PUTC, format, ap); + va_end(ap); + return ret; +} + +static int nl_putc (int c) +{ + ets_putc(c); + if (c == '\n') + doprint_direct("%d:", nl++); + return c; +} + +extern uint32_t millis (void); + +#if STRING_IN_FLASH +// http://marrin.org/2017/01/16/putting-data-in-esp8266-flash-memory/ +// https://github.com/cmarrin/m8rscript/blob/master/esp/core/Esp.{h,cpp} +static inline uint8_t readRomByte(const uint8_t* addr) +{ + uint32_t bytes; + bytes = *(uint32_t*)((uint32_t)addr & ~3); + return ((uint8_t*)&bytes)[(uint32_t)addr & 3]; +} +size_t ROMstrlen(const char* s) +{ + const char* p; + for (p = s; readRomByte((uint8_t*)p) != '\0'; p++) ; + return (size_t) (p - s); +} +char* ROMCopyString(char* dst, const char* src) +{ + uint8_t* s = (uint8_t*) src; + char c; + while ((c = (char) readRomByte(s++))) { + *dst++ = c; + } + *dst = '\0'; + return dst; +} +#endif + +int doprint_minus (const char* minus_format, ...) +{ + int ret; + int (*myputc)(int); + + if (doprint_allow) + { + if (rotbuf) + { + doprint_direct("\n\n"); + os_free(rotbuf); + rotbuf = NULL; + } + + myputc = PUTC; + } + else if (!rotbuf && !(rotbuf = (char*)os_malloc(ROTBUFLEN))) + return 0; + else + myputc = bufputc; + +#if STRING_IN_FLASH + size_t fmtlen = ROMstrlen(minus_format); + char* format = os_malloc(fmtlen + 1); + ROMCopyString(format, minus_format); +#else +#define format minus_format +#endif + + va_list ap; + va_start(ap, minus_format); + ret += ets_vprintf(myputc, format, ap); + va_end(ap); + +#if STRING_IN_FLASH + os_free(format); +#endif + + return ret; +} + +#endif diff --git a/Sming/third-party/lwip2/glue/doprint.h b/Sming/third-party/lwip2/glue/doprint.h new file mode 100644 index 0000000000..461578d8c7 --- /dev/null +++ b/Sming/third-party/lwip2/glue/doprint.h @@ -0,0 +1,27 @@ + +#ifndef DOPRINT_H +#define DOPRINT_H + +// os_printf/ets_printf works only with Serial.setDebugOutput(true) +// ets_putc always work (after Serial.begin()) +// doprint uses ets_putc after doprint_allow gets true and bufferizes before that + +#include // ICACHE_RODATA_ATTR STORE_ATTR + +extern int doprint_allow; + +#define STRING_IN_FLASH 1 + +#if STRING_IN_FLASH +#define doprint(fmt, ...) \ + do { \ + static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ + doprint_minus(flash_str, ##__VA_ARGS__); \ + } while(0) +#else +#define doprint(fmt, ...) doprint_minus(fmt, ##__VA_ARGS__) +#endif + +int doprint_minus (const char* format, ...) __attribute__ ((format (printf, 1, 2))); // format in flash + +#endif // DOPRINT_H diff --git a/Sming/third-party/lwip2/glue/esp-missing.h b/Sming/third-party/lwip2/glue/esp-missing.h new file mode 100644 index 0000000000..4cb5d6c096 --- /dev/null +++ b/Sming/third-party/lwip2/glue/esp-missing.h @@ -0,0 +1,45 @@ + +#ifndef ESP_MISSING_H +#define ESP_MISSING_H + +#include +#include + +// these declarations are missing from sdk and used by lwip1.4 from sdk2.0.0 + +uint32_t r_rand (void); + +void* pvPortZalloc (size_t, const char*, unsigned line); +void* pvPortMalloc (size_t xWantedSize, const char* file, unsigned line) __attribute__((malloc, alloc_size(1))); +void vPortFree (void *ptr, const char* file, unsigned line); + +struct netif* eagle_lwip_getif (int netif_index); + +void ets_intr_lock (void); +void ets_intr_unlock (void); + +int ets_vprintf (int (*print_function)(int), const char * format, va_list arg) __attribute__ ((format (printf, 2, 0))); +int ets_sprintf (char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +int ets_putc(int); + +void ets_bzero (void*, size_t); +int ets_memcmp (const void*, const void*, size_t n); +void *ets_memset (void *s, int c, size_t n); +void *ets_memcpy (void *dest, const void *src, size_t n); + +//typedef void ETSTimerFunc(void *timer_arg); +//void ets_timer_disarm (ETSTimer *a); +//void ets_timer_arm_new (ETSTimer *a, int b, int c, int isMstimer); +//void ets_timer_setfn (ETSTimer *t, ETSTimerFunc *fn, void *parg); + +struct ip_addr; +void wifi_softap_set_station_info (uint8_t* mac, struct ip_addr*); + +#define os_intr_lock ets_intr_lock +#define os_intr_unlock ets_intr_unlock +#define os_bzero ets_bzero +#define os_memcmp ets_memcmp +#define os_memset ets_memset +#define os_memcpy ets_memcpy + +#endif diff --git a/Sming/third-party/lwip2/glue/glue.h b/Sming/third-party/lwip2/glue/glue.h new file mode 100644 index 0000000000..47ae2c9a7b --- /dev/null +++ b/Sming/third-party/lwip2/glue/glue.h @@ -0,0 +1,115 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + + +#ifndef GLUE_STUB_H +#define GLUE_STUB_H + +#include "ets_sys.h" +#include "osapi.h" +#include "user_interface.h" +#include "esp-missing.h" + +#define UDEBUG 0 // 0 or 1 +#define UDUMP 0 // 0 or 1 (show packets content) + +#include "uprint.h" +#include "doprint.h" + +// 0: use os_printf +// 1: buffered and line number, needs doprint_allow=1 after Serial.begin +#if UDEBUG +#undef os_printf +#define os_printf uprint +#define UPRINTF doprint +#else +#define UPRINTF os_printf +#ifdef USE_OPTIMIZE_PRINTF // bug in osapi.h +extern int os_printf_plus(const char * format, ...) __attribute__ ((format (printf, 1, 2))); +#endif +#endif + +#if UDEBUG +#define uprint(x...) do { UPRINTF(x); } while (0) +#else +#define uprint(x...) do { (void)0; } while (0) +#endif + +#define uerror(x...) do { UPRINTF(x); } while (0) +#define uassert(ass...) do { if ((ass) == 0) { UPRINTF("assert fail: " #ass " @%s:%d\n", __FILE__, __LINE__); uhalt(); } } while (0) +#define uhalt() do { (void)0; } while (0) +#define nl() do { uprint("\n"); } while (0) + + +typedef enum +{ + GLUE_ERR_OK = 0, + GLUE_ERR_MEM = -1, + GLUE_ERR_BUF = -2, + GLUE_ERR_TIMEOUT = -3, + GLUE_ERR_RTE = -4, + GLUE_ERR_INPROGRESS = -5, + GLUE_ERR_VAL = -6, + GLUE_ERR_WOULDBLOCK = -7, + GLUE_ERR_USE = -8, + GLUE_ERR_ALREADY = -9, + GLUE_ERR_ISCONN = -10, + GLUE_ERR_CONN = -11, + GLUE_ERR_IF = -12, + GLUE_ERR_ABRT = -13, + GLUE_ERR_RST = -14, + GLUE_ERR_CLSD = -15, + GLUE_ERR_ARG = -16 +} err_glue_t; + +typedef enum +{ + GLUE_NETIF_FLAG_BROADCAST = 1, + GLUE_NETIF_FLAG_UP = 2, + GLUE_NETIF_FLAG_ETHARP = 4, + GLUE_NETIF_FLAG_IGMP = 8, + GLUE_NETIF_FLAG_LINK_UP = 16, +} glue_netif_flags_t; + +void esp2glue_lwip_init (void); +void esp2glue_dhcps_start (struct ip_info* info); +err_glue_t esp2glue_dhcp_start (int netif_idx); +void esp2glue_netif_updated (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw, glue_netif_flags_t flags, size_t hwlen, const uint8_t* hw /*, void* state*/); +err_glue_t esp2glue_ethernet_input (int netif_idx, void* glue_pbuf); +void esp2glue_alloc_for_recv (size_t len, void** glue_pbuf, void** glue_data); +void esp2glue_pbuf_freed (void* ref_saved); +void esp2glue_netif_set_default (int netif_idx); +void esp2glue_netif_add (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw, size_t hwlen, const uint8_t* hwaddr, uint16_t mtu); +void esp2glue_netif_set_addr (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw); +void esp2glue_netif_set_updown (int netif_idx, int up1_or_down0); + +void glue2esp_ifup (int netif_idx, uint32_t ip, uint32_t mask, uint32_t gw); +err_glue_t glue2esp_linkoutput (int netif_idx, void* ref2save, void* data, size_t size); + +#endif // GLUE_STUB_H diff --git a/Sming/third-party/lwip2/glue/uprint.c b/Sming/third-party/lwip2/glue/uprint.c new file mode 100644 index 0000000000..61f4a564bc --- /dev/null +++ b/Sming/third-party/lwip2/glue/uprint.c @@ -0,0 +1,76 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + + +#include "uprint.h" +#include "glue.h" + +#if UDEBUG + +void dump (const char* what, const char* data, uint16_t len) +{ + #define N 16 + size_t i, j; + uprint("DUMP %s: len=%d\n", what, len); + for (i = 0; i < len; i += N) + { + for (j = i; j < i + N && j < len; j++) + uprint("%02x ", data[j]); + for (; j < i + N; j++) + uprint(" "); + for (j = i; j < i + N && j < len; j++) + uprint("%c", (data[j] >= 32 && data[j] < 127)? data[j]: '.'); + uprint("\n"); + } +} + +void display_ip32 (const char* pre, uint32_t ip) +{ + uprint("%s%d.%d.%d.%d", + pre, + (int)(ip & 0xff), + (int)((ip >> 8) & 0xff), + (int)((ip >> 16) & 0xff), + (int)(ip >> 24)); +} + +void display_mac (const uint8_t* mac) +{ + uprint("%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +void display_ip_info (const struct ip_info* i) +{ + display_ip32("ip=", i->ip.addr); + display_ip32(" mask=", i->netmask.addr); + display_ip32(" gw=", i->gw.addr); +} + +#endif diff --git a/Sming/third-party/lwip2/glue/uprint.h b/Sming/third-party/lwip2/glue/uprint.h new file mode 100644 index 0000000000..62859790ae --- /dev/null +++ b/Sming/third-party/lwip2/glue/uprint.h @@ -0,0 +1,26 @@ + +#ifndef UPRINT_H +#define UPRINT_H + +#include + +#include "glue.h" +#include "lwipopts.h" // struct ip_info + +#if UDEBUG + +void dump (const char* what, const char* data, uint16_t len); +void display_ip32 (const char* pre, uint32_t ip); +void display_mac (const uint8_t* mac); +void display_ip_info (const struct ip_info* i); + +#else + +#define dump(x,y,z) do { (void)0; } while (0) +#define display_ip32(x,y) do { (void)0; } while (0) +#define display_mac(x) do { (void)0; } while (0) +#define display_ip_info(x) do { (void)0; } while (0) + +#endif + +#endif // BUFPRINT_H diff --git a/Sming/third-party/lwip2/include/README.md b/Sming/third-party/lwip2/include/README.md new file mode 100644 index 0000000000..8cc8ecd2db --- /dev/null +++ b/Sming/third-party/lwip2/include/README.md @@ -0,0 +1 @@ +warning: this directory is re/over/written from lwip2 builder upon lwip2 rebuild diff --git a/Sming/third-party/lwip2/include/arch/cc.h b/Sming/third-party/lwip2/include/arch/cc.h new file mode 100644 index 0000000000..5f100ebce0 --- /dev/null +++ b/Sming/third-party/lwip2/include/arch/cc.h @@ -0,0 +1,141 @@ + +/* + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +author: d. gauchard + +*/ + +// version for esp8266 sdk-2.0.0(656edbf) + +#ifndef LWIP2_ARCH_CC_H +#define LWIP2_ARCH_CC_H + +#include "stdint.h" + +typedef signed short sint16_t; + +#ifdef LWIP_BUILD + +// define LWIP_BUILD only when building LWIP +// otherwise include files below would conflict +// with standard headers like atoi() +#include "ets_sys.h" +#include "osapi.h" +#include "esp-missing.h" + +void sntp_set_system_time (uint32_t t); + +#endif // defined(LWIP_BUILD) + +#include "mem.h" // useful for os_malloc used in esp-arduino's mDNS + +typedef int sys_prot_t; // not really used +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) os_intr_lock() +#define SYS_ARCH_UNPROTECT(lev) os_intr_unlock() + +/////////////////////////////// +//// DEBUG +#if 0 // debug 1:on or 0 + +//#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH) +//#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON) + +#define LWIP_DEBUG 1 + +//int doprint (const char* format, ...) __attribute__ ((format (printf, 1, 2))); +extern int os_printf_plus(const char * format, ...) __attribute__ ((format (printf, 1, 2))); +#define LWIP_PLATFORM_DIAG(x) do { os_printf x;} while(0) + +#else +#define LWIP_NOASSERT 1 +#endif // debug + +/////////////////////////////// +//// MISSING + +#define sys_now millis // arduino wire millis() definition returns 32 bits like sys_now() does +#define LWIP_RAND r_rand // old lwip uses this useful undocumented function +#define IPSTR "%d.%d.%d.%d" +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +// ip_addr / ip_info: do not exist in lwip2 (only in lwip1.4) +struct ip_addr { + uint32_t addr; +}; +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; + +/////////////////////////////// +//// PROVIDED TO USER + +typedef struct ip4_addr ip4_addr_t; +extern int ntp_servers_number; +extern ip4_addr_t* ntp_servers; + +/////////////////////////////// +//// STUBS + +// these symbols must be renamed in the new implementation +// because they are known/used in blobs + +#define dhcp_cleanup dhcp_cleanup_LWIP2 +#define dhcp_release dhcp_release_LWIP2 +#define dhcp_start dhcp_start_LWIP2 +#define dhcp_stop dhcp_stop_LWIP2 +#define dhcps_start dhcps_start_LWIP2 +#define dhcps_stop dhcps_stop_LWIP2 +#define espconn_init espconn_init_LWIP2 +#define etharp_output etharp_output_LWIP2 +#define ethbroadcast ethbroadcast_LWIP2 +#define ethernet_input ethernet_input_LWIP2 +#define lwip_init lwip_init_LWIP2 +#define netif_add netif_add_LWIP2 +#define netif_default netif_default_LWIP2 +#define netif_remove netif_remove_LWIP2 +#define netif_set_addr netif_set_addr_LWIP2 +#define netif_set_default netif_set_default_LWIP2 +#define netif_set_down netif_set_down_LWIP2 +#define netif_set_up netif_set_up_LWIP2 +#define pbuf_alloc pbuf_alloc_LWIP2 +#define pbuf_free pbuf_free_LWIP2 +#define pbuf_ref pbuf_ref_LWIP2 +//#define sys_check_timeouts sys_check_timeouts_LWIP2 // void(void) + +#if !defined(LWIP_DEBUG) || !SYS_DEBUG +#define sys_timeout sys_timeout_LWIP2 +#endif + +#define sys_untimeout sys_untimeout_LWIP2 + +/////////////////////////////// +#endif // LWIP2_ARCH_CC_H diff --git a/Sming/third-party/lwip2/include/arch/sys_arch.h b/Sming/third-party/lwip2/include/arch/sys_arch.h new file mode 100644 index 0000000000..abcf8afd02 --- /dev/null +++ b/Sming/third-party/lwip2/include/arch/sys_arch.h @@ -0,0 +1,5 @@ + +#ifndef MYSYSARCH_H +#define MYSYSARCH_H + +#endif // MYSYSARCH_H \ No newline at end of file diff --git a/Sming/third-party/lwip2/include/espconn.h b/Sming/third-party/lwip2/include/espconn.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/lwip2/include/lwip-git-hash.h b/Sming/third-party/lwip2/include/lwip-git-hash.h new file mode 100644 index 0000000000..35807ca22d --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip-git-hash.h @@ -0,0 +1,6 @@ +// generated by makefiles/make-lwip2-hash +#ifndef LWIP_HASH_H +#define LWIP_HASH_H +#define LWIP_HASH 0xc0862d6 +#define LWIP_HASH_STR "c0862d6(tag:STABLE-2_0_2_RELEASE_VER)" +#endif // LWIP_HASH_H diff --git a/Sming/third-party/lwip2/include/lwip/api.h b/Sming/third-party/lwip2/include/lwip/api.h new file mode 100644 index 0000000000..516bd163dd --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/api.h @@ -0,0 +1,400 @@ +/** + * @file + * netconn API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_H +#define LWIP_HDR_API_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/arch.h" +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 +#if LWIP_IPV6 +/** If this flag is set then only IPv6 communication is allowed on the + netconn. As per RFC#3493 this features defaults to OFF allowing + dual-stack usage by default. */ +#define NETCONN_FLAG_IPV6_V6ONLY 0x20 +#endif /* LWIP_IPV6 */ + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#if LWIP_IPV6 +#define NETCONN_TYPE_IPV6 0x08 +#define NETCONNTYPE_ISIPV6(t) (((t)&NETCONN_TYPE_IPV6) != 0) +#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM) +#else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISIPV6(t) (0) +#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) +#endif /* LWIP_IPV6 */ + +/** @ingroup netconn_common + * Protocol family and type of the netconn + */ +enum netconn_type { + NETCONN_INVALID = 0, + /** TCP IPv4 */ + NETCONN_TCP = 0x10, +#if LWIP_IPV6 + /** TCP IPv6 */ + NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, +#endif /* LWIP_IPV6 */ + /** UDP IPv4 */ + NETCONN_UDP = 0x20, + /** UDP IPv4 lite */ + NETCONN_UDPLITE = 0x21, + /** UDP IPv4 no checksum */ + NETCONN_UDPNOCHKSUM = 0x22, + +#if LWIP_IPV6 + /** UDP IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, + /** UDP IPv6 lite (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, + /** UDP IPv6 no checksum (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, +#endif /* LWIP_IPV6 */ + + /** Raw connection IPv4 */ + NETCONN_RAW = 0x40 +#if LWIP_IPV6 + /** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ +#endif /* LWIP_IPV6 */ +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Used to inform the callback function about changes + * + * Event explanation: + * + * In the netconn implementation, there are three ways to block a client: + * + * - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept()) + * - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data()) + * - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write()) + * + * The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking + * connections, you need to know in advance whether a call to a netconn function call would block or not, + * and these events tell you about that. + * + * RCVPLUS events say: Safe to perform a potentially blocking call call once more. + * They are counted in sockets - three RCVPLUS events for accept mbox means you are safe + * to call netconn_accept 3 times without being blocked. + * Same thing for receive mbox. + * + * RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged". + * Socket implementation decrements the counter. + * + * For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something. + * SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again. + * A SENDMINUS event occurs when the next call to a netconn_send() would be blocking. + */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/* Used for netconn_gethostbyname_addrtype(), these should match the DNS_ADDRTYPE defines in dns.h */ +#define NETCONN_DNS_DEFAULT NETCONN_DNS_IPV4_IPV6 +#define NETCONN_DNS_IPV4 0 +#define NETCONN_DNS_IPV6 1 +#define NETCONN_DNS_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define NETCONN_DNS_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#endif /* LWIP_DNS */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last error this netconn had */ + err_t last_err; +#if !LWIP_NETCONN_SEM_PER_THREAD + /** sem that is used to synchronously execute functions in the core context */ + sys_sem_t op_completed; +#endif + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_SNDTIMEO + /** timeout to wait for sending data (which means enqueueing data for sending + in internal buffers) in milliseconds */ + s32_t send_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVTIMEO + /** timeout in milliseconds to wait for new data to be received + (or connections to arrive for listening netconns) */ + int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + /** values <0 mean linger is disabled, values > 0 are seconds to linger */ + s16_t linger; +#endif /* LWIP_SO_LINGER */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores how much is already sent. */ + size_t write_offset; + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { if ((conn) != NULL) { \ + SYS_ARCH_DECL_PROTECT(netconn_set_safe_err_lev); \ + SYS_ARCH_PROTECT(netconn_set_safe_err_lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(netconn_set_safe_err_lev); \ +}} while(0); + +/* Network connection functions: */ + +/** @ingroup netconn_common + * Create new netconn connection + * @param t @ref netconn_type */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +/** @ingroup netconn_common */ +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +/** @ingroup netconn_common */ +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +/** @ingroup netconn_tcp */ +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + const ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written); +/** @ingroup netconn_tcp */ +#define netconn_write(conn, dataptr, size, apiflags) \ + netconn_write_partly(conn, dataptr, size, apiflags, NULL) +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +err_t netconn_join_leave_group(struct netconn *conn, const ip_addr_t *multiaddr, + const ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if LWIP_DNS +#if LWIP_IPV4 && LWIP_IPV6 +err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); +#define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) +#else /* LWIP_IPV4 && LWIP_IPV6 */ +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#define netconn_gethostbyname_addrtype(name, addr, dns_addrtype) netconn_gethostbyname(name, addr) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#endif /* LWIP_DNS */ + +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +#if LWIP_IPV6 +/** @ingroup netconn_common + * TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_set_ipv6only(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_IPV6_V6ONLY; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_IPV6_V6ONLY; }} while(0) +/** @ingroup netconn_common + * TCP: Get the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_get_ipv6only(conn) (((conn)->flags & NETCONN_FLAG_IPV6_V6ONLY) != 0) +#endif /* LWIP_IPV6 */ + +#if LWIP_SO_SNDTIMEO +/** Set the send timeout in milliseconds */ +#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) +/** Get the send timeout in milliseconds */ +#define netconn_get_sendtimeout(conn) ((conn)->send_timeout) +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#if LWIP_NETCONN_SEM_PER_THREAD +void netconn_thread_init(void); +void netconn_thread_cleanup(void); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define netconn_thread_init() +#define netconn_thread_cleanup() +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_API_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/FILES b/Sming/third-party/lwip2/include/lwip/apps/FILES new file mode 100644 index 0000000000..adfc0f3345 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/FILES @@ -0,0 +1,2 @@ +This directory contains application headers. +Every application shall provide one api file APP.h and optionally one options file APP_opts.h diff --git a/Sming/third-party/lwip2/include/lwip/apps/fs.h b/Sming/third-party/lwip2/include/lwip/apps/fs.h new file mode 100644 index 0000000000..bb176fa010 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/fs.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_APPS_FS_H +#define LWIP_HDR_APPS_FS_H + +#include "httpd_opts.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FS_READ_EOF -1 +#define FS_READ_DELAYED -2 + +#if HTTPD_PRECALCULATED_CHECKSUM +struct fsdata_chksum { + u32_t offset; + u16_t chksum; + u16_t len; +}; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + +#define FS_FILE_FLAGS_HEADER_INCLUDED 0x01 +#define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02 + +struct fs_file { + const char *data; + int len; + int index; + void *pextension; +#if HTTPD_PRECALCULATED_CHECKSUM + const struct fsdata_chksum *chksum; + u16_t chksum_count; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + u8_t flags; +#if LWIP_HTTPD_CUSTOM_FILES + u8_t is_custom_file; +#endif /* LWIP_HTTPD_CUSTOM_FILES */ +#if LWIP_HTTPD_FILE_STATE + void *state; +#endif /* LWIP_HTTPD_FILE_STATE */ +}; + +#if LWIP_HTTPD_FS_ASYNC_READ +typedef void (*fs_wait_cb)(void *arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + +err_t fs_open(struct fs_file *file, const char *name); +void fs_close(struct fs_file *file); +#if LWIP_HTTPD_DYNAMIC_FILE_READ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_read(struct fs_file *file, char *buffer, int count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_bytes_left(struct fs_file *file); + +#if LWIP_HTTPD_FILE_STATE +/** This user-defined function is called when a file is opened. */ +void *fs_state_init(struct fs_file *file, const char *name); +/** This user-defined function is called when a file is closed. */ +void fs_state_free(struct fs_file *file, void *state); +#endif /* #if LWIP_HTTPD_FILE_STATE */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_FS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/httpd.h b/Sming/third-party/lwip2/include/lwip/apps/httpd.h new file mode 100644 index 0000000000..40f1811e57 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/httpd.h @@ -0,0 +1,236 @@ +/** + * @file + * HTTP server + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_H +#define LWIP_HDR_APPS_HTTPD_H + +#include "httpd_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_HTTPD_CGI + +/* + * Function pointer for a CGI script handler. + * + * This function is called each time the HTTPD server is asked for a file + * whose name was previously registered as a CGI function using a call to + * http_set_cgi_handler. The iIndex parameter provides the index of the + * CGI within the ppcURLs array passed to http_set_cgi_handler. Parameters + * pcParam and pcValue provide access to the parameters provided along with + * the URI. iNumParams provides a count of the entries in the pcParam and + * pcValue arrays. Each entry in the pcParam array contains the name of a + * parameter with the corresponding entry in the pcValue array containing the + * value for that parameter. Note that pcParam may contain multiple elements + * with the same name if, for example, a multi-selection list control is used + * in the form generating the data. + * + * The function should return a pointer to a character string which is the + * path and filename of the response that is to be sent to the connected + * browser, for example "/thanks.htm" or "/response/error.ssi". + * + * The maximum number of parameters that will be passed to this function via + * iNumParams is defined by LWIP_HTTPD_MAX_CGI_PARAMETERS. Any parameters in the incoming + * HTTP request above this number will be discarded. + * + * Requests intended for use by this CGI mechanism must be sent using the GET + * method (which encodes all parameters within the URI rather than in a block + * later in the request). Attempts to use the POST method will result in the + * request being ignored. + * + */ +typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], + char *pcValue[]); + +/* + * Structure defining the base filename (URL) of a CGI and the associated + * function which is to be called when that URL is requested. + */ +typedef struct +{ + const char *pcCGIName; + tCGIHandler pfnCGIHandler; +} tCGI; + +void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); + +#endif /* LWIP_HTTPD_CGI */ + +#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI + +#if LWIP_HTTPD_CGI_SSI +/** Define this generic CGI handler in your application. + * It is called once for every URI with parameters. + * The parameters can be stored to + */ +extern void httpd_cgi_handler(const char* uri, int iNumParams, char **pcParam, char **pcValue +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); +#endif /* LWIP_HTTPD_CGI_SSI */ + +#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */ + +#if LWIP_HTTPD_SSI + +/* + * Function pointer for the SSI tag handler callback. + * + * This function will be called each time the HTTPD server detects a tag of the + * form in a .shtml, .ssi or .shtm file where "name" appears as + * one of the tags supplied to http_set_ssi_handler in the ppcTags array. The + * returned insert string, which will be appended after the the string + * "" in file sent back to the client,should be written to pointer + * pcInsert. iInsertLen contains the size of the buffer pointed to by + * pcInsert. The iIndex parameter provides the zero-based index of the tag as + * found in the ppcTags array and identifies the tag that is to be processed. + * + * The handler returns the number of characters written to pcInsert excluding + * any terminating NULL or a negative number to indicate a failure (tag not + * recognized, for example). + * + * Note that the behavior of this SSI mechanism is somewhat different from the + * "normal" SSI processing as found in, for example, the Apache web server. In + * this case, the inserted text is appended following the SSI tag rather than + * replacing the tag entirely. This allows for an implementation that does not + * require significant additional buffering of output data yet which will still + * offer usable SSI functionality. One downside to this approach is when + * attempting to use SSI within JavaScript. The SSI tag is structured to + * resemble an HTML comment but this syntax does not constitute a comment + * within JavaScript and, hence, leaving the tag in place will result in + * problems in these cases. To work around this, any SSI tag which needs to + * output JavaScript code must do so in an encapsulated way, sending the whole + * HTML section as a single include. + */ +typedef u16_t (*tSSIHandler)( +#if LWIP_HTTPD_SSI_RAW + const char* ssi_tag_name, +#else /* LWIP_HTTPD_SSI_RAW */ + int iIndex, +#endif /* LWIP_HTTPD_SSI_RAW */ + char *pcInsert, int iInsertLen +#if LWIP_HTTPD_SSI_MULTIPART + , u16_t current_tag_part, u16_t *next_tag_part +#endif /* LWIP_HTTPD_SSI_MULTIPART */ +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); + +/** Set the SSI handler function + * (if LWIP_HTTPD_SSI_RAW==1, only the first argument is used) + */ +void http_set_ssi_handler(tSSIHandler pfnSSIHandler, + const char **ppcTags, int iNumTags); + +/** For LWIP_HTTPD_SSI_RAW==1, return this to indicate the tag is unknown. + * In this case, the webserver writes a warning into the page. + * You can also just return 0 to write nothing for unknown tags. + */ +#define HTTPD_SSI_TAG_UNKNOWN 0xFFFF + +#endif /* LWIP_HTTPD_SSI */ + +#if LWIP_HTTPD_SUPPORT_POST + +/* These functions must be implemented by the application */ + +/** Called when a POST request has been received. The application can decide + * whether to accept it or not. + * + * @param connection Unique connection identifier, valid until httpd_post_end + * is called. + * @param uri The HTTP header URI receiving the POST request. + * @param http_request The raw HTTP request (the first packet, normally). + * @param http_request_len Size of 'http_request'. + * @param content_len Content-Length from HTTP header. + * @param response_uri Filename of response file, to be filled when denying the + * request + * @param response_uri_len Size of the 'response_uri' buffer. + * @param post_auto_wnd Set this to 0 to let the callback code handle window + * updates by calling 'httpd_post_data_recved' (to throttle rx speed) + * default is 1 (httpd handles window updates automatically) + * @return ERR_OK: Accept the POST request, data may be passed in + * another err_t: Deny the POST request, send back 'bad request'. + */ +err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, + u16_t http_request_len, int content_len, char *response_uri, + u16_t response_uri_len, u8_t *post_auto_wnd); + +/** Called for each pbuf of data that has been received for a POST. + * ATTENTION: The application is responsible for freeing the pbufs passed in! + * + * @param connection Unique connection identifier. + * @param p Received data. + * @return ERR_OK: Data accepted. + * another err_t: Data denied, http_post_get_response_uri will be called. + */ +err_t httpd_post_receive_data(void *connection, struct pbuf *p); + +/** Called when all data is received or when the connection is closed. + * The application must return the filename/URI of a file to send in response + * to this POST request. If the response_uri buffer is untouched, a 404 + * response is returned. + * + * @param connection Unique connection identifier. + * @param response_uri Filename of response file, to be filled when denying the request + * @param response_uri_len Size of the 'response_uri' buffer. + */ +void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); + +#if LWIP_HTTPD_POST_MANUAL_WND +void httpd_post_data_recved(void *connection, u16_t recved_len); +#endif /* LWIP_HTTPD_POST_MANUAL_WND */ + +#endif /* LWIP_HTTPD_SUPPORT_POST */ + +void httpd_init(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HTTPD_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/httpd_opts.h b/Sming/third-party/lwip2/include/lwip/apps/httpd_opts.h new file mode 100644 index 0000000000..340db15f66 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/httpd_opts.h @@ -0,0 +1,323 @@ +/** + * @file + * HTTP server options list + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_OPTS_H +#define LWIP_HDR_APPS_HTTPD_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup httpd_opts Options + * @ingroup httpd + * @{ + */ + +/** Set this to 1 to support CGI (old style) */ +#if !defined LWIP_HTTPD_CGI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI 0 +#endif + +/** Set this to 1 to support CGI (new style) */ +#if !defined LWIP_HTTPD_CGI_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI_SSI 0 +#endif + +/** Set this to 1 to support SSI (Server-Side-Includes) */ +#if !defined LWIP_HTTPD_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI 0 +#endif + +/** Set this to 1 to implement an SSI tag handler callback that gets a const char* + * to the tag (instead of an index into a pre-registered array of known tags) */ +#if !defined LWIP_HTTPD_SSI_RAW || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_RAW 0 +#endif + +/** Set this to 1 to support HTTP POST */ +#if !defined LWIP_HTTPD_SUPPORT_POST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_POST 0 +#endif + +/* The maximum number of parameters that the CGI handler can be sent. */ +#if !defined LWIP_HTTPD_MAX_CGI_PARAMETERS || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 +#endif + +/** LWIP_HTTPD_SSI_MULTIPART==1: SSI handler function is called with 2 more + * arguments indicating a counter for insert string that are too long to be + * inserted at once: the SSI handler function must then set 'next_tag_part' + * which will be passed back to it in the next call. */ +#if !defined LWIP_HTTPD_SSI_MULTIPART || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_MULTIPART 0 +#endif + +/* The maximum length of the string comprising the tag name */ +#if !defined LWIP_HTTPD_MAX_TAG_NAME_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 +#endif + +/* The maximum length of string that can be returned to replace any given tag */ +#if !defined LWIP_HTTPD_MAX_TAG_INSERT_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 +#endif + +#if !defined LWIP_HTTPD_POST_MANUAL_WND || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MANUAL_WND 0 +#endif + +/** This string is passed in the HTTP header as "Server: " */ +#if !defined HTTPD_SERVER_AGENT || defined __DOXYGEN__ +#define HTTPD_SERVER_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)" +#endif + +/** Set this to 1 if you want to include code that creates HTTP headers + * at runtime. Default is off: HTTP headers are then created statically + * by the makefsdata tool. Static headers mean smaller code size, but + * the (readonly) fsdata will grow a bit as every file includes the HTTP + * header. */ +#if !defined LWIP_HTTPD_DYNAMIC_HEADERS || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_HEADERS 0 +#endif + +#if !defined HTTPD_DEBUG || defined __DOXYGEN__ +#define HTTPD_DEBUG LWIP_DBG_OFF +#endif + +/** Set this to 1 to use a memp pool for allocating + * struct http_state instead of the heap. + */ +#if !defined HTTPD_USE_MEM_POOL || defined __DOXYGEN__ +#define HTTPD_USE_MEM_POOL 0 +#endif + +/** The server port for HTTPD to use */ +#if !defined HTTPD_SERVER_PORT || defined __DOXYGEN__ +#define HTTPD_SERVER_PORT 80 +#endif + +/** Maximum retries before the connection is aborted/closed. + * - number of times pcb->poll is called -> default is 4*500ms = 2s; + * - reset when pcb->sent is called + */ +#if !defined HTTPD_MAX_RETRIES || defined __DOXYGEN__ +#define HTTPD_MAX_RETRIES 4 +#endif + +/** The poll delay is X*500ms */ +#if !defined HTTPD_POLL_INTERVAL || defined __DOXYGEN__ +#define HTTPD_POLL_INTERVAL 4 +#endif + +/** Priority for tcp pcbs created by HTTPD (very low by default). + * Lower priorities get killed first when running out of memory. + */ +#if !defined HTTPD_TCP_PRIO || defined __DOXYGEN__ +#define HTTPD_TCP_PRIO TCP_PRIO_MIN +#endif + +/** Set this to 1 to enable timing each file sent */ +#if !defined LWIP_HTTPD_TIMING || defined __DOXYGEN__ +#define LWIP_HTTPD_TIMING 0 +#endif +/** Set this to 1 to enable timing each file sent */ +#if !defined HTTPD_DEBUG_TIMING || defined __DOXYGEN__ +#define HTTPD_DEBUG_TIMING LWIP_DBG_OFF +#endif + +/** Set this to one to show error pages when parsing a request fails instead + of simply closing the connection. */ +#if !defined LWIP_HTTPD_SUPPORT_EXTSTATUS || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_EXTSTATUS 0 +#endif + +/** Set this to 0 to drop support for HTTP/0.9 clients (to save some bytes) */ +#if !defined LWIP_HTTPD_SUPPORT_V09 || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_V09 1 +#endif + +/** Set this to 1 to enable HTTP/1.1 persistent connections. + * ATTENTION: If the generated file system includes HTTP headers, these must + * include the "Connection: keep-alive" header (pass argument "-11" to makefsdata). + */ +#if !defined LWIP_HTTPD_SUPPORT_11_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_11_KEEPALIVE 0 +#endif + +/** Set this to 1 to support HTTP request coming in in multiple packets/pbufs */ +#if !defined LWIP_HTTPD_SUPPORT_REQUESTLIST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_REQUESTLIST 1 +#endif + +#if LWIP_HTTPD_SUPPORT_REQUESTLIST +/** Number of rx pbufs to enqueue to parse an incoming request (up to the first + newline) */ +#if !defined LWIP_HTTPD_REQ_QUEUELEN || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_QUEUELEN 5 +#endif + +/** Number of (TCP payload-) bytes (in pbufs) to enqueue to parse and incoming + request (up to the first double-newline) */ +#if !defined LWIP_HTTPD_REQ_BUFSIZE || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH +#endif + +/** Defines the maximum length of a HTTP request line (up to the first CRLF, + copied from pbuf into this a global buffer when pbuf- or packet-queues + are received - otherwise the input pbuf is used directly) */ +#if !defined LWIP_HTTPD_MAX_REQ_LENGTH || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQ_LENGTH LWIP_MIN(1023, (LWIP_HTTPD_REQ_QUEUELEN * PBUF_POOL_BUFSIZE)) +#endif +#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ + +/** This is the size of a static buffer used when URIs end with '/'. + * In this buffer, the directory requested is concatenated with all the + * configured default file names. + * Set to 0 to disable checking default filenames on non-root directories. + */ +#if !defined LWIP_HTTPD_MAX_REQUEST_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 63 +#endif + +/** Maximum length of the filename to send as response to a POST request, + * filled in by the application when a POST is finished. + */ +#if !defined LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63 +#endif + +/** Set this to 0 to not send the SSI tag (default is on, so the tag will + * be sent in the HTML page */ +#if !defined LWIP_HTTPD_SSI_INCLUDE_TAG || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_INCLUDE_TAG 1 +#endif + +/** Set this to 1 to call tcp_abort when tcp_close fails with memory error. + * This can be used to prevent consuming all memory in situations where the + * HTTP server has low priority compared to other communication. */ +#if !defined LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR || defined __DOXYGEN__ +#define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0 +#endif + +/** Set this to 1 to kill the oldest connection when running out of + * memory for 'struct http_state' or 'struct http_ssi_state'. + * ATTENTION: This puts all connections on a linked list, so may be kind of slow. + */ +#if !defined LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED || defined __DOXYGEN__ +#define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 +#endif + +/** Set this to 1 to send URIs without extension without headers + * (who uses this at all??) */ +#if !defined LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI || defined __DOXYGEN__ +#define LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI 0 +#endif + +/** Default: Tags are sent from struct http_state and are therefore volatile */ +#if !defined HTTP_IS_TAG_VOLATILE || defined __DOXYGEN__ +#define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY +#endif + +/* By default, the httpd is limited to send 2*pcb->mss to keep resource usage low + when http is not an important protocol in the device. */ +#if !defined HTTPD_LIMIT_SENDING_TO_2MSS || defined __DOXYGEN__ +#define HTTPD_LIMIT_SENDING_TO_2MSS 1 +#endif + +/* Define this to a function that returns the maximum amount of data to enqueue. + The function have this signature: u16_t fn(struct tcp_pcb* pcb); */ +#if !defined HTTPD_MAX_WRITE_LEN || defined __DOXYGEN__ +#if HTTPD_LIMIT_SENDING_TO_2MSS +#define HTTPD_MAX_WRITE_LEN(pcb) (2 * tcp_mss(pcb)) +#endif +#endif + +/*------------------- FS OPTIONS -------------------*/ + +/** Set this to 1 and provide the functions: + * - "int fs_open_custom(struct fs_file *file, const char *name)" + * Called first for every opened file to allow opening files + * that are not included in fsdata(_custom).c + * - "void fs_close_custom(struct fs_file *file)" + * Called to free resources allocated by fs_open_custom(). + */ +#if !defined LWIP_HTTPD_CUSTOM_FILES || defined __DOXYGEN__ +#define LWIP_HTTPD_CUSTOM_FILES 0 +#endif + +/** Set this to 1 to support fs_read() to dynamically read file data. + * Without this (default=off), only one-block files are supported, + * and the contents must be ready after fs_open(). + */ +#if !defined LWIP_HTTPD_DYNAMIC_FILE_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_FILE_READ 0 +#endif + +/** Set this to 1 to include an application state argument per file + * that is opened. This allows to keep a state per connection/file. + */ +#if !defined LWIP_HTTPD_FILE_STATE || defined __DOXYGEN__ +#define LWIP_HTTPD_FILE_STATE 0 +#endif + +/** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for + * predefined (MSS-sized) chunks of the files to prevent having to calculate + * the checksums at runtime. */ +#if !defined HTTPD_PRECALCULATED_CHECKSUM || defined __DOXYGEN__ +#define HTTPD_PRECALCULATED_CHECKSUM 0 +#endif + +/** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations + * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). + */ +#if !defined LWIP_HTTPD_FS_ASYNC_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_FS_ASYNC_READ 0 +#endif + +/** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the + * file system (to prevent changing the file included in CVS) */ +#if !defined HTTPD_USE_CUSTOM_FSDATA || defined __DOXYGEN__ +#define HTTPD_USE_CUSTOM_FSDATA 0 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_HTTPD_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/lwiperf.h b/Sming/third-party/lwip2/include/lwip/apps/lwiperf.h new file mode 100644 index 0000000000..7dbebb0826 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/lwiperf.h @@ -0,0 +1,84 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_LWIPERF_H +#define LWIP_HDR_APPS_LWIPERF_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIPERF_TCP_PORT_DEFAULT 5001 + +/** lwIPerf test results */ +enum lwiperf_report_type +{ + /** The server side test is done */ + LWIPERF_TCP_DONE_SERVER, + /** The client side test is done */ + LWIPERF_TCP_DONE_CLIENT, + /** Local error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL, + /** Data check error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, + /** Transmit error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_TXERROR, + /** Remote side aborted the test */ + LWIPERF_TCP_ABORTED_REMOTE +}; + +/** Prototype of a report function that is called when a session is finished. + This report function can show the test results. + @param report_type contains the test result */ +typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, + const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, + u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); + + +void* lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg); +void lwiperf_abort(void* lwiperf_session); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/mdns.h b/Sming/third-party/lwip2/include/lwip/apps/mdns.h new file mode 100644 index 0000000000..d036816115 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/mdns.h @@ -0,0 +1,69 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ +#ifndef LWIP_HDR_MDNS_H +#define LWIP_HDR_MDNS_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/netif.h" + +#if LWIP_MDNS_RESPONDER + +enum mdns_sd_proto { + DNSSD_PROTO_UDP = 0, + DNSSD_PROTO_TCP = 1 +}; + +#define MDNS_LABEL_MAXLEN 63 + +struct mdns_host; +struct mdns_service; + +/** Callback function to add text to a reply, called when generating the reply */ +typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata); + +void mdns_resp_init(void); + +err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); +err_t mdns_resp_remove_netif(struct netif *netif); + +err_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); +err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len); +void mdns_resp_netif_settings_changed(struct netif *netif); + +#endif /* LWIP_MDNS_RESPONDER */ + +#endif /* LWIP_HDR_MDNS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/mdns_opts.h b/Sming/third-party/lwip2/include/lwip/apps/mdns_opts.h new file mode 100644 index 0000000000..bf186bcce1 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/mdns_opts.h @@ -0,0 +1,74 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_OPTS_H +#define LWIP_HDR_APPS_MDNS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup mdns_opts Options + * @ingroup mdns + * @{ + */ + +/** + * LWIP_MDNS_RESPONDER==1: Turn on multicast DNS module. UDP must be available for MDNS + * transport. IGMP is needed for IPv4 multicast. + */ +#ifndef LWIP_MDNS_RESPONDER +#define LWIP_MDNS_RESPONDER 0 +#endif /* LWIP_MDNS_RESPONDER */ + +/** The maximum number of services per netif */ +#ifndef MDNS_MAX_SERVICES +#define MDNS_MAX_SERVICES 1 +#endif + +/** + * MDNS_DEBUG: Enable debugging for multicast DNS. + */ +#ifndef MDNS_DEBUG +#define MDNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_MDNS_OPTS_H */ + diff --git a/Sming/third-party/lwip2/include/lwip/apps/mdns_priv.h b/Sming/third-party/lwip2/include/lwip/apps/mdns_priv.h new file mode 100644 index 0000000000..8ee6db86af --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/mdns_priv.h @@ -0,0 +1,66 @@ +/** + * @file + * MDNS responder private definitions + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ +#ifndef LWIP_HDR_MDNS_PRIV_H +#define LWIP_HDR_MDNS_PRIV_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/pbuf.h" + +#if LWIP_MDNS_RESPONDER + +/* Domain struct and methods - visible for unit tests */ + +#define MDNS_DOMAIN_MAXLEN 256 +#define MDNS_READNAME_ERROR 0xFFFF + +struct mdns_domain { + /* Encoded domain name */ + u8_t name[MDNS_DOMAIN_MAXLEN]; + /* Total length of domain name, including zero */ + u16_t length; + /* Set if compression of this domain is not allowed */ + u8_t skip_compression; +}; + +err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); +u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); +int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); +u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); + +#endif /* LWIP_MDNS_RESPONDER */ + +#endif /* LWIP_HDR_MDNS_PRIV_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/mqtt.h b/Sming/third-party/lwip2/include/lwip/apps/mqtt.h new file mode 100644 index 0000000000..34b230b888 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/mqtt.h @@ -0,0 +1,244 @@ +/** + * @file + * MQTT client + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H +#define LWIP_HDR_APPS_MQTT_CLIENT_H + +#include "lwip/apps/mqtt_opts.h" +#include "lwip/err.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mqtt_client_t mqtt_client_t; + +/** @ingroup mqtt + * Default MQTT port */ +#define MQTT_PORT 1883 + +/*---------------------------------------------------------------------------------------------- */ +/* Connection with server */ + +/** + * @ingroup mqtt + * Client information and connection parameters */ +struct mqtt_connect_client_info_t { + /** Client identifier, must be set by caller */ + const char *client_id; + /** User name and password, set to NULL if not used */ + const char* client_user; + const char* client_pass; + /** keep alive time in seconds, 0 to disable keep alive functionality*/ + u16_t keep_alive; + /** will topic, set to NULL if will is not to be used, + will_msg, will_qos and will retain are then ignored */ + const char* will_topic; + const char* will_msg; + u8_t will_qos; + u8_t will_retain; +}; + +/** + * @ingroup mqtt + * Connection status codes */ +typedef enum +{ + MQTT_CONNECT_ACCEPTED = 0, + MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1, + MQTT_CONNECT_REFUSED_IDENTIFIER = 2, + MQTT_CONNECT_REFUSED_SERVER = 3, + MQTT_CONNECT_REFUSED_USERNAME_PASS = 4, + MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5, + MQTT_CONNECT_DISCONNECTED = 256, + MQTT_CONNECT_TIMEOUT = 257 +} mqtt_connection_status_t; + +/** + * @ingroup mqtt + * Function prototype for mqtt connection status callback. Called when + * client has connected to the server after initiating a mqtt connection attempt by + * calling mqtt_connect() or when connection is closed by server or an error + * + * @param client MQTT client itself + * @param arg Additional argument to pass to the callback function + * @param status Connect result code or disconnection notification @see mqtt_connection_status_t + * + */ +typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status); + + +/** + * @ingroup mqtt + * Data callback flags */ +enum { + /** Flag set when last fragment of data arrives in data callback */ + MQTT_DATA_FLAG_LAST = 1 +}; + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish data callback function. Called when data + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param data User data, pointed object, data may not be referenced after callback return, + NULL is passed when all publish data are delivered + * @param len Length of publish data fragment + * @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message + * + */ +typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); + + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish function. Called when an incoming publish + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param topic Zero terminated Topic text string, topic may not be referenced after callback return + * @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked + */ +typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); + + +/** + * @ingroup mqtt + * Function prototype for mqtt request callback. Called when a subscribe, unsubscribe + * or publish request has completed + * @param arg Pointer to user data supplied when invoking request + * @param err ERR_OK on success + * ERR_TIMEOUT if no response was received within timeout, + * ERR_ABRT if (un)subscribe was denied + */ +typedef void (*mqtt_request_cb_t)(void *arg, err_t err); + + +/** + * Pending request item, binds application callback to pending server requests + */ +struct mqtt_request_t +{ + /** Next item in list, NULL means this is the last in chain, + next pointing at itself means request is unallocated */ + struct mqtt_request_t *next; + /** Callback to upper layer */ + mqtt_request_cb_t cb; + void *arg; + /** MQTT packet identifier */ + u16_t pkt_id; + /** Expire time relative to element before this */ + u16_t timeout_diff; +}; + +/** Ring buffer */ +struct mqtt_ringbuf_t { + u16_t put; + u16_t get; + u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; +}; + +/** MQTT client */ +struct mqtt_client_t +{ + /** Timers and timeouts */ + u16_t cyclic_tick; + u16_t keep_alive; + u16_t server_watchdog; + /** Packet identifier generator*/ + u16_t pkt_id_seq; + /** Packet identifier of pending incoming publish */ + u16_t inpub_pkt_id; + /** Connection state */ + u8_t conn_state; + struct tcp_pcb *conn; + /** Connection callback */ + void *connect_arg; + mqtt_connection_cb_t connect_cb; + /** Pending requests to server */ + struct mqtt_request_t *pend_req_queue; + struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT]; + void *inpub_arg; + /** Incoming data callback */ + mqtt_incoming_data_cb_t data_cb; + mqtt_incoming_publish_cb_t pub_cb; + /** Input */ + u32_t msg_idx; + u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN]; + /** Output ring-buffer */ + struct mqtt_ringbuf_t output; +}; + + +/** Connect to server */ +err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg, + const struct mqtt_connect_client_info_t *client_info); + +/** Disconnect from server */ +void mqtt_disconnect(mqtt_client_t *client); + +/** Create new client */ +mqtt_client_t *mqtt_client_new(void); + +/** Check connection status */ +u8_t mqtt_client_is_connected(mqtt_client_t *client); + +/** Set callback to call for incoming publish */ +void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, + mqtt_incoming_data_cb_t data_cb, void *arg); + +/** Common function for subscribe and unsubscribe */ +err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub); + +/** @ingroup mqtt + *Subscribe to topic */ +#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) +/** @ingroup mqtt + * Unsubscribe to topic */ +#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0) + + +/** Publish data to topic */ +err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain, + mqtt_request_cb_t cb, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/mqtt_opts.h b/Sming/third-party/lwip2/include/lwip/apps/mqtt_opts.h new file mode 100644 index 0000000000..ffefacd259 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/mqtt_opts.h @@ -0,0 +1,103 @@ +/** + * @file + * MQTT client options + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_OPTS_H +#define LWIP_HDR_APPS_MQTT_OPTS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mqtt_opts Options + * @ingroup mqtt + * @{ + */ + +/** + * Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads + */ +#ifndef MQTT_OUTPUT_RINGBUF_SIZE +#define MQTT_OUTPUT_RINGBUF_SIZE 256 +#endif + +/** + * Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8 + * If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8 + */ +#ifndef MQTT_VAR_HEADER_BUFFER_LEN +#define MQTT_VAR_HEADER_BUFFER_LEN 128 +#endif + +/** + * Maximum number of pending subscribe, unsubscribe and publish requests to server . + */ +#ifndef MQTT_REQ_MAX_IN_FLIGHT +#define MQTT_REQ_MAX_IN_FLIGHT 4 +#endif + +/** + * Seconds between each cyclic timer call. + */ +#ifndef MQTT_CYCLIC_TIMER_INTERVAL +#define MQTT_CYCLIC_TIMER_INTERVAL 5 +#endif + +/** + * Publish, subscribe and unsubscribe request timeout in seconds. + */ +#ifndef MQTT_REQ_TIMEOUT +#define MQTT_REQ_TIMEOUT 30 +#endif + +/** + * Seconds for MQTT connect response timeout after sending connect request + */ +#ifndef MQTT_CONNECT_TIMOUT +#define MQTT_CONNECT_TIMOUT 100 +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/netbiosns.h b/Sming/third-party/lwip2/include/lwip/apps/netbiosns.h new file mode 100644 index 0000000000..c9f68d8d12 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/netbiosns.h @@ -0,0 +1,43 @@ +/** + * @file + * NETBIOS name service responder + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_H +#define LWIP_HDR_APPS_NETBIOS_H + +#include "lwip/apps/netbiosns_opts.h" + +void netbiosns_init(void); +#ifndef NETBIOS_LWIP_NAME +void netbiosns_set_name(const char* hostname); +#endif +void netbiosns_stop(void); + +#endif /* LWIP_HDR_APPS_NETBIOS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/netbiosns_opts.h b/Sming/third-party/lwip2/include/lwip/apps/netbiosns_opts.h new file mode 100644 index 0000000000..0909ef7b94 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/netbiosns_opts.h @@ -0,0 +1,59 @@ +/** + * @file + * NETBIOS name service responder options + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_OPTS_H +#define LWIP_HDR_APPS_NETBIOS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup netbiosns_opts Options + * @ingroup netbiosns + * @{ + */ + +/** NetBIOS name of lwip device + * This must be uppercase until NETBIOS_STRCMP() is defined to a string + * comparision function that is case insensitive. + * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): + * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") + * + * If this is not defined, netbiosns_set_name() can be called at runtime to change the name. + */ +#ifdef __DOXYGEN__ +#define NETBIOS_LWIP_NAME "NETBIOSLWIPDEV" +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_NETBIOS_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp.h b/Sming/third-party/lwip2/include/lwip/apps/snmp.h new file mode 100644 index 0000000000..10e8ff434b --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp.h @@ -0,0 +1,128 @@ +/** + * @file + * SNMP server main API - start and basic configuration + */ + +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * Martin Hentschel + * + */ +#ifndef LWIP_HDR_APPS_SNMP_H +#define LWIP_HDR_APPS_SNMP_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/apps/snmp_core.h" + +/** SNMP variable binding descriptor (publically needed for traps) */ +struct snmp_varbind +{ + /** pointer to next varbind, NULL for last in list */ + struct snmp_varbind *next; + /** pointer to previous varbind, NULL for first in list */ + struct snmp_varbind *prev; + + /** object identifier */ + struct snmp_obj_id oid; + + /** value ASN1 type */ + u8_t type; + /** object value length */ + u16_t value_len; + /** object value */ + void *value; +}; + +/** + * @ingroup snmp_core + * Agent setup, start listening to port 161. + */ +void snmp_init(void); +void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs); + +void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid); +const struct snmp_obj_id* snmp_get_device_enterprise_oid(void); + +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst); + +/** Generic trap: cold start */ +#define SNMP_GENTRAP_COLDSTART 0 +/** Generic trap: warm start */ +#define SNMP_GENTRAP_WARMSTART 1 +/** Generic trap: link down */ +#define SNMP_GENTRAP_LINKDOWN 2 +/** Generic trap: link up */ +#define SNMP_GENTRAP_LINKUP 3 +/** Generic trap: authentication failure */ +#define SNMP_GENTRAP_AUTH_FAILURE 4 +/** Generic trap: EGP neighbor lost */ +#define SNMP_GENTRAP_EGP_NEIGHBOR_LOSS 5 +/** Generic trap: enterprise specific */ +#define SNMP_GENTRAP_ENTERPRISE_SPECIFIC 6 + +err_t snmp_send_trap_generic(s32_t generic_trap); +err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds); +err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); + +#define SNMP_AUTH_TRAPS_DISABLED 0 +#define SNMP_AUTH_TRAPS_ENABLED 1 +void snmp_set_auth_traps_enabled(u8_t enable); +u8_t snmp_get_auth_traps_enabled(void); + +const char * snmp_get_community(void); +const char * snmp_get_community_write(void); +const char * snmp_get_community_trap(void); +void snmp_set_community(const char * const community); +void snmp_set_community_write(const char * const community); +void snmp_set_community_trap(const char * const community); + +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +typedef void (*snmp_write_callback_fct)(const u32_t* oid, u8_t oid_len, void* callback_arg); +void snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_core.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_core.h new file mode 100644 index 0000000000..e781c532b3 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_core.h @@ -0,0 +1,364 @@ +/** + * @file + * SNMP core API for implementing MIBs + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + */ + +#ifndef LWIP_HDR_APPS_SNMP_CORE_H +#define LWIP_HDR_APPS_SNMP_CORE_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* basic ASN1 defines */ +#define SNMP_ASN1_CLASS_UNIVERSAL 0x00 +#define SNMP_ASN1_CLASS_APPLICATION 0x40 +#define SNMP_ASN1_CLASS_CONTEXT 0x80 +#define SNMP_ASN1_CLASS_PRIVATE 0xC0 + +#define SNMP_ASN1_CONTENTTYPE_PRIMITIVE 0x00 +#define SNMP_ASN1_CONTENTTYPE_CONSTRUCTED 0x20 + +/* universal tags (from ASN.1 spec.) */ +#define SNMP_ASN1_UNIVERSAL_END_OF_CONTENT 0 +#define SNMP_ASN1_UNIVERSAL_INTEGER 2 +#define SNMP_ASN1_UNIVERSAL_OCTET_STRING 4 +#define SNMP_ASN1_UNIVERSAL_NULL 5 +#define SNMP_ASN1_UNIVERSAL_OBJECT_ID 6 +#define SNMP_ASN1_UNIVERSAL_SEQUENCE_OF 16 + +/* application specific (SNMP) tags (from SNMPv2-SMI) */ +#define SNMP_ASN1_APPLICATION_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */ +#define SNMP_ASN1_APPLICATION_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */ +#define SNMP_ASN1_APPLICATION_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */ + +/* context specific (SNMP) tags (from RFC 1905) */ +#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE 1 + +/* full ASN1 type defines */ +#define SNMP_ASN1_TYPE_END_OF_CONTENT (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_END_OF_CONTENT) +#define SNMP_ASN1_TYPE_INTEGER (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_INTEGER) +#define SNMP_ASN1_TYPE_OCTET_STRING (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OCTET_STRING) +#define SNMP_ASN1_TYPE_NULL (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_NULL) +#define SNMP_ASN1_TYPE_OBJECT_ID (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OBJECT_ID) +#define SNMP_ASN1_TYPE_SEQUENCE (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_UNIVERSAL_SEQUENCE_OF) +#define SNMP_ASN1_TYPE_IPADDR (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_IPADDR) +#define SNMP_ASN1_TYPE_IPADDRESS SNMP_ASN1_TYPE_IPADDR +#define SNMP_ASN1_TYPE_COUNTER (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER) +#define SNMP_ASN1_TYPE_COUNTER32 SNMP_ASN1_TYPE_COUNTER +#define SNMP_ASN1_TYPE_GAUGE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_GAUGE) +#define SNMP_ASN1_TYPE_GAUGE32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_UNSIGNED32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_TIMETICKS (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_TIMETICKS) +#define SNMP_ASN1_TYPE_OPAQUE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_OPAQUE) +#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64) + +#define SNMP_VARBIND_EXCEPTION_OFFSET 0xF0 +#define SNMP_VARBIND_EXCEPTION_MASK 0x0F + +/** error codes predefined by SNMP prot. */ +typedef enum { + SNMP_ERR_NOERROR = 0, +/* +outdated v1 error codes. do not use anmore! +#define SNMP_ERR_NOSUCHNAME 2 use SNMP_ERR_NOSUCHINSTANCE instead +#define SNMP_ERR_BADVALUE 3 use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead +#define SNMP_ERR_READONLY 4 use SNMP_ERR_NOTWRITABLE instead +*/ + SNMP_ERR_GENERROR = 5, + SNMP_ERR_NOACCESS = 6, + SNMP_ERR_WRONGTYPE = 7, + SNMP_ERR_WRONGLENGTH = 8, + SNMP_ERR_WRONGENCODING = 9, + SNMP_ERR_WRONGVALUE = 10, + SNMP_ERR_NOCREATION = 11, + SNMP_ERR_INCONSISTENTVALUE = 12, + SNMP_ERR_RESOURCEUNAVAILABLE = 13, + SNMP_ERR_COMMITFAILED = 14, + SNMP_ERR_UNDOFAILED = 15, + SNMP_ERR_NOTWRITABLE = 17, + SNMP_ERR_INCONSISTENTNAME = 18, + + SNMP_ERR_NOSUCHINSTANCE = SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE +} snmp_err_t; + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + u32_t id[SNMP_MAX_OBJ_ID_LEN]; +}; + +struct snmp_obj_id_const_ref +{ + u8_t len; + const u32_t* id; +}; + +extern const struct snmp_obj_id_const_ref snmp_zero_dot_zero; /* administrative identifier from SNMPv2-SMI */ + +/** SNMP variant value, used as reference in struct snmp_node_instance and table implementation */ +union snmp_variant_value +{ + void* ptr; + const void* const_ptr; + u32_t u32; + s32_t s32; +}; + + +/** +SNMP MIB node types + tree node is the only node the stack can process in order to walk the tree, + all other nodes are assumed to be leaf nodes. + This cannot be an enum because users may want to define their own node types. +*/ +#define SNMP_NODE_TREE 0x00 +/* predefined leaf node types */ +#define SNMP_NODE_SCALAR 0x01 +#define SNMP_NODE_SCALAR_ARRAY 0x02 +#define SNMP_NODE_TABLE 0x03 +#define SNMP_NODE_THREADSYNC 0x04 + +/** node "base class" layout, the mandatory fields for a node */ +struct snmp_node +{ + /** one out of SNMP_NODE_TREE or any leaf node type (like SNMP_NODE_SCALAR) */ + u8_t node_type; + /** the number assigned to this node which used as part of the full OID */ + u32_t oid; +}; + +/** SNMP node instance access types */ +typedef enum { + SNMP_NODE_INSTANCE_ACCESS_READ = 1, + SNMP_NODE_INSTANCE_ACCESS_WRITE = 2, + SNMP_NODE_INSTANCE_READ_ONLY = SNMP_NODE_INSTANCE_ACCESS_READ, + SNMP_NODE_INSTANCE_READ_WRITE = (SNMP_NODE_INSTANCE_ACCESS_READ | SNMP_NODE_INSTANCE_ACCESS_WRITE), + SNMP_NODE_INSTANCE_WRITE_ONLY = SNMP_NODE_INSTANCE_ACCESS_WRITE, + SNMP_NODE_INSTANCE_NOT_ACCESSIBLE = 0 +} snmp_access_t; + +struct snmp_node_instance; + +typedef s16_t (*node_instance_get_value_method)(struct snmp_node_instance*, void*); +typedef snmp_err_t (*node_instance_set_test_method)(struct snmp_node_instance*, u16_t, void*); +typedef snmp_err_t (*node_instance_set_value_method)(struct snmp_node_instance*, u16_t, void*); +typedef void (*node_instance_release_method)(struct snmp_node_instance*); + +#define SNMP_GET_VALUE_RAW_DATA 0x8000 + +/** SNMP node instance */ +struct snmp_node_instance +{ + /** prefilled with the node, get_instance() is called on; may be changed by user to any value to pass an arbitrary node between calls to get_instance() and get_value/test_value/set_value */ + const struct snmp_node* node; + /** prefilled with the instance id requested; for get_instance() this is the exact oid requested; for get_next_instance() this is the relative starting point, stack expects relative oid of next node here */ + struct snmp_obj_id instance_oid; + + /** ASN type for this object (see snmp_asn1.h for definitions) */ + u8_t asn1_type; + /** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */ + snmp_access_t access; + + /** returns object value for the given object identifier. Return values <0 to indicate an error */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; + /** called in any case when the instance is not required anymore by stack (useful for freeing memory allocated in get_instance/get_next_instance methods) */ + node_instance_release_method release_instance; + + /** reference to pass arbitrary value between calls to get_instance() and get_value/test_value/set_value */ + union snmp_variant_value reference; + /** see reference (if reference is a pointer, the length of underlying data may be stored here or anything else) */ + u32_t reference_len; +}; + + +/** SNMP tree node */ +struct snmp_tree_node +{ + /** inherited "base class" members */ + struct snmp_node node; + u16_t subnode_count; + const struct snmp_node* const *subnodes; +}; + +#define SNMP_CREATE_TREE_NODE(oid, subnodes) \ + {{ SNMP_NODE_TREE, (oid) }, \ + (u16_t)LWIP_ARRAYSIZE(subnodes), (subnodes) } + +#define SNMP_CREATE_EMPTY_TREE_NODE(oid) \ + {{ SNMP_NODE_TREE, (oid) }, \ + 0, NULL } + +/** SNMP leaf node */ +struct snmp_leaf_node +{ + /** inherited "base class" members */ + struct snmp_node node; + snmp_err_t (*get_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + snmp_err_t (*get_next_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +}; + +/** represents a single mib with its base oid and root node */ +struct snmp_mib +{ + const u32_t *base_oid; + u8_t base_oid_len; + const struct snmp_node *root_node; +}; + +#define SNMP_MIB_CREATE(oid_list, root_node) { (oid_list), (u8_t)LWIP_ARRAYSIZE(oid_list), root_node } + +/** OID range structure */ +struct snmp_oid_range +{ + u32_t min; + u32_t max; +}; + +/** checks if incoming OID length and values are in allowed ranges */ +u8_t snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len); + +typedef enum { + SNMP_NEXT_OID_STATUS_SUCCESS, + SNMP_NEXT_OID_STATUS_NO_MATCH, + SNMP_NEXT_OID_STATUS_BUF_TO_SMALL +} snmp_next_oid_status_t; + +/** state for next_oid_init / next_oid_check functions */ +struct snmp_next_oid_state +{ + const u32_t* start_oid; + u8_t start_oid_len; + + u32_t* next_oid; + u8_t next_oid_len; + u8_t next_oid_max_len; + + snmp_next_oid_status_t status; + void* reference; +}; + +void snmp_next_oid_init(struct snmp_next_oid_state *state, + const u32_t *start_oid, u8_t start_oid_len, + u32_t *next_oid_buf, u8_t next_oid_max_len); +u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len); +u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference); + +void snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +void snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +u8_t snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +s8_t snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); + +#if LWIP_IPV4 +u8_t snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip); +void snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +u8_t snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip); +void snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 || LWIP_IPV6 +u8_t snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid); +u8_t snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid); + +u8_t snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip); +u8_t snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port); +#endif /* LWIP_IPV4 || LWIP_IPV6 */ + +struct netif; +u8_t netif_to_num(const struct netif *netif); + +snmp_err_t snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value); /* generic function which can be used if test is always successful */ + +err_t snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value); +err_t snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value); +u8_t snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count); +u8_t snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value); + +struct snmp_statistics +{ + u32_t inpkts; + u32_t outpkts; + u32_t inbadversions; + u32_t inbadcommunitynames; + u32_t inbadcommunityuses; + u32_t inasnparseerrs; + u32_t intoobigs; + u32_t innosuchnames; + u32_t inbadvalues; + u32_t inreadonlys; + u32_t ingenerrs; + u32_t intotalreqvars; + u32_t intotalsetvars; + u32_t ingetrequests; + u32_t ingetnexts; + u32_t insetrequests; + u32_t ingetresponses; + u32_t intraps; + u32_t outtoobigs; + u32_t outnosuchnames; + u32_t outbadvalues; + u32_t outgenerrs; + u32_t outgetrequests; + u32_t outgetnexts; + u32_t outsetrequests; + u32_t outgetresponses; + u32_t outtraps; +}; + +extern struct snmp_statistics snmp_stats; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_CORE_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_mib2.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_mib2.h new file mode 100644 index 0000000000..2f4a68935e --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_mib2.h @@ -0,0 +1,78 @@ +/** + * @file + * SNMP MIB2 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_APPS_SNMP_MIB2_H +#define LWIP_HDR_APPS_SNMP_MIB2_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ +#if SNMP_LWIP_MIB2 + +#include "lwip/apps/snmp_core.h" + +extern const struct snmp_mib mib2; + +#if SNMP_USE_NETCONN +#include "lwip/apps/snmp_threadsync.h" +void snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg); +extern struct snmp_threadsync_instance snmp_mib2_lwip_locks; +#endif + +#ifndef SNMP_SYSSERVICES +#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) +#endif + +void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */ +void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen); + +#endif /* SNMP_LWIP_MIB2 */ +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_MIB2_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_opts.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_opts.h new file mode 100644 index 0000000000..6c9ba7beb3 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_opts.h @@ -0,0 +1,293 @@ +/** + * @file + * SNMP server options list + */ + +/* + * Copyright (c) 2015 Dirk Ziegelmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_OPTS_H +#define LWIP_HDR_SNMP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup snmp_opts Options + * @ingroup snmp + * @{ + */ + +/** + * LWIP_SNMP==1: This enables the lwIP SNMP agent. UDP must be available + * for SNMP transport. + * If you want to use your own SNMP agent, leave this disabled. + * To integrate MIB2 of an external agent, you need to enable + * LWIP_MIB2_CALLBACKS and MIB2_STATS. This will give you the callbacks + * and statistics counters you need to get MIB2 working. + */ +#if !defined LWIP_SNMP || defined __DOXYGEN__ +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_USE_NETCONN: Use netconn API instead of raw API. + * Makes SNMP agent run in a worker thread, so blocking operations + * can be done in MIB calls. + */ +#if !defined SNMP_USE_NETCONN || defined __DOXYGEN__ +#define SNMP_USE_NETCONN 0 +#endif + +/** + * SNMP_USE_RAW: Use raw API. + * SNMP agent does not run in a worker thread, so blocking operations + * should not be done in MIB calls. + */ +#if !defined SNMP_USE_RAW || defined __DOXYGEN__ +#define SNMP_USE_RAW 1 +#endif + +#if SNMP_USE_NETCONN && SNMP_USE_RAW +#error SNMP stack can use only one of the APIs {raw, netconn} +#endif + +#if LWIP_SNMP && !SNMP_USE_NETCONN && !SNMP_USE_RAW +#error SNMP stack needs a receive API and UDP {raw, netconn} +#endif + +#if SNMP_USE_NETCONN +/** + * SNMP_STACK_SIZE: Stack size of SNMP netconn worker thread + */ +#if !defined SNMP_STACK_SIZE || defined __DOXYGEN__ +#define SNMP_STACK_SIZE DEFAULT_THREAD_STACKSIZE +#endif + +/** + * SNMP_THREAD_PRIO: SNMP netconn worker thread priority + */ +#if !defined SNMP_THREAD_PRIO || defined __DOXYGEN__ +#define SNMP_THREAD_PRIO DEFAULT_THREAD_PRIO +#endif +#endif /* SNMP_USE_NETCONN */ + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#if !defined SNMP_TRAP_DESTINATIONS || defined __DOXYGEN__ +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#if !defined SNMP_SAFE_REQUESTS || defined __DOXYGEN__ +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. + */ +#if !defined SNMP_MAX_OCTET_STRING_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum number of Sub ID's inside an object identifier. + * Indirectly this also limits the maximum depth of SNMP tree. + */ +#if !defined SNMP_MAX_OBJ_ID_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OBJ_ID_LEN 50 +#endif + +#if !defined SNMP_MAX_VALUE_SIZE || defined __DOXYGEN__ +/** + * The maximum size of a value. + */ +#define SNMP_MIN_VALUE_SIZE (2 * sizeof(u32_t*)) /* size required to store the basic types (8 bytes for counter64) */ +/** + * The minimum size of a value. + */ +#define SNMP_MAX_VALUE_SIZE LWIP_MAX(LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN), sizeof(u32_t)*(SNMP_MAX_OBJ_ID_LEN)), SNMP_MIN_VALUE_SIZE) +#endif + +/** + * The snmp read-access community. Used for write-access and traps, too + * unless SNMP_COMMUNITY_WRITE or SNMP_COMMUNITY_TRAP are enabled, respectively. + */ +#if !defined SNMP_COMMUNITY || defined __DOXYGEN__ +#define SNMP_COMMUNITY "public" +#endif + +/** + * The snmp write-access community. + * Set this community to "" in order to disallow any write access. + */ +#if !defined SNMP_COMMUNITY_WRITE || defined __DOXYGEN__ +#define SNMP_COMMUNITY_WRITE "private" +#endif + +/** + * The snmp community used for sending traps. + */ +#if !defined SNMP_COMMUNITY_TRAP || defined __DOXYGEN__ +#define SNMP_COMMUNITY_TRAP "public" +#endif + +/** + * The maximum length of community string. + * If community names shall be adjusted at runtime via snmp_set_community() calls, + * enter here the possible maximum length (+1 for terminating null character). + */ +#if !defined SNMP_MAX_COMMUNITY_STR_LEN || defined __DOXYGEN__ +#define SNMP_MAX_COMMUNITY_STR_LEN LWIP_MAX(LWIP_MAX(sizeof(SNMP_COMMUNITY), sizeof(SNMP_COMMUNITY_WRITE)), sizeof(SNMP_COMMUNITY_TRAP)) +#endif + +/** + * The OID identifiying the device. This may be the enterprise OID itself or any OID located below it in tree. + */ +#if !defined SNMP_DEVICE_ENTERPRISE_OID || defined __DOXYGEN__ +#define SNMP_LWIP_ENTERPRISE_OID 26381 +/** + * IANA assigned enterprise ID for lwIP is 26381 + * @see http://www.iana.org/assignments/enterprise-numbers + * + * @note this enterprise ID is assigned to the lwIP project, + * all object identifiers living under this ID are assigned + * by the lwIP maintainers! + * @note don't change this define, use snmp_set_device_enterprise_oid() + * + * If you need to create your own private MIB you'll need + * to apply for your own enterprise ID with IANA: + * http://www.iana.org/numbers.html + */ +#define SNMP_DEVICE_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, SNMP_LWIP_ENTERPRISE_OID} +/** + * Length of SNMP_DEVICE_ENTERPRISE_OID + */ +#define SNMP_DEVICE_ENTERPRISE_OID_LEN 7 +#endif + +/** + * SNMP_DEBUG: Enable debugging for SNMP messages. + */ +#if !defined SNMP_DEBUG || defined __DOXYGEN__ +#define SNMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#if !defined SNMP_MIB_DEBUG || defined __DOXYGEN__ +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * Indicates if the MIB2 implementation of LWIP SNMP stack is used. + */ +#if !defined SNMP_LWIP_MIB2 || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2 LWIP_SNMP +#endif + +/** + * Value return for sysDesc field of MIB2. + */ +#if !defined SNMP_LWIP_MIB2_SYSDESC || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSDESC "lwIP" +#endif + +/** + * Value return for sysName field of MIB2. + * To make sysName field settable, call snmp_mib2_set_sysname() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSNAME || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSNAME "FQDN-unk" +#endif + +/** + * Value return for sysContact field of MIB2. + * To make sysContact field settable, call snmp_mib2_set_syscontact() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSCONTACT || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSCONTACT "" +#endif + +/** + * Value return for sysLocation field of MIB2. + * To make sysLocation field settable, call snmp_mib2_set_syslocation() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSLOCATION || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSLOCATION "" +#endif + +/** + * This value is used to limit the repetitions processed in GetBulk requests (value == 0 means no limitation). + * This may be useful to limit the load for a single request. + * According to SNMP RFC 1905 it is allowed to not return all requested variables from a GetBulk request if system load would be too high. + * so the effect is that the client will do more requests to gather all data. + * For the stack this could be useful in case that SNMP processing is done in TCP/IP thread. In this situation a request with many + * repetitions could block the thread for a longer time. Setting limit here will keep the stack more responsive. + */ +#if !defined SNMP_LWIP_GETBULK_MAX_REPETITIONS || defined __DOXYGEN__ +#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0 +#endif + +/** + * @} + */ + +/* + ------------------------------------ + ---------- SNMPv3 options ---------- + ------------------------------------ +*/ + +/** + * LWIP_SNMP_V3==1: This enables EXPERIMENTAL SNMPv3 support. LWIP_SNMP must + * also be enabled. + * THIS IS UNDER DEVELOPMENT AND SHOULD NOT BE ENABLED IN PRODUCTS. + */ +#ifndef LWIP_SNMP_V3 +#define LWIP_SNMP_V3 0 +#endif + +#ifndef LWIP_SNMP_V3_CRYPTO +#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3 +#endif + +#ifndef LWIP_SNMP_V3_MBEDTLS +#define LWIP_SNMP_V3_MBEDTLS LWIP_SNMP_V3 +#endif + +#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_scalar.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_scalar.h new file mode 100644 index 0000000000..40a060c640 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_scalar.h @@ -0,0 +1,113 @@ +/** + * @file + * SNMP server MIB API to implement scalar nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_SCALAR_H +#define LWIP_HDR_APPS_SNMP_SCALAR_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** basic scalar node */ +struct snmp_scalar_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u8_t asn1_type; + snmp_access_t access; + node_instance_get_value_method get_value; + node_instance_set_test_method set_test; + node_instance_set_value_method set_value; +}; + + +snmp_err_t snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_NODE(oid, access, asn1_type, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR, (oid) }, \ + snmp_scalar_get_instance, \ + snmp_scalar_get_next_instance }, \ + (asn1_type), (access), (get_value_method), (set_test_method), (set_value_method) } + +#define SNMP_SCALAR_CREATE_NODE_READONLY(oid, asn1_type, get_value_method) SNMP_SCALAR_CREATE_NODE(oid, SNMP_NODE_INSTANCE_READ_ONLY, asn1_type, get_value_method, NULL, NULL) + +/** scalar array node - a tree node which contains scalars only as children */ +struct snmp_scalar_array_node_def +{ + u32_t oid; + u8_t asn1_type; + snmp_access_t access; +}; + +typedef s16_t (*snmp_scalar_array_get_value_method)(const struct snmp_scalar_array_node_def*, void*); +typedef snmp_err_t (*snmp_scalar_array_set_test_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); +typedef snmp_err_t (*snmp_scalar_array_set_value_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); + +/** basic scalar array node */ +struct snmp_scalar_array_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t array_node_count; + const struct snmp_scalar_array_node_def* array_nodes; + snmp_scalar_array_get_value_method get_value; + snmp_scalar_array_set_test_method set_test; + snmp_scalar_array_set_value_method set_value; +}; + +snmp_err_t snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_ARRAY_NODE(oid, array_nodes, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR_ARRAY, (oid) }, \ + snmp_scalar_array_get_instance, \ + snmp_scalar_array_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(array_nodes), (array_nodes), (get_value_method), (set_test_method), (set_value_method) } + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_SCALAR_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_table.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_table.h new file mode 100644 index 0000000000..4988b51c25 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_table.h @@ -0,0 +1,134 @@ +/** + * @file + * SNMP server MIB API to implement table nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_TABLE_H +#define LWIP_HDR_APPS_SNMP_TABLE_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** default (customizable) read/write table */ +struct snmp_table_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_access_t access; +}; + +/** table node */ +struct snmp_table_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_col_def* columns; + snmp_err_t (*get_cell_instance)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); + snmp_err_t (*get_next_cell_instance)(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); + /** returns object value for the given object identifier */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; +}; + +snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE(oid, columns, get_cell_instance_method, get_next_cell_instance_method, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_get_instance, \ + snmp_table_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), \ + (get_cell_instance_method), (get_next_cell_instance_method), \ + (get_value_method), (set_test_method), (set_value_method)} + +#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */ + + +/** simple read-only table */ +typedef enum { + SNMP_VARIANT_VALUE_TYPE_U32, + SNMP_VARIANT_VALUE_TYPE_S32, + SNMP_VARIANT_VALUE_TYPE_PTR, + SNMP_VARIANT_VALUE_TYPE_CONST_PTR +} snmp_table_column_data_type_t; + +struct snmp_table_simple_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_table_column_data_type_t data_type; /* depending of what union member is used to store the value*/ +}; + +/** simple read-only table node */ +struct snmp_table_simple_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_simple_col_def* columns; + snmp_err_t (*get_cell_value)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len); + snmp_err_t (*get_next_cell_instance_and_value)(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len); +}; + +snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE_SIMPLE(oid, columns, get_cell_value_method, get_next_cell_instance_and_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_simple_get_instance, \ + snmp_table_simple_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), (get_cell_value_method), (get_next_cell_instance_and_value_method) } + +s16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_TABLE_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmp_threadsync.h b/Sming/third-party/lwip2/include/lwip/apps/snmp_threadsync.h new file mode 100644 index 0000000000..a25dbf2d0f --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmp_threadsync.h @@ -0,0 +1,114 @@ +/** + * @file + * SNMP server MIB API to implement thread synchronization + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_THREADSYNC_H +#define LWIP_HDR_APPS_SNMP_THREADSYNC_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_core.h" +#include "lwip/sys.h" + +typedef void (*snmp_threadsync_called_fn)(void* arg); +typedef void (*snmp_threadsync_synchronizer_fn)(snmp_threadsync_called_fn fn, void* arg); + + +/** Thread sync runtime data. For internal usage only. */ +struct threadsync_data +{ + union { + snmp_err_t err; + s16_t s16; + } retval; + union { + const u32_t *root_oid; + void *value; + } arg1; + union { + u8_t root_oid_len; + u16_t len; + } arg2; + const struct snmp_threadsync_node *threadsync_node; + struct snmp_node_instance proxy_instance; +}; + +/** Thread sync instance. Needed EXCATLY once for every thread to be synced into. */ +struct snmp_threadsync_instance +{ + sys_sem_t sem; + sys_mutex_t sem_usage_mutex; + snmp_threadsync_synchronizer_fn sync_fn; + struct threadsync_data data; +}; + +/** SNMP thread sync proxy leaf node */ +struct snmp_threadsync_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + + const struct snmp_leaf_node *target; + struct snmp_threadsync_instance *instance; +}; + +snmp_err_t snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +/** Create thread sync proxy node */ +#define SNMP_CREATE_THREAD_SYNC_NODE(oid, target_leaf_node, threadsync_instance) \ + {{{ SNMP_NODE_THREADSYNC, (oid) }, \ + snmp_threadsync_get_instance, \ + snmp_threadsync_get_next_instance }, \ + (target_leaf_node), \ + (threadsync_instance) } + +/** Create thread sync instance data */ +void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_THREADSYNC_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/snmpv3.h b/Sming/third-party/lwip2/include/lwip/apps/snmpv3.h new file mode 100644 index 0000000000..c99fed4e10 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/snmpv3.h @@ -0,0 +1,90 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_H +#define LWIP_HDR_APPS_SNMP_V3_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#define SNMP_V3_AUTH_ALGO_INVAL 0 +#define SNMP_V3_AUTH_ALGO_MD5 1 +#define SNMP_V3_AUTH_ALGO_SHA 2 + +#define SNMP_V3_PRIV_ALGO_INVAL 0 +#define SNMP_V3_PRIV_ALGO_DES 1 +#define SNMP_V3_PRIV_ALGO_AES 2 + +#define SNMP_V3_PRIV_MODE_DECRYPT 0 +#define SNMP_V3_PRIV_MODE_ENCRYPT 1 + +/* + * The following callback functions must be implemented by the application. + * There is a dummy implementation in snmpv3_dummy.c. + */ + +void snmpv3_get_engine_id(const char **id, u8_t *len); +err_t snmpv3_set_engine_id(const char* id, u8_t len); + +u32_t snmpv3_get_engine_boots(void); +void snmpv3_set_engine_boots(u32_t boots); + +u32_t snmpv3_get_engine_time(void); +void snmpv3_reset_engine_time(void); + +err_t snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key); + +/* The following functions are provided by the SNMPv3 agent */ + +void snmpv3_engine_id_changed(void); + +void snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 16-octet buffer */ + +void snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 20-octet buffer */ + +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/sntp.h b/Sming/third-party/lwip2/include/lwip/apps/sntp.h new file mode 100644 index 0000000000..40df9cc590 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/sntp.h @@ -0,0 +1,76 @@ +/** + * @file + * SNTP client API + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_H +#define LWIP_HDR_APPS_SNTP_H + +#include "lwip/apps/sntp_opts.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* SNTP operating modes: default is to poll using unicast. + The mode has to be set before calling sntp_init(). */ +#define SNTP_OPMODE_POLL 0 +#define SNTP_OPMODE_LISTENONLY 1 +void sntp_setoperatingmode(u8_t operating_mode); +u8_t sntp_getoperatingmode(void); + +void sntp_init(void); +void sntp_stop(void); +u8_t sntp_enabled(void); + +void sntp_setserver(u8_t idx, const ip_addr_t *addr); +const ip_addr_t* sntp_getserver(u8_t idx); + +#if SNTP_SERVER_DNS +void sntp_setservername(u8_t idx, char *server); +char *sntp_getservername(u8_t idx); +#endif /* SNTP_SERVER_DNS */ + +#if SNTP_GET_SERVERS_FROM_DHCP +void sntp_servermode_dhcp(int set_servers_from_dhcp); +#else /* SNTP_GET_SERVERS_FROM_DHCP */ +#define sntp_servermode_dhcp(x) +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNTP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/sntp_opts.h b/Sming/third-party/lwip2/include/lwip/apps/sntp_opts.h new file mode 100644 index 0000000000..f3651f90e6 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/sntp_opts.h @@ -0,0 +1,173 @@ +/** + * @file + * SNTP client options list + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_OPTS_H +#define LWIP_HDR_APPS_SNTP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup sntp_opts Options + * @ingroup sntp + * @{ + */ + +/** SNTP macro to change system time in seconds + * Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds instead of this one + * if you need the additional precision. + */ +#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec) +#endif + +/** The maximum number of SNTP servers that can be set */ +#if !defined SNTP_MAX_SERVERS || defined __DOXYGEN__ +#define SNTP_MAX_SERVERS LWIP_DHCP_MAX_NTP_SERVERS +#endif + +/** Set this to 1 to implement the callback function called by dhcp when + * NTP servers are received. */ +#if !defined SNTP_GET_SERVERS_FROM_DHCP || defined __DOXYGEN__ +#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV +#endif + +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ +#define SNTP_SERVER_DNS 0 +#endif + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#if !defined SNTP_DEBUG || defined __DOXYGEN__ +#define SNTP_DEBUG LWIP_DBG_OFF +#endif + +/** SNTP server port */ +#if !defined SNTP_PORT || defined __DOXYGEN__ +#define SNTP_PORT 123 +#endif + +/** Set this to 1 to allow config of SNTP server(s) by DNS name */ +#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ +#define SNTP_SERVER_DNS 0 +#endif + +/** Sanity check: + * Define this to + * - 0 to turn off sanity checks (default; smaller code) + * - >= 1 to check address and port of the response packet to ensure the + * response comes from the server we sent the request to. + * - >= 2 to check returned Originate Timestamp against Transmit Timestamp + * sent to the server (to ensure response to older request). + * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp + * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). + * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each + * greater than or equal to 0 and less than infinity, where infinity is + * currently a cozy number like one second. This check avoids using a + * server whose synchronization source has expired for a very long time. + */ +#if !defined SNTP_CHECK_RESPONSE || defined __DOXYGEN__ +#define SNTP_CHECK_RESPONSE 0 +#endif + +/** According to the RFC, this shall be a random delay + * between 1 and 5 minutes (in milliseconds) to prevent load peaks. + * This can be defined to a random generation function, + * which must return the delay in milliseconds as u32_t. + * Turned off by default. + */ +#if !defined SNTP_STARTUP_DELAY || defined __DOXYGEN__ +#define SNTP_STARTUP_DELAY 0 +#endif + +/** If you want the startup delay to be a function, define this + * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. + */ +#if !defined SNTP_STARTUP_DELAY_FUNC || defined __DOXYGEN__ +#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY +#endif + +/** SNTP receive timeout - in milliseconds + * Also used as retry timeout - this shouldn't be too low. + * Default is 3 seconds. + */ +#if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RECV_TIMEOUT 3000 +#endif + +/** SNTP update delay - in milliseconds + * Default is 1 hour. Must not be beolw 15 seconds by specification (i.e. 15000) + */ +#if !defined SNTP_UPDATE_DELAY || defined __DOXYGEN__ +#define SNTP_UPDATE_DELAY 3600000 +#endif + +/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 + * to send in request and compare in response. + */ +#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) +#endif + +/** Default retry timeout (in milliseconds) if the response + * received is invalid. + * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. + */ +#if !defined SNTP_RETRY_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT +#endif + +/** Maximum retry timeout (in milliseconds). */ +#if !defined SNTP_RETRY_TIMEOUT_MAX || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) +#endif + +/** Increase retry timeout with every retry sent + * Default is on to conform to RFC. + */ +#if !defined SNTP_RETRY_TIMEOUT_EXP || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_EXP 1 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/tftp_opts.h b/Sming/third-party/lwip2/include/lwip/apps/tftp_opts.h new file mode 100644 index 0000000000..6968a803b4 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/tftp_opts.h @@ -0,0 +1,105 @@ +/****************************************************************//** + * + * @file tftp_opts.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) implementation options + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_OPTS_H +#define LWIP_HDR_APPS_TFTP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup tftp_opts Options + * @ingroup tftp + * @{ + */ + +/** + * Enable TFTP debug messages + */ +#if !defined TFTP_DEBUG || defined __DOXYGEN__ +#define TFTP_DEBUG LWIP_DBG_ON +#endif + +/** + * TFTP server port + */ +#if !defined TFTP_PORT || defined __DOXYGEN__ +#define TFTP_PORT 69 +#endif + +/** + * TFTP timeout + */ +#if !defined TFTP_TIMEOUT_MSECS || defined __DOXYGEN__ +#define TFTP_TIMEOUT_MSECS 10000 +#endif + +/** + * Max. number of retries when a file is read from server + */ +#if !defined TFTP_MAX_RETRIES || defined __DOXYGEN__ +#define TFTP_MAX_RETRIES 5 +#endif + +/** + * TFTP timer cyclic interval + */ +#if !defined TFTP_TIMER_MSECS || defined __DOXYGEN__ +#define TFTP_TIMER_MSECS 50 +#endif + +/** + * Max. length of TFTP filename + */ +#if !defined TFTP_MAX_FILENAME_LEN || defined __DOXYGEN__ +#define TFTP_MAX_FILENAME_LEN 20 +#endif + +/** + * Max. length of TFTP mode + */ +#if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__ +#define TFTP_MAX_MODE_LEN 7 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_TFTP_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/apps/tftp_server.h b/Sming/third-party/lwip2/include/lwip/apps/tftp_server.h new file mode 100644 index 0000000000..3fbe701e0a --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/apps/tftp_server.h @@ -0,0 +1,94 @@ +/****************************************************************//** + * + * @file tftp_server.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_SERVER_H +#define LWIP_HDR_APPS_TFTP_SERVER_H + +#include "lwip/apps/tftp_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup tftp + * TFTP context containing callback functions for TFTP transfers + */ +struct tftp_context { + /** + * Open file for read/write. + * @param fname Filename + * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) + * @param write Flag indicating read (0) or write (!= 0) access + * @returns File handle supplied to other functions + */ + void* (*open)(const char* fname, const char* mode, u8_t write); + /** + * Close file handle + * @param handle File handle returned by open() + */ + void (*close)(void* handle); + /** + * Read from file + * @param handle File handle returned by open() + * @param buf Target buffer to copy read data to + * @param bytes Number of bytes to copy to buf + * @returns >= 0: Success; < 0: Error + */ + int (*read)(void* handle, void* buf, int bytes); + /** + * Write to file + * @param handle File handle returned by open() + * @param pbuf PBUF adjusted such that payload pointer points + * to the beginning of write data. In other words, + * TFTP headers are stripped off. + * @returns >= 0: Success; < 0: Error + */ + int (*write)(void* handle, struct pbuf* p); +}; + +err_t tftp_init(const struct tftp_context* ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_TFTP_SERVER_H */ diff --git a/Sming/third-party/lwip2/include/lwip/arch.h b/Sming/third-party/lwip2/include/lwip/arch.h new file mode 100644 index 0000000000..55714e1132 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/arch.h @@ -0,0 +1,319 @@ +/** + * @file + * Support for different processor and compiler architectures + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ARCH_H +#define LWIP_HDR_ARCH_H + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** + * @defgroup compiler_abstraction Compiler/platform abstraction + * @ingroup sys_layer + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/cc.h! + * These options cannot be \#defined in lwipopts.h since they are not options + * of lwIP itself, but options of the lwIP port to your system. + * @{ + */ + +/** Define the byte order of the system. + * Needed for conversion of network data to host byte order. + * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN + */ +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +/** Define random number generator function of your system */ +#ifdef __DOXYGEN__ +#define LWIP_RAND() ((u32_t)rand()) +#endif + +/** Platform specific diagnostic output.\n + * Note the default implementation pulls in printf, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_DIAG +#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) +#include +#include +#endif + +/** Platform specific assertion handling.\n + * Note the default implementation pulls in printf, fflush and abort, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_ASSERT +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) +#include +#include +#endif + +/** Define this to 1 in arch/cc.h of your port if you do not want to + * include stddef.h header to get size_t. You need to typedef size_t + * by yourself in this case. + */ +#ifndef LWIP_NO_STDDEF_H +#define LWIP_NO_STDDEF_H 0 +#endif + +#if !LWIP_NO_STDDEF_H +#include /* for size_t */ +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the stdint.h header. You need to typedef the generic types listed in + * lwip/arch.h yourself in this case (u8_t, u16_t...). + */ +#ifndef LWIP_NO_STDINT_H +#define LWIP_NO_STDINT_H 0 +#endif + +/* Define generic types used in lwIP */ +#if !LWIP_NO_STDINT_H +#include +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef uintptr_t mem_ptr_t; +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the inttypes.h header. You need to define the format strings listed in + * lwip/arch.h yourself in this case (X8_F, U16_F...). + */ +#ifndef LWIP_NO_INTTYPES_H +#define LWIP_NO_INTTYPES_H 0 +#endif + +/* Define (sn)printf formatters for these lwIP types */ +#if !LWIP_NO_INTTYPES_H +#include +#ifndef X8_F +#define X8_F "02" PRIx8 +#endif +#ifndef U16_F +#define U16_F PRIu16 +#endif +#ifndef S16_F +#define S16_F PRId16 +#endif +#ifndef X16_F +#define X16_F PRIx16 +#endif +#ifndef U32_F +#define U32_F PRIu32 +#endif +#ifndef S32_F +#define S32_F PRId32 +#endif +#ifndef X32_F +#define X32_F PRIx32 +#endif +#ifndef SZT_F +#define SZT_F PRIuPTR +#endif +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the limits.h header. You need to define the type limits yourself in this case + * (e.g. INT_MAX). + */ +#ifndef LWIP_NO_LIMITS_H +#define LWIP_NO_LIMITS_H 0 +#endif + +/* Include limits.h? */ +#if !LWIP_NO_LIMITS_H +#include +#endif + +/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ +#ifndef LWIP_CONST_CAST +#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) +#endif + +/** Get rid of alignment cast warnings (GCC -Wcast-align) */ +#ifndef LWIP_ALIGNMENT_CAST +#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, + * e.g. "conversion from 'u8_t' to 'void *' of greater size" + */ +#ifndef LWIP_PTR_NUMERIC_CAST +#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Allocates a memory buffer of specified size that is of sufficient size to align + * its start address using LWIP_MEM_ALIGN. + * You can declare your own version here e.g. to enforce alignment without adding + * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement + * requirements.\n + * e.g. if you use gcc and need 32 bit alignment:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n + * or more portable:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] + */ +#ifndef LWIP_DECLARE_MEMORY_ALIGNED +#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] +#endif + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** Packed structs support. + * Placed BEFORE declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +/** Packed structs support. + * Placed AFTER declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +/** Packed structs support. + * Placed between end of declaration of a packed struct and trailing semicolon.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_STRUCT +#if defined(__GNUC__) || defined(__clang__) +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#else +#define PACK_STRUCT_STRUCT +#endif +#endif /* PACK_STRUCT_STRUCT */ + +/** Packed structs support. + * Wraps u32_t and u16_t members.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + +/** Packed structs support. + * Wraps u8_t members, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_8 +#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_8 */ + +/** Packed structs support. + * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_S +#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_S */ + +/** Packed structs support using \#include files before and after struct to be packed.\n + * The file included BEFORE the struct is "arch/bpstruct.h".\n + * The file included AFTER the struct is "arch/epstruct.h".\n + * This can be used to implement struct packing on MS Visual C compilers, see + * the Win32 port in the lwIP contrib repository for reference. + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifdef __DOXYGEN__ +#define PACK_STRUCT_USE_INCLUDES +#endif + +/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ARCH_H */ diff --git a/Sming/third-party/lwip2/include/lwip/autoip.h b/Sming/third-party/lwip2/include/lwip/autoip.h new file mode 100644 index 0000000000..1d85bccff8 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/autoip.h @@ -0,0 +1,99 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_AUTOIP_H +#define LWIP_HDR_AUTOIP_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +/* #include "lwip/udp.h" */ +#include "lwip/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/** AutoIP state information per netif */ +struct autoip +{ + /** the currently selected, probed, announced or used LL IP-Address */ + ip4_addr_t llipaddr; + /** current AutoIP state machine state */ + u8_t state; + /** sent number of probes or announces, dependent on state */ + u8_t sent_num; + /** ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u16_t ttw; + /** ticks until a conflict can be solved by defending */ + u8_t lastconflict; + /** total number of probed/used Link Local IP-Addresses */ + u8_t tried_llipaddr; +}; + + +void autoip_set_struct(struct netif *netif, struct autoip *autoip); +/** Remove a struct autoip previously set to the netif using autoip_set_struct() */ +#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) +err_t autoip_start(struct netif *netif); +err_t autoip_stop(struct netif *netif); +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); +void autoip_tmr(void); +void autoip_network_changed(struct netif *netif); +u8_t autoip_supplied_address(const struct netif *netif); + +/* for lwIP internal use by ip4.c */ +u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); + +#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_AUTOIP */ + +#endif /* LWIP_HDR_AUTOIP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/debug.h b/Sming/third-party/lwip2/include/lwip/debug.h new file mode 100644 index 0000000000..a142f1cff3 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/debug.h @@ -0,0 +1,167 @@ +/** + * @file + * Debug messages infrastructure + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_DEBUG_H +#define LWIP_HDR_DEBUG_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +/** + * @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values + * @ingroup lwip_opts_debugmsg + * @{ + */ + +/** @name Debug level (LWIP_DBG_MIN_LEVEL) + * @{ + */ +/** Debug level: ALL messages*/ +#define LWIP_DBG_LEVEL_ALL 0x00 +/** Debug level: Warnings. bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_WARNING 0x01 +/** Debug level: Serious. memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 +/** Debug level: Severe */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +/** + * @} + */ + +#define LWIP_DBG_MASK_LEVEL 0x03 +/* compatibility define only */ +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL + +/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U +/** + * @} + */ + +/** @name Debug message types (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup lwip_assertions Assertion handling + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_NOASSERT: Disable LWIP_ASSERT checks: + * To disable assertions define LWIP_NOASSERT in arch/cc.h. + */ +#ifdef __DOXYGEN__ +#define LWIP_NOASSERT +#undef LWIP_NOASSERT +#endif +/** + * @} + */ + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \ + LWIP_PLATFORM_ASSERT(message); }} while(0) +#ifndef LWIP_PLATFORM_ASSERT +#error "If you want to use LWIP_ASSERT, LWIP_PLATFORM_ASSERT(message) needs to be defined in your arch/cc.h" +#endif +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +#ifndef LWIP_ERROR +#ifndef LWIP_NOASSERT +#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_ASSERT(message) +#elif defined LWIP_DEBUG +#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_DIAG((message)) +#else +#define LWIP_PLATFORM_ERROR(message) +#endif + +/* if "expression" isn't true, then print "message" and execute "handler" expression */ +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ERROR(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +/** Enable debug message printing, but only if debug message type is enabled + * AND is of correct type AND is at least LWIP_DBG_LEVEL. + */ +#ifdef __DOXYGEN__ +#define LWIP_DEBUG +#undef LWIP_DEBUG +#endif + +#ifdef LWIP_DEBUG +#ifndef LWIP_PLATFORM_DIAG +#error "If you want to use LWIP_DEBUG, LWIP_PLATFORM_DIAG(message) needs to be defined in your arch/cc.h" +#endif +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* LWIP_HDR_DEBUG_H */ diff --git a/Sming/third-party/lwip2/include/lwip/def.h b/Sming/third-party/lwip2/include/lwip/def.h new file mode 100644 index 0000000000..aaa64c77ab --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/def.h @@ -0,0 +1,142 @@ +/** + * @file + * various utility macros + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_DEF_H +#define LWIP_HDR_DEF_H + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" +#if LWIP_PERF +#include "arch/perf.h" +#else /* LWIP_PERF */ +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ +#endif /* LWIP_PERF */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +/* Get the number of entries in an array ('x' must NOT be a pointer!) */ +#define LWIP_ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) + +/** Create u32_t value from bytes */ +#define LWIP_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff)) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#ifndef lwip_htons +u16_t lwip_htons(u16_t x); +#endif +#define lwip_ntohs(x) lwip_htons(x) + +#ifndef lwip_htonl +u32_t lwip_htonl(u32_t x); +#endif +#define lwip_ntohl(x) lwip_htonl(x) + +/* Provide usual function names as macros for users, but this can be turned off */ +#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0x00ffUL) << 8) | (((x) & 0xff00UL) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0x000000ffUL) << 24) | \ + (((x) & 0x0000ff00UL) << 8) | \ + (((x) & 0x00ff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +/* Functions that are not available as standard implementations. + * In cc.h, you can #define these to implementations available on + * your platform to save some code bytes if you use these functions + * in your application, too. + */ + +#ifndef lwip_itoa +/* This can be #defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform */ +void lwip_itoa(char* result, size_t bufsize, int number); +#endif +#ifndef lwip_strnicmp +/* This can be #defined to strnicmp() or strncasecmp() depending on your platform */ +int lwip_strnicmp(const char* str1, const char* str2, size_t len); +#endif +#ifndef lwip_stricmp +/* This can be #defined to stricmp() or strcasecmp() depending on your platform */ +int lwip_stricmp(const char* str1, const char* str2); +#endif +#ifndef lwip_strnstr +/* This can be #defined to strnstr() depending on your platform */ +char* lwip_strnstr(const char* buffer, const char* token, size_t n); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_DEF_H */ diff --git a/Sming/third-party/lwip2/include/lwip/dhcp.h b/Sming/third-party/lwip2/include/lwip/dhcp.h new file mode 100644 index 0000000000..ac1b18e9f1 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/dhcp.h @@ -0,0 +1,143 @@ +/** + * @file + * DHCP client API + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_DHCP_H +#define LWIP_HDR_DHCP_H + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_BOOT_FILE_LEN 128U + +/* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ +typedef enum { + DHCP_AUTOIP_COOP_STATE_OFF = 0, + DHCP_AUTOIP_COOP_STATE_ON = 1 +} dhcp_autoip_coop_state_enum_t; + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** track PCB allocation state */ + u8_t pcb_allocated; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ + u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ + u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ + u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ + ip4_addr_t offered_ip_addr; + ip4_addr_t offered_sn_mask; + ip4_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 87.5 of lease period) */ +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_t offered_si_addr; + char boot_file_name[DHCP_BOOT_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); +err_t dhcp_start(struct netif *netif); +err_t dhcp_renew(struct netif *netif); +err_t dhcp_release(struct netif *netif); +void dhcp_stop(struct netif *netif); +void dhcp_inform(struct netif *netif); +void dhcp_network_changed(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); +#endif +u8_t dhcp_supplied_address(const struct netif *netif); +/* to be called every minute */ +void dhcp_coarse_tmr(void); +/* to be called every half second */ +void dhcp_fine_tmr(void); + +#if LWIP_DHCP_GET_NTP_SRV +/** This function must exist, in other to add offered NTP servers to + * the NTP (or SNTP) engine. + * See LWIP_DHCP_MAX_NTP_SERVERS */ +extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*LWIP_HDR_DHCP_H*/ diff --git a/Sming/third-party/lwip2/include/lwip/dhcp6.h b/Sming/third-party/lwip2/include/lwip/dhcp6.h new file mode 100644 index 0000000000..455336d37d --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/dhcp6.h @@ -0,0 +1,58 @@ +/** + * @file + * + * IPv6 address autoconfiguration as per RFC 4862. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * IPv6 address autoconfiguration as per RFC 4862. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_IP6_DHCP6_H +#define LWIP_HDR_IP6_DHCP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + + +struct dhcp6 +{ + /*@todo: implement DHCP6*/ +}; + +#endif /* LWIP_IPV6_DHCP6 */ + +#endif /* LWIP_HDR_IP6_DHCP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/dns.h b/Sming/third-party/lwip2/include/lwip/dns.h new file mode 100644 index 0000000000..1453d72341 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/dns.h @@ -0,0 +1,130 @@ +/** + * @file + * DNS API + */ + +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_DNS_H +#define LWIP_HDR_DNS_H + +#include "lwip/opt.h" + +#if LWIP_DNS + +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/* DNS resolve types: */ +#define LWIP_DNS_ADDRTYPE_IPV4 0 +#define LWIP_DNS_ADDRTYPE_IPV6 1 +#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#if LWIP_IPV4 && LWIP_IPV6 +#ifndef LWIP_DNS_ADDRTYPE_DEFAULT +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4_IPV6 +#endif +#elif LWIP_IPV4 +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4 +#else +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV6 +#endif + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#define DNS_LOCAL_HOSTLIST_ELEM(name, addr_init) {name, addr_init, NULL} +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#if LWIP_IPV4 +extern const ip_addr_t dns_mquery_v4group; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +extern const ip_addr_t dns_mquery_v6group; +#endif /* LWIP_IPV6 */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, const ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver); +const ip_addr_t* dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); +err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg, + u8_t dns_addrtype); + + +#if DNS_LOCAL_HOSTLIST +size_t dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg); +err_t dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype); +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* LWIP_HDR_DNS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/err.h b/Sming/third-party/lwip2/include/lwip/err.h new file mode 100644 index 0000000000..84e528d1ed --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/err.h @@ -0,0 +1,119 @@ +/** + * @file + * lwIP Error codes + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERR_H +#define LWIP_HDR_ERR_H + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup infrastructure_errors Error codes + * @ingroup infrastructure + * @{ + */ + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/** Definitions for error constants. */ +typedef enum { +/** No error, everything OK. */ + ERR_OK = 0, +/** Out of memory error. */ + ERR_MEM = -1, +/** Buffer error. */ + ERR_BUF = -2, +/** Timeout. */ + ERR_TIMEOUT = -3, +/** Routing problem. */ + ERR_RTE = -4, +/** Operation in progress */ + ERR_INPROGRESS = -5, +/** Illegal value. */ + ERR_VAL = -6, +/** Operation would block. */ + ERR_WOULDBLOCK = -7, +/** Address in use. */ + ERR_USE = -8, +/** Already connecting. */ + ERR_ALREADY = -9, +/** Conn already established.*/ + ERR_ISCONN = -10, +/** Not connected. */ + ERR_CONN = -11, +/** Low-level netif error */ + ERR_IF = -12, + +/** Connection aborted. */ + ERR_ABRT = -13, +/** Connection reset. */ + ERR_RST = -14, +/** Connection closed. */ + ERR_CLSD = -15, +/** Illegal argument. */ + ERR_ARG = -16 +} err_enum_t; + +#define ERR_IS_FATAL(e) ((e) <= ERR_ABRT) + +/** + * @} + */ + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#if !NO_SYS +int err_to_errno(err_t err); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERR_H */ diff --git a/Sming/third-party/lwip2/include/lwip/errno.h b/Sming/third-party/lwip2/include/lwip/errno.h new file mode 100644 index 0000000000..641cffb09c --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/errno.h @@ -0,0 +1,193 @@ +/** + * @file + * Posix Errno defines + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERRNO_H +#define LWIP_HDR_ERRNO_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +#ifndef errno +extern int errno; +#endif + +#else /* LWIP_PROVIDE_ERRNO */ + +/* Define LWIP_ERRNO_INCLUDE to to include the error defines here */ +#ifdef LWIP_ERRNO_INCLUDE +#include LWIP_ERRNO_INCLUDE +#endif /* LWIP_ERRNO_INCLUDE */ + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERRNO_H */ diff --git a/Sming/third-party/lwip2/include/lwip/etharp.h b/Sming/third-party/lwip2/include/lwip/etharp.h new file mode 100644 index 0000000000..7080a19d05 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/etharp.h @@ -0,0 +1,106 @@ +/** + * @file + * Ethernet output function - handles OUTGOING ethernet level traffic, implements + * ARP resolving. + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHARP_H +#define LWIP_HDR_NETIF_ETHARP_H + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/prot/etharp.h" + +/** 1 seconds period */ +#define ARP_TMR_INTERVAL 1000 + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct etharp_q_entry { + struct etharp_q_entry *next; + struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, no init needed. */ +void etharp_tmr(void); +s8_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, + struct eth_addr **eth_ret, const ip4_addr_t **ip_ret); +u8_t etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret); +err_t etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), netif_ip4_addr(netif)) +void etharp_cleanup_netif(struct netif *netif); + +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr); +err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#endif /* LWIP_IPV4 && LWIP_ARP */ + +void etharp_input(struct pbuf *p, struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#endif /* LWIP_HDR_NETIF_ETHARP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ethip6.h b/Sming/third-party/lwip2/include/lwip/ethip6.h new file mode 100644 index 0000000000..5e88dffd05 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ethip6.h @@ -0,0 +1,68 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ETHIP6_H +#define LWIP_HDR_ETHIP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +err_t ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + +#endif /* LWIP_HDR_ETHIP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/icmp.h b/Sming/third-party/lwip2/include/lwip/icmp.h new file mode 100644 index 0000000000..f5a31fd4c0 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/icmp.h @@ -0,0 +1,110 @@ +/** + * @file + * ICMP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ICMP_H +#define LWIP_HDR_ICMP_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp.h" + +#if LWIP_IPV6 && LWIP_ICMP6 +#include "lwip/icmp6.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP destination unreachable codes */ +enum icmp_dur_type { + /** net unreachable */ + ICMP_DUR_NET = 0, + /** host unreachable */ + ICMP_DUR_HOST = 1, + /** protocol unreachable */ + ICMP_DUR_PROTO = 2, + /** port unreachable */ + ICMP_DUR_PORT = 3, + /** fragmentation needed and DF set */ + ICMP_DUR_FRAG = 4, + /** source route failed */ + ICMP_DUR_SR = 5 +}; + +/** ICMP time exceeded codes */ +enum icmp_te_type { + /** time to live exceeded in transit */ + ICMP_TE_TTL = 0, + /** fragment reassembly time exceeded */ + ICMP_TE_FRAG = 1 +}; + +#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp); +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#endif /* LWIP_IPV4 && LWIP_ICMP */ + +#if LWIP_IPV4 && LWIP_IPV6 +#if LWIP_ICMP && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ + icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ + icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) +#elif LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) do{ if(!(isipv6)) { icmp_dest_unreach(pbuf, ICMP_DUR_PORT);}}while(0) +#elif LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) do{ if(isipv6) { icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT);}}while(0) +#else +#define icmp_port_unreach(isipv6, pbuf) +#endif +#elif LWIP_IPV6 && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) +#elif LWIP_IPV4 && LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) +#else /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) */ +#define icmp_port_unreach(isipv6, pbuf) +#endif /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) LWIP_IPV4*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ICMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/icmp6.h b/Sming/third-party/lwip2/include/lwip/icmp6.h new file mode 100644 index 0000000000..a29dc8c1c2 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/icmp6.h @@ -0,0 +1,70 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_ICMP6_H +#define LWIP_HDR_ICMP6_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +void icmp6_input(struct pbuf *p, struct netif *inp); +void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); +void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); +void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); +void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* LWIP_HDR_ICMP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/igmp.h b/Sming/third-party/lwip2/include/lwip/igmp.h new file mode 100644 index 0000000000..ffd80e680c --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/igmp.h @@ -0,0 +1,115 @@ +/** + * @file + * IGMP API + */ + +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef LWIP_HDR_IGMP_H +#define LWIP_HDR_IGMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* Compatibility defines (don't use for new code) */ +#define IGMP_DEL_MAC_FILTER NETIF_DEL_MAC_FILTER +#define IGMP_ADD_MAC_FILTER NETIF_ADD_MAC_FILTER + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** multicast address */ + ip4_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void); +err_t igmp_start(struct netif *netif); +err_t igmp_stop(struct netif *netif); +void igmp_report_groups(struct netif *netif); +struct igmp_group *igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr); +void igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest); +err_t igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +void igmp_tmr(void); + +/** @ingroup igmp + * Get list head of IGMP groups for netif. + * Note: The allsystems group IP is contained in the list as first entry. + * @see @ref netif_set_igmp_mac_filter() + */ +#define netif_igmp_data(netif) ((struct igmp_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_IGMP */ + +#endif /* LWIP_HDR_IGMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/inet.h b/Sming/third-party/lwip2/include/lwip/inet.h new file mode 100644 index 0000000000..4a34f02653 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/inet.h @@ -0,0 +1,172 @@ +/** + * @file + * This file (together with sockets.h) aims to provide structs and functions from + * - arpa/inet.h + * - netinet/in.h + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_H +#define LWIP_HDR_INET_H + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) +typedef u32_t in_addr_t; +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct in6_addr { + union { + u32_t u32_addr[4]; + u8_t u8_addr[16]; + } un; +#define s6_addr un.u8_addr +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 wildcard address. */ +#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 loopback address. */ +#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} +/** This variable is initialized by the system to contain the wildcard IPv6 address. */ +extern const struct in6_addr in6addr_any; + +/* Definitions of the bits in an (IPv4) Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX +#endif +#if LWIP_IPV6 +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX +#endif +#endif + +#if LWIP_IPV4 + +#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip4_addr_t are an u32_t effectively! */ +#define inet_addr_to_ip4addr_p(target_ip4addr_p, source_inaddr) ((target_ip4addr_p) = (ip4_addr_t*)&((source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) +#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ + (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3];} +/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ +#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) + +/* directly map this to the lwip internal functions */ +#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) +#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) +#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ diff --git a/Sming/third-party/lwip2/include/lwip/inet_chksum.h b/Sming/third-party/lwip2/include/lwip/inet_chksum.h new file mode 100644 index 0000000000..4e23d7f194 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/inet_chksum.h @@ -0,0 +1,105 @@ +/** + * @file + * IP checksum calculation functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_CHKSUM_H +#define LWIP_HDR_INET_CHKSUM_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like lwip_htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +# ifndef LWIP_CHKSUM_COPY +# define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +# ifndef LWIP_CHKSUM_COPY_ALGORITHM +# define LWIP_CHKSUM_COPY_ALGORITHM 1 +# endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +# else /* LWIP_CHKSUM_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +# endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(const void *dataptr, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#if LWIP_IPV4 +u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip4_addr_t *src, const ip4_addr_t *dest); +u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, + u16_t proto_len, u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest); +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip6_addr_t *src, const ip6_addr_t *dest); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest); +#endif /* LWIP_IPV6 */ + + +u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip_addr_t *src, const ip_addr_t *dest); +u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ + diff --git a/Sming/third-party/lwip2/include/lwip/init.h b/Sming/third-party/lwip2/include/lwip/init.h new file mode 100644 index 0000000000..940fa21aff --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/init.h @@ -0,0 +1,100 @@ +/** + * @file + * lwIP initialization API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INIT_H +#define LWIP_HDR_INIT_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup lwip_version Version + * @ingroup lwip + * @{ + */ + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 2 +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 0 +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 2 +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC LWIP_RC_RELEASE + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255 +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ +#define LWIP_RC_DEVELOPMENT 0 + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/* Some helper defines to get a version string */ +#define LWIP_VERSTR2(x) #x +#define LWIP_VERSTR(x) LWIP_VERSTR2(x) +#if LWIP_VERSION_IS_RELEASE +#define LWIP_VERSION_STRING_SUFFIX "" +#elif LWIP_VERSION_IS_DEVELOPMENT +#define LWIP_VERSION_STRING_SUFFIX "d" +#else +#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) +#endif + +/** Provides the version of the stack */ +#define LWIP_VERSION (((u32_t)LWIP_VERSION_MAJOR) << 24 | ((u32_t)LWIP_VERSION_MINOR) << 16 | \ + ((u32_t)LWIP_VERSION_REVISION) << 8 | ((u32_t)LWIP_VERSION_RC)) +/** Provides the version of the stack as string */ +#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX + +/** + * @} + */ + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INIT_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip.h b/Sming/third-party/lwip2/include/lwip/ip.h new file mode 100644 index 0000000000..0673be9b4a --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip.h @@ -0,0 +1,319 @@ +/** + * @file + * IP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_H +#define LWIP_HDR_IP_H + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/ip6.h" +#include "lwip/prot/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#define LWIP_IP_HDRINCL NULL + +/** pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ +#ifndef LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX +#define LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p) LWIP_ASSERT("p->ref == 1", (p)->ref == 1) +#endif + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/** This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX in sockets.h + */ +#define SOF_REUSEADDR 0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE 0x08U /* keep connections alive */ +#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) + +/** Global variables of this module, kept in a struct for efficient access using base+index. */ +struct ip_globals +{ + /** The interface that accepted the packet for the current callback invocation. */ + struct netif *current_netif; + /** The interface that received the packet for the current callback invocation. */ + struct netif *current_input_netif; +#if LWIP_IPV4 + /** Header of the input packet currently being processed. */ + struct ip_hdr *current_ip4_header; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Header of the input IPv6 packet currently being processed. */ + struct ip6_hdr *current_ip6_header; +#endif /* LWIP_IPV6 */ + /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ + u16_t current_ip_header_tot_len; + /** Source IP address of current_header */ + ip_addr_t current_iphdr_src; + /** Destination IP address of current_header */ + ip_addr_t current_iphdr_dest; +}; +extern struct ip_globals ip_data; + + +/** Get the interface that accepted the current packet. + * This may or may not be the receiving netif, depending on your netif/network setup. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (ip_data.current_netif) +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_input_netif() (ip_data.current_input_netif) +/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ +#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) +/** Source IP address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if LWIP_IPV4 && LWIP_IPV6 +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ((const struct ip_hdr*)(ip_data.current_ip4_header)) +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ +#define ip_current_is_v6() (ip6_current_header() != NULL) +/** Source IPv6 address of current_header */ +#define ip6_current_src_addr() (ip_2_ip6(&ip_data.current_iphdr_src)) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (ip_2_ip6(&ip_data.current_iphdr_dest)) +/** Get the transport layer protocol */ +#define ip_current_header_proto() (ip_current_is_v6() ? \ + IP6H_NEXTH(ip6_current_header()) :\ + IPH_PROTO(ip4_current_header())) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((ip_current_is_v6() ? \ + (const u8_t*)ip6_current_header() : (const u8_t*)ip4_current_header()) + ip_current_header_tot_len())) + +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (ip_2_ip4(&ip_data.current_iphdr_src)) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (ip_2_ip4(&ip_data.current_iphdr_dest)) + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ((const struct ip_hdr*)(ip_data.current_ip4_header)) +/** Always returns FALSE when only supporting IPv4 only */ +#define ip_current_is_v6() 0 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IPH_PROTO(ip4_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((const u8_t*)ip4_current_header() + ip_current_header_tot_len())) +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (&ip_data.current_iphdr_dest) + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Always returns TRUE when only supporting IPv6 only */ +#define ip_current_is_v6() 1 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IP6H_NEXTH(ip6_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((const u8_t*)ip6_current_header())) +/** Source IP6 address of current_header */ +#define ip6_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP6 address of current_header */ +#define ip6_current_dest_addr() (&ip_data.current_iphdr_dest) + +#endif /* LWIP_IPV6 */ + +/** Union source address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Union destination address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +/** Gets an IP pcb option (SOF_* flags) */ +#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt)) +/** Sets an IP pcb option (SOF_* flags) */ +#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt)) +/** Resets an IP pcb option (SOF_* flags) */ +#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ip + * Output IP packet, netif is selected by source address + */ +#define ip_output(p, src, dest, ttl, tos, proto) \ + (IP_IS_V6(dest) ? \ + ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ + ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto)) +/** + * @ingroup ip + * Output IP packet to specified interface + */ +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** + * @ingroup ip + * Output IP packet to interface specifying source address + */ +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if_src(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** Output IP packet with addr_hint */ +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + (IP_IS_V6(dest) ? \ + ip6_output_hinted(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, addr_hint) : \ + ip4_output_hinted(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, addr_hint)) +/** + * @ingroup ip + * Get netif for address combination. See \ref ip6_route and \ref ip4_route + */ +#define ip_route(src, dest) \ + (IP_IS_V6(dest) ? \ + ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ + ip4_route_src(ip_2_ip4(dest), ip_2_ip4(src))) +/** + * @ingroup ip + * Get netif for IP. + */ +#define ip_netif_get_local_ip(netif, dest) (IP_IS_V6(dest) ? \ + ip6_netif_get_local_ip(netif, ip_2_ip6(dest)) : \ + ip4_netif_get_local_ip(netif)) +#define ip_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip4_debug_print(p)) + +err_t ip_input(struct pbuf *p, struct netif *inp); + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip4_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + ip4_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_route(src, dest) \ + ip4_route_src(dest, src) +#define ip_netif_get_local_ip(netif, dest) \ + ip4_netif_get_local_ip(netif) +#define ip_debug_print(is_ipv6, p) ip4_debug_print(p) + +#define ip_input ip4_input + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip6_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + ip6_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_route(src, dest) \ + ip6_route(src, dest) +#define ip_netif_get_local_ip(netif, dest) \ + ip6_netif_get_local_ip(netif, dest) +#define ip_debug_print(is_ipv6, p) ip6_debug_print(p) + +#define ip_input ip6_input + +#endif /* LWIP_IPV6 */ + +#define ip_route_get_local_ip(src, dest, netif, ipaddr) do { \ + (netif) = ip_route(src, dest); \ + (ipaddr) = ip_netif_get_local_ip(netif, dest); \ +}while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Sming/third-party/lwip2/include/lwip/ip4.h b/Sming/third-party/lwip2/include/lwip/ip4.h new file mode 100644 index 0000000000..48246ecc25 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip4.h @@ -0,0 +1,111 @@ +/** + * @file + * IPv4 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_H +#define LWIP_HDR_IP4_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/prot/ip4.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +#define LWIP_IPV4_SRC_ROUTING 1 +#else +#define LWIP_IPV4_SRC_ROUTING 0 +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) + +#define ip_init() /* Compatibility define, no init needed. */ +struct netif *ip4_route(const ip4_addr_t *dest); +#if LWIP_IPV4_SRC_ROUTING +struct netif *ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src); +#else /* LWIP_IPV4_SRC_ROUTING */ +#define ip4_route_src(dest, src) ip4_route(dest) +#endif /* LWIP_IPV4_SRC_ROUTING */ +err_t ip4_input(struct pbuf *p, struct netif *inp); +err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto); +err_t ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +#endif /* IP_OPTIONS_SEND */ + +#if LWIP_MULTICAST_TX_OPTIONS +void ip4_set_default_multicast_netif(struct netif* default_multicast_netif); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#define ip4_netif_get_local_ip(netif) (((netif) != NULL) ? netif_ip_addr4(netif) : NULL) + +#if IP_DEBUG +void ip4_debug_print(struct pbuf *p); +#else +#define ip4_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Sming/third-party/lwip2/include/lwip/ip4_addr.h b/Sming/third-party/lwip2/include/lwip/ip4_addr.h new file mode 100644 index 0000000000..51b46b8d4c --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip4_addr.h @@ -0,0 +1,227 @@ +/** + * @file + * IPv4 address API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_ADDR_H +#define LWIP_HDR_IP4_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the aligned version of ip4_addr_t, + used as local variable, on the stack, etc. */ +struct ip4_addr { + u32_t addr; +}; + +/** ip4_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip4_addr_t as well as on ip4_addr_p_t. */ +typedef struct ip4_addr ip4_addr_t; + +/** + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Forward declaration to not include netif.h */ +struct netif; + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) +#endif + +/** Copy IP address - faster than ip4_addr_set: no NULL check */ +#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip4_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for lwip_htonl()) */ +#define ip4_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip4_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Check if an address is in the loopback region */ +#define ip4_addr_isloopback(ipaddr) (((ipaddr)->addr & PP_HTONL(IP_CLASSA_NET)) == PP_HTONL(((u32_t)IP_LOOPBACKNET) << 24)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip4_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + lwip_htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip4_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY) +#define ip4_addr_isany(addr1) ((addr1) == NULL || ip4_addr_isany_val(*(addr1))) + +#define ip4_addr_isbroadcast(addr1, netif) ip4_addr_isbroadcast_u32((addr1)->addr, netif) +u8_t ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif); + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask); + +#define ip4_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip4_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip4_addr_debug_print_parts(debug, a, b, c, d) \ + LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d)) +#define ip4_addr_debug_print(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0)) +#define ip4_addr_debug_print_val(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + ip4_addr1_16(&(ipaddr)), \ + ip4_addr2_16(&(ipaddr)), \ + ip4_addr3_16(&(ipaddr)), \ + ip4_addr4_16(&(ipaddr))) + +/* Get one byte from the 4-byte address */ +#define ip4_addr1(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[0]) +#define ip4_addr2(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[1]) +#define ip4_addr3(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[2]) +#define ip4_addr4(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[3]) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) + +#define IP4ADDR_STRLEN_MAX 16 + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp); +int ip4addr_aton(const char *cp, ip4_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip4addr_ntoa(const ip4_addr_t *addr); +char *ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip4_frag.h b/Sming/third-party/lwip2/include/lwip/ip4_frag.h new file mode 100644 index 0000000000..ed5bf14a31 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip4_frag.h @@ -0,0 +1,100 @@ +/** + * @file + * IP fragmentation/reassembly + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef LWIP_HDR_IP4_FRAG_H +#define LWIP_HDR_IP4_FRAG_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/** IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void); +void ip_reass_tmr(void); +struct pbuf * ip4_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !LWIP_NETIF_TX_SINGLE_PBUF +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP4_FRAG_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip6.h b/Sming/third-party/lwip2/include/lwip/ip6.h new file mode 100644 index 0000000000..099b94fb74 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip6.h @@ -0,0 +1,93 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_H +#define LWIP_HDR_IP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); +const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); +err_t ip6_input(struct pbuf *p, struct netif *inp); +err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth); +err_t ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if LWIP_IPV6_MLD +err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); +#endif /* LWIP_IPV6_MLD */ + +#define ip6_netif_get_local_ip(netif, dest) (((netif) != NULL) ? \ + ip6_select_source_address(netif, dest) : NULL) + +#if IP6_DEBUG +void ip6_debug_print(struct pbuf *p); +#else +#define ip6_debug_print(p) +#endif /* IP6_DEBUG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip6_addr.h b/Sming/third-party/lwip2/include/lwip/ip6_addr.h new file mode 100644 index 0000000000..ee381aeb23 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip6_addr.h @@ -0,0 +1,285 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Structs and macros for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_ADDR_H +#define LWIP_HDR_IP6_ADDR_H + +#include "lwip/opt.h" +#include "def.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** This is the aligned version of ip6_addr_t, + used as local variable, on the stack, etc. */ +struct ip6_addr { + u32_t addr[4]; +}; + +/** IPv6 address */ +typedef struct ip6_addr ip6_addr_t; + +/** Set an IPv6 partial address given by byte-parts */ +#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** Set a full IPv6 address by passing the 4 u32_t indices in network byte order + (use PP_HTONL() for constants) */ +#define IP6_ADDR(ip6addr, idx0, idx1, idx2, idx3) do { \ + (ip6addr)->addr[0] = idx0; \ + (ip6addr)->addr[1] = idx1; \ + (ip6addr)->addr[2] = idx2; \ + (ip6addr)->addr[3] = idx3; } while(0) + +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3])) & 0xffff)) + +/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) +/** Safely copy one IPv6 address to another (src may be NULL) */ +#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) + +/** Set complete address to zero */ +#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = 0;}while(0) + +/** Set address to ipv6 'any' (no need for lwip_htonl()) */ +#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) +/** Set address to ipv6 loopback address */ +#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) +/** Safely copy one IPv6 address to another and change byte order + * from host- to network-order. */ +#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : lwip_htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : lwip_htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : lwip_htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : lwip_htonl((src)->addr[3]);}while(0) + + +/** + * Determine if two IPv6 address are on the same network. + * + * @arg addr1 IPv6 address 1 + * @arg addr2 IPv6 address 2 + * @return !0 if the network identifiers of both address match + */ +#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1])) + +#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) + +#define ip6_get_subnet_id(ip6addr) (lwip_htonl((ip6addr)->addr[2]) & 0x0000ffffUL) + +#define ip6_addr_isany_val(ip6addr) (((ip6addr).addr[0] == 0) && \ + ((ip6addr).addr[1] == 0) && \ + ((ip6addr).addr[2] == 0) && \ + ((ip6addr).addr[3] == 0)) +#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || ip6_addr_isany_val(*(ip6addr))) + +#define ip6_addr_isloopback(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) + +#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) + +#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) + +#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) + +#define ip6_addr_isipv4mappedipv6(ip6addr) (((ip6addr)->addr[0] == 0) && ((ip6addr)->addr[1] == 0) && (((ip6addr)->addr[2]) == PP_HTONL(0x0000FFFFUL))) + +#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) +#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) +#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) +#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) +#define ip6_addr_multicast_scope(ip6addr) ((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xf) +#define IP6_MULTICAST_SCOPE_RESERVED 0x0 +#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 +#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 +#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 +#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 +#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 +#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 +#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IP6_MULTICAST_SCOPE_GLOBAL 0xe +#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf +#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff010000UL)) +#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff020000UL)) +#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff040000UL)) +#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff050000UL)) +#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff080000UL)) +#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff0e0000UL)) + +/* @todo define get/set for well-know multicast addresses, e.g. ff02::1 */ +#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) +#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) + +#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) +#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0) + +#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) + +#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ + (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id));}while(0) + +#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) + +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */ +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */ + +#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */ + +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) + +#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \ + LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \ + a, b, c, d, e, f, g, h)) +#define ip6_addr_debug_print(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) +#define ip6_addr_debug_print_val(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + IP6_ADDR_BLOCK1(&(ipaddr)), \ + IP6_ADDR_BLOCK2(&(ipaddr)), \ + IP6_ADDR_BLOCK3(&(ipaddr)), \ + IP6_ADDR_BLOCK4(&(ipaddr)), \ + IP6_ADDR_BLOCK5(&(ipaddr)), \ + IP6_ADDR_BLOCK6(&(ipaddr)), \ + IP6_ADDR_BLOCK7(&(ipaddr)), \ + IP6_ADDR_BLOCK8(&(ipaddr))) + +#define IP6ADDR_STRLEN_MAX 46 + +int ip6addr_aton(const char *cp, ip6_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip6addr_ntoa(const ip6_addr_t *addr); +char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); + + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_ADDR_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip6_frag.h b/Sming/third-party/lwip2/include/lwip/ip6_frag.h new file mode 100644 index 0000000000..6be274734b --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip6_frag.h @@ -0,0 +1,120 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_FRAG_H +#define LWIP_HDR_IP6_FRAG_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + +/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, this needs to + * be enabled (to not overwrite part of the data). When enabled, the IPv6 header + * is copied instead of referencing it, which gives more room for struct ip6_reass_helper */ +#ifndef IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_COPYHEADER 0 +#endif + +/** The IPv6 reassembly timer interval in milliseconds. */ +#define IP6_REASS_TMR_INTERVAL 1000 + +/* Copy the complete header of the first fragment to struct ip6_reassdata + or just point to its original location in the first pbuf? */ +#if IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_HDRPTR +#define IPV6_FRAG_HDRREF(hdr) (&(hdr)) +#else /* IPV6_FRAG_COPYHEADER */ +#define IPV6_FRAG_HDRPTR * +#define IPV6_FRAG_HDRREF(hdr) (hdr) +#endif /* IPV6_FRAG_COPYHEADER */ + +/** IPv6 reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip6_reassdata { + struct ip6_reassdata *next; + struct pbuf *p; + struct ip6_hdr IPV6_FRAG_HDRPTR iphdr; + u32_t identification; + u16_t datagram_len; + u8_t nexth; + u8_t timer; +}; + +#define ip6_reass_init() /* Compatibility define */ +void ip6_reass_tmr(void); +struct pbuf *ip6_reass(struct pbuf *p); + +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ + +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ + +err_t ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest); + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP6_FRAG_H */ diff --git a/Sming/third-party/lwip2/include/lwip/ip_addr.h b/Sming/third-party/lwip2/include/lwip/ip_addr.h new file mode 100644 index 0000000000..11f65d25bd --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/ip_addr.h @@ -0,0 +1,407 @@ +/** + * @file + * IP address API (common IPv4 and IPv6) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_ADDR_H +#define LWIP_HDR_IP_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include "lwip/ip4_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup ipaddr + * IP address types for use in ip_addr_t.type member. + * @see tcp_new_ip_type(), udp_new_ip_type(), raw_new_ip_type(). + */ +enum lwip_ip_addr_type { + /** IPv4 */ + IPADDR_TYPE_V4 = 0U, + /** IPv6 */ + IPADDR_TYPE_V6 = 6U, + /** IPv4+IPv6 ("dual-stack") */ + IPADDR_TYPE_ANY = 46U +}; + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ipaddr + * A union struct for both IP version's addresses. + * ATTENTION: watch out for its size when adding IPv6 address scope! + */ +typedef struct ip_addr { + union { + ip6_addr_t ip6; + ip4_addr_t ip4; + } u_addr; + /** @ref lwip_ip_addr_type */ + u8_t type; +} ip_addr_t; + +extern const ip_addr_t ip_addr_any_type; + +/** @ingroup ip4addr */ +#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_V4 } +/** @ingroup ip4addr */ +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) +/** @ingroup ip6addr */ +#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 } +/** @ingroup ip6addr */ +#define IPADDR6_INIT_HOST(a, b, c, d) { { { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } } }, IPADDR_TYPE_V6 } + +/** @ingroup ipaddr */ +#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY) +/** @ingroup ipaddr */ +#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_ANY } + +/** @ingroup ip4addr */ +#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4) +/** @ingroup ip6addr */ +#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6) +/** @ingroup ip4addr */ +#define IP_IS_V4(ipaddr) (((ipaddr) == NULL) || IP_IS_V4_VAL(*(ipaddr))) +/** @ingroup ip6addr */ +#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr))) + +#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) +#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0) +#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) + +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr)) +#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) + +/** @ingroup ip6addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) +/** @ingroup ip4addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) + +/** @ingroup ip4addr */ +#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +/** @ingroup ipaddr */ +#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); }}while(0) +/** @ingroup ip6addr */ +#define ip_addr_copy_from_ip6(dest, src) do{ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_copy_from_ip4(dest, src) do{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V4); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_set_ip4_u32(ipaddr, val) do{if(ipaddr){ip4_addr_set_u32(ip_2_ip4(ipaddr), val); \ + IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ip4addr */ +#define ip_addr_get_ip4_u32(ipaddr) (((ipaddr) && IP_IS_V4(ipaddr)) ? \ + ip4_addr_get_u32(ip_2_ip4(ipaddr)) : 0) +/** @ingroup ipaddr */ +#define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, IP_GET_TYPE(src)); if(IP_IS_V6(src)){ \ + ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); }else{ \ + ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_ipaddr(dest, src) ip_addr_set(dest, src) +/** @ingroup ipaddr */ +#define ip_addr_set_zero(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, 0); }while(0) +/** @ingroup ip5addr */ +#define ip_addr_set_zero_ip4(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }while(0) +/** @ingroup ip6addr */ +#define ip_addr_set_zero_ip6(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_any(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_loopback(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_hton(dest, src) do{if(IP_IS_V6(src)){ \ + ip6_addr_set_hton(ip_2_ip6(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_hton(ip_2_ip4(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_get_network(target, host, netmask) do{if(IP_IS_V6(host)){ \ + ip4_addr_set_zero(ip_2_ip4(target)); IP_SET_TYPE(target, IPADDR_TYPE_V6); } else { \ + ip4_addr_get_network(ip_2_ip4(target), ip_2_ip4(host), ip_2_ip4(netmask)); IP_SET_TYPE(target, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_netcmp(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ + 0 : \ + ip4_addr_netcmp(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) +/** @ingroup ipaddr */ +#define ip_addr_cmp(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_cmp(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** @ingroup ipaddr */ +#define ip_addr_isany(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isany(ip_2_ip6(ipaddr)) : \ + ip4_addr_isany(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_isany_val(ipaddr) ((IP_IS_V6_VAL(ipaddr)) ? \ + ip6_addr_isany_val(*ip_2_ip6(&(ipaddr))) : \ + ip4_addr_isany_val(*ip_2_ip4(&(ipaddr)))) +/** @ingroup ipaddr */ +#define ip_addr_isbroadcast(ipaddr, netif) ((IP_IS_V6(ipaddr)) ? \ + 0 : \ + ip4_addr_isbroadcast(ip_2_ip4(ipaddr), netif)) +/** @ingroup ipaddr */ +#define ip_addr_ismulticast(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_ismulticast(ip_2_ip6(ipaddr)) : \ + ip4_addr_ismulticast(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_isloopback(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isloopback(ip_2_ip6(ipaddr)) : \ + ip4_addr_isloopback(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_islinklocal(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_islinklocal(ip_2_ip6(ipaddr)) : \ + ip4_addr_islinklocal(ip_2_ip4(ipaddr))) +#define ip_addr_debug_print(debug, ipaddr) do { if(IP_IS_V6(ipaddr)) { \ + ip6_addr_debug_print(debug, ip_2_ip6(ipaddr)); } else { \ + ip4_addr_debug_print(debug, ip_2_ip4(ipaddr)); }}while(0) +#define ip_addr_debug_print_val(debug, ipaddr) do { if(IP_IS_V6_VAL(ipaddr)) { \ + ip6_addr_debug_print_val(debug, *ip_2_ip6(&(ipaddr))); } else { \ + ip4_addr_debug_print_val(debug, *ip_2_ip4(&(ipaddr))); }}while(0) +/** @ingroup ipaddr */ +#define ipaddr_ntoa(addr) (((addr) == NULL) ? "NULL" : \ + ((IP_IS_V6(addr)) ? ip6addr_ntoa(ip_2_ip6(addr)) : ip4addr_ntoa(ip_2_ip4(addr)))) +/** @ingroup ipaddr */ +#define ipaddr_ntoa_r(addr, buf, buflen) (((addr) == NULL) ? "NULL" : \ + ((IP_IS_V6(addr)) ? ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen) : ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen))) +int ipaddr_aton(const char *cp, ip_addr_t *addr); + +/** @ingroup ipaddr */ +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +/** @ingroup ipaddr */ +#define ip4_2_ipv4_mapped_ipv6(ip6addr, ip4addr) do { \ + (ip6addr)->addr[3] = (ip4addr)->addr; \ + (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[0] = 0; } while(0); + +/** @ingroup ipaddr */ +#define unmap_ipv4_mapped_ipv6(ip4addr, ip6addr) \ + (ip4addr)->addr = (ip6addr)->addr[3]; + +#define IP46_ADDR_ANY(type) (((type) == IPADDR_TYPE_V6)? IP6_ADDR_ANY : IP4_ADDR_ANY) + +#else /* LWIP_IPV4 && LWIP_IPV6 */ + +#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1 + +#if LWIP_IPV4 + +typedef ip4_addr_t ip_addr_t; +#define IPADDR4_INIT(u32val) { u32val } +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) +#define IP_IS_V4_VAL(ipaddr) 1 +#define IP_IS_V6_VAL(ipaddr) 0 +#define IP_IS_V4(ipaddr) 1 +#define IP_IS_V6(ipaddr) 0 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V4 +#define ip_2_ip4(ipaddr) (ipaddr) +#define IP_ADDR4(ipaddr,a,b,c,d) IP4_ADDR(ipaddr,a,b,c,d) + +#define ip_addr_copy(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_copy_from_ip4(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_set_ip4_u32(ipaddr, val) ip4_addr_set_u32(ip_2_ip4(ipaddr), val) +#define ip_addr_get_ip4_u32(ipaddr) ip4_addr_get_u32(ip_2_ip4(ipaddr)) +#define ip_addr_set(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip4(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip4_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip4_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip4_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip4_addr_get_network(target, host, mask) +#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_netcmp(addr1, addr2, mask) +#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2) +#define ip_addr_isany(ipaddr) ip4_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip4_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip4_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip4_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) ip4_addr_isbroadcast(addr, netif) +#define ip_addr_ismulticast(ipaddr) ip4_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip4_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip4_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip4addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip4addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip4addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP4_ADDR_ANY) + +#else /* LWIP_IPV4 */ + +typedef ip6_addr_t ip_addr_t; +#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } } +#define IPADDR6_INIT_HOST(a, b, c, d) { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } } +#define IP_IS_V4_VAL(ipaddr) 0 +#define IP_IS_V6_VAL(ipaddr) 1 +#define IP_IS_V4(ipaddr) 0 +#define IP_IS_V6(ipaddr) 1 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V6 +#define ip_2_ip6(ipaddr) (ipaddr) +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,i3) +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +#define ip_addr_copy(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_copy_from_ip6(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_set(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip6(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip6_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip6_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip6_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip6_addr_set_zero(target) +#define ip_addr_netcmp(addr1, addr2, mask) 0 +#define ip_addr_cmp(addr1, addr2) ip6_addr_cmp(addr1, addr2) +#define ip_addr_isany(ipaddr) ip6_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip6_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip6_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip6_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) 0 +#define ip_addr_ismulticast(ipaddr) ip6_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip6_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip6_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip6addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip6addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip6addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP6_ADDR_ANY) + +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_IPV4 + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IP wildcard. + * Defined to @ref IP4_ADDR_ANY when IPv4 is enabled. + * Defined to @ref IP6_ADDR_ANY in IPv6 only systems. + * Use this if you can handle IPv4 _AND_ IPv6 addresses. + * Use @ref IP4_ADDR_ANY or @ref IP6_ADDR_ANY when the IP + * type matters. + */ +#define IP_ADDR_ANY IP4_ADDR_ANY +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IPv4 wildcard and the broadcast address + */ +#define IP4_ADDR_ANY (&ip_addr_any) +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip4_addr_t + * for the wildcard and the broadcast address + */ +#define IP4_ADDR_ANY4 (ip_2_ip4(&ip_addr_any)) + +/** @ingroup ip4addr */ +#define IP_ADDR_BROADCAST (&ip_addr_broadcast) +/** @ingroup ip4addr */ +#define IP4_ADDR_BROADCAST (ip_2_ip4(&ip_addr_broadcast)) + +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 + +extern const ip_addr_t ip6_addr_any; + +/** + * @ingroup ip6addr + * IP6_ADDR_ANY can be used as a fixed ip_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY (&ip6_addr_any) +/** + * @ingroup ip6addr + * IP6_ADDR_ANY6 can be used as a fixed ip6_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY6 (ip_2_ip6(&ip6_addr_any)) + +#if !LWIP_IPV4 +/** IPv6-only configurations */ +#define IP_ADDR_ANY IP6_ADDR_ANY +#endif /* !LWIP_IPV4 */ + +#endif + +#if LWIP_IPV4 && LWIP_IPV6 +/** @ingroup ipaddr */ +#define IP_ANY_TYPE (&ip_addr_any_type) +#else +#define IP_ANY_TYPE IP_ADDR_ANY +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Sming/third-party/lwip2/include/lwip/mem.h b/Sming/third-party/lwip2/include/lwip/mem.h new file mode 100644 index 0000000000..ff208d25c3 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/mem.h @@ -0,0 +1,82 @@ +/** + * @file + * Heap API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_MEM_H +#define LWIP_HDR_MEM_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include "lwip/arch.h" + +typedef size_t mem_size_t; +#define MEM_SIZE_F SZT_F + +#elif MEM_USE_POOLS + +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F + +#else + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000L +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ +#endif + +void mem_init(void); +void *mem_trim(void *mem, mem_size_t size); +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void mem_free(void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEM_H */ diff --git a/Sming/third-party/lwip2/include/lwip/memp.h b/Sming/third-party/lwip2/include/lwip/memp.h new file mode 100644 index 0000000000..68fcd99145 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/memp.h @@ -0,0 +1,153 @@ +/** + * @file + * Memory pool API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_H +#define LWIP_HDR_MEMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* run once with empty definition to handle all custom includes in lwippools.h */ +#define LWIP_MEMPOOL(name,num,size,desc) +#include "lwip/priv/memp_std.h" + +/** Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, +#include "lwip/priv/memp_std.h" + MEMP_MAX +} memp_t; + +#include "lwip/priv/memp_priv.h" +#include "lwip/stats.h" + +extern const struct memp_desc* const memp_pools[MEMP_MAX]; + +/** + * @ingroup mempool + * Declare prototype for private memory pool if it is used in multiple files + */ +#define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc memp_ ## name + +#if MEMP_MEM_MALLOC + +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size) \ + }; + +#else /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Declare a private memory pool + * Private mempools example: + * .h: only when pool is used in multiple .c files: LWIP_MEMPOOL_PROTOTYPE(my_private_pool); + * .c: + * - in global variables section: LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description") + * - call ONCE before using pool (e.g. in some init() function): LWIP_MEMPOOL_INIT(my_private_pool); + * - allocate: void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool); + * - free: LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem); + * + * To relocate a pool, declare it as extern in cc.h. Example for GCC: + * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_my_private_pool[]; + */ +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ + \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + \ + static struct memp *memp_tab_ ## name; \ + \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size), \ + (num), \ + memp_memory_ ## name ## _base, \ + &memp_tab_ ## name \ + }; + +#endif /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Initialize a private memory pool + */ +#define LWIP_MEMPOOL_INIT(name) memp_init_pool(&memp_ ## name) +/** + * @ingroup mempool + * Allocate from a private memory pool + */ +#define LWIP_MEMPOOL_ALLOC(name) memp_malloc_pool(&memp_ ## name) +/** + * @ingroup mempool + * Free element from a private memory pool + */ +#define LWIP_MEMPOOL_FREE(name, x) memp_free_pool(&memp_ ## name, (x)) + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. + * This has to be defined here as it is required for pool size calculation. */ +struct memp_malloc_helper +{ + memp_t poolnr; +#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) + u16_t size; +#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type); +#endif +void memp_free(memp_t type, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/mld6.h b/Sming/third-party/lwip2/include/lwip/mld6.h new file mode 100644 index 0000000000..7fa0797f27 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/mld6.h @@ -0,0 +1,99 @@ +/** + * @file + * + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_MLD6_H +#define LWIP_HDR_MLD6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** MLD group */ +struct mld_group { + /** next link */ + struct mld_group *next; + /** multicast address */ + ip6_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ + +err_t mld6_stop(struct netif *netif); +void mld6_report_groups(struct netif *netif); +void mld6_tmr(void); +struct mld_group *mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr); +void mld6_input(struct pbuf *p, struct netif *inp); +err_t mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); + +/** @ingroup mld6 + * Get list head of MLD6 groups for netif. + * Note: The allnodes group IP is NOT in the list, since it must always + * be received for correct IPv6 operation. + * @see @ref netif_set_mld_mac_filter() + */ +#define netif_mld6_data(netif) ((struct mld_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ + +#endif /* LWIP_HDR_MLD6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/nd6.h b/Sming/third-party/lwip2/include/lwip/nd6.h new file mode 100644 index 0000000000..8204fa4cce --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/nd6.h @@ -0,0 +1,84 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_H +#define LWIP_HDR_ND6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period */ +#define ND6_TMR_INTERVAL 1000 + +struct pbuf; +struct netif; + +void nd6_tmr(void); +void nd6_input(struct pbuf *p, struct netif *inp); +void nd6_clear_destination_cache(void); +struct netif *nd6_find_route(const ip6_addr_t *ip6addr); +err_t nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp); +u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); +#if LWIP_ND6_TCP_REACHABILITY_HINTS +void nd6_reachability_hint(const ip6_addr_t *ip6addr); +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ +void nd6_cleanup_netif(struct netif *netif); +#if LWIP_IPV6_MLD +void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state); +#endif /* LWIP_IPV6_MLD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/netbuf.h b/Sming/third-party/lwip2/include/lwip/netbuf.h new file mode 100644 index 0000000000..e6865f80f9 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/netbuf.h @@ -0,0 +1,118 @@ +/** + * @file + * netbuf API (for netconn API) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETBUF_H +#define LWIP_HDR_NETBUF_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +/** "Network buffer" - contains data and addressing info */ +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void); +void netbuf_delete (struct netbuf *buf); +void * netbuf_alloc (struct netbuf *buf, u16_t size); +void netbuf_free (struct netbuf *buf); +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size); +void netbuf_chain (struct netbuf *head, struct netbuf *tail); + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len); +s8_t netbuf_next (struct netbuf *buf); +void netbuf_first (struct netbuf *buf); + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(&((buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(&((buf)->toaddr), destaddr) +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#else /* LWIP_CHECKSUM_ON_COPY */ +#define netbuf_destport(buf) ((buf)->toport_chksum) +#endif /* LWIP_CHECKSUM_ON_COPY */ +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETBUF_H */ diff --git a/Sming/third-party/lwip2/include/lwip/netdb.h b/Sming/third-party/lwip2/include/lwip/netdb.h new file mode 100644 index 0000000000..d3d15dfac5 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/netdb.h @@ -0,0 +1,150 @@ +/** + * @file + * NETDB API (sockets) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_NETDB_H +#define LWIP_HDR_NETDB_H + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/arch.h" +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_FLAGS +#define LWIP_DNS_API_DEFINE_FLAGS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 +#define EAI_FAMILY 204 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DEFINE_FLAGS +/* input flags for struct addrinfo */ +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_NUMERICSERV 0x08 +#define AI_V4MAPPED 0x10 +#define AI_ALL 0x20 +#define AI_ADDRCONFIG 0x40 +#endif /* LWIP_DNS_API_DEFINE_FLAGS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessible error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +/** @ingroup netdbapi */ +#define gethostbyname(name) lwip_gethostbyname(name) +/** @ingroup netdbapi */ +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +/** @ingroup netdbapi */ +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +/** @ingroup netdbapi */ +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETDB_H */ diff --git a/Sming/third-party/lwip2/include/lwip/netif.h b/Sming/third-party/lwip2/include/lwip/netif.h new file mode 100644 index 0000000000..67a2d24de8 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/netif.h @@ -0,0 +1,474 @@ +/** + * @file + * netif API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_H +#define LWIP_HDR_NETIF_H + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** Must be the maximum of all used hardware address lengths + across all types of interfaces in use. + This does not have to be changed, normally. */ +#ifndef NETIF_MAX_HWADDR_LEN +#define NETIF_MAX_HWADDR_LEN 6U +#endif + +/** + * @defgroup netif_flags Flags + * @ingroup netif + * @{ + */ + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It must be set by the startup code before this netif can be used + * (also for dhcp/autoip). + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x04U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x08U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x10U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x20U +/** If set, the netif has MLD6 capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_MLD6 0x40U + +/** + * @} + */ + +enum lwip_internal_netif_client_data_index +{ +#if LWIP_DHCP + LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, +#endif +#if LWIP_AUTOIP + LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, +#endif +#if LWIP_IGMP + LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, +#endif +#if LWIP_IPV6_MLD + LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, +#endif + LWIP_NETIF_CLIENT_DATA_INDEX_MAX +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_CHECKSUM_GEN_IP 0x0001 +#define NETIF_CHECKSUM_GEN_UDP 0x0002 +#define NETIF_CHECKSUM_GEN_TCP 0x0004 +#define NETIF_CHECKSUM_GEN_ICMP 0x0008 +#define NETIF_CHECKSUM_GEN_ICMP6 0x0010 +#define NETIF_CHECKSUM_CHECK_IP 0x0100 +#define NETIF_CHECKSUM_CHECK_UDP 0x0200 +#define NETIF_CHECKSUM_CHECK_TCP 0x0400 +#define NETIF_CHECKSUM_CHECK_ICMP 0x0800 +#define NETIF_CHECKSUM_CHECK_ICMP6 0x1000 +#define NETIF_CHECKSUM_ENABLE_ALL 0xFFFF +#define NETIF_CHECKSUM_DISABLE_ALL 0x0000 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +struct netif; + +/** MAC Filter Actions, these are passed to a netif's igmp_mac_filter or + * mld_mac_filter callback function. */ +enum netif_mac_filter_action { + /** Delete a filter entry */ + NETIF_DEL_MAC_FILTER = 0, + /** Add a filter entry */ + NETIF_ADD_MAC_FILTER = 1 +}; + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV4 +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 +/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'ethip6_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IPv6 address to which the packet shall be sent + */ +typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, + const ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ + +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +#if LWIP_IPV4 && LWIP_IGMP +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + const ip4_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** Function prototype for netif mld_mac_filter functions */ +typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, + const ip6_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if LWIP_DHCP || LWIP_AUTOIP || LWIP_IGMP || LWIP_IPV6_MLD || (LWIP_NUM_NETIF_CLIENT_DATA > 0) +u8_t netif_alloc_client_data_id(void); +/** @ingroup netif_cd + * Set client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_set_client_data(netif, id, data) netif_get_client_data(netif, id) = (data) +/** @ingroup netif_cd + * Get client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_get_client_data(netif, id) (netif)->client_data[(id)] +#endif /* LWIP_DHCP || LWIP_AUTOIP || (LWIP_NUM_NETIF_CLIENT_DATA > 0) */ + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { + /** pointer to next in linked list */ + struct netif *next; + +#if LWIP_IPV4 + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Array of IPv6 addresses for this netif. */ + ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; + /** The state of each IPv6 address (Tentative, Preferred, etc). + * @see ip6_addr.h */ + u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; +#endif /* LWIP_IPV6 */ + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. */ + netif_input_fn input; +#if LWIP_IPV4 + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually etharp_output() */ + netif_output_fn output; +#endif /* LWIP_IPV4 */ + /** This function is called by ethernet_output() when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. */ + netif_linkoutput_fn linkoutput; +#if LWIP_IPV6 + /** This function is called by the IPv6 module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually ethip6_output() */ + netif_output_ip6_fn output_ip6; +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK + /** This function is called when the netif has been removed */ + netif_status_callback_fn remove_callback; +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. */ + void *state; +#ifdef netif_get_client_data + void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; +#endif +#if LWIP_IPV6_AUTOCONFIG + /** is this netif enabled for IPv6 autoconfiguration */ + u8_t ip6_autoconfig_enabled; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /** Number of Router Solicitation messages that remain to be sent. */ + u8_t rs_count; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + const char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ +#if LWIP_CHECKSUM_CTRL_PER_NETIF + u16_t chksum_flags; +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ + /** maximum transfer unit (in bytes) */ + u16_t mtu; + /** number of bytes used in hwaddr */ + u8_t hwaddr_len; + /** link level hardware address of this interface */ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** flags (@see @ref netif_flags) */ + u8_t flags; + /** descriptive abbreviation */ + char name[2]; + /** number of this interface */ + u8_t num; +#if MIB2_STATS + /** link type (from "snmp_ifType" enum from snmp_mib2.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + struct stats_mib2_netif_ctrs mib2_counters; +#endif /* MIB2_STATS */ +#if LWIP_IPV4 && LWIP_IGMP + /** This function could be called to add or delete an entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /** This function could be called to add or delete an entry in the IPv6 multicast + filter table of the ethernet MAC. */ + netif_mld_mac_filter_fn mld_mac_filter; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. */ + struct pbuf *loop_first; + struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ + (netif)->chksum_flags = chksumflags; } while(0) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void); + +struct netif *netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input); +#if LWIP_IPV4 +void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, + const ip4_addr_t *gw); +#endif /* LWIP_IPV4 */ +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(const char *name); + +void netif_set_default(struct netif *netif); + +#if LWIP_IPV4 +void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); +void netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask); +void netif_set_gw(struct netif *netif, const ip4_addr_t *gw); +/** @ingroup netif_ip4 */ +#define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) +/** @ingroup netif_ip4 */ +#define netif_ip4_netmask(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->netmask))) +/** @ingroup netif_ip4 */ +#define netif_ip4_gw(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->gw))) +/** @ingroup netif_ip4 */ +#define netif_ip_addr4(netif) ((const ip_addr_t*)&((netif)->ip_addr)) +/** @ingroup netif_ip4 */ +#define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask)) +/** @ingroup netif_ip4 */ +#define netif_ip_gw4(netif) ((const ip_addr_t*)&((netif)->gw)) +#endif /* LWIP_IPV4 */ + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +/** @ingroup netif + * Ask if an interface is up + */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +/** @ingroup netif */ +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +/** @ingroup netif */ +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +/** @ingroup netif */ +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** @ingroup netif */ +#define netif_set_mld_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->mld_mac_filter = function; }}while(0) +#define netif_get_mld_mac_filter(netif) (((netif) != NULL) ? ((netif)->mld_mac_filter) : NULL) +#define netif_mld_mac_filter(netif, addr, action) do { if((netif) && (netif)->mld_mac_filter) { (netif)->mld_mac_filter((netif), (addr), (action)); }}while(0) +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +err_t netif_input(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV6 +/** @ingroup netif_ip6 */ +#define netif_ip_addr6(netif, i) ((const ip_addr_t*)(&((netif)->ip6_addr[i]))) +/** @ingroup netif_ip6 */ +#define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) +void netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6); +void netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3); +#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) +void netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state); +s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr); +void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit); +err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx); +#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0) +#endif /* LWIP_IPV6 */ + +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint)) +#else /* LWIP_NETIF_HWADDRHINT */ +#define NETIF_SET_HWADDRHINT(netif, hint) +#endif /* LWIP_NETIF_HWADDRHINT */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_H */ diff --git a/Sming/third-party/lwip2/include/lwip/netifapi.h b/Sming/third-party/lwip2/include/lwip/netifapi.h new file mode 100644 index 0000000000..8bd2b4f76f --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/netifapi.h @@ -0,0 +1,140 @@ +/** + * @file + * netif API (to be used from non-TCPIP threads) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_NETIFAPI_H +#define LWIP_HDR_NETIFAPI_H + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MPU_COMPATIBLE +#define NETIFAPI_IPADDR_DEF(type, m) type m +#else /* LWIP_MPU_COMPATIBLE */ +#define NETIFAPI_IPADDR_DEF(type, m) const type * m +#endif /* LWIP_MPU_COMPATIBLE */ + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg { + struct tcpip_api_call_data call; + struct netif *netif; + union { + struct { +#if LWIP_IPV4 + NETIFAPI_IPADDR_DEF(ip4_addr_t, ipaddr); + NETIFAPI_IPADDR_DEF(ip4_addr_t, netmask); + NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); +#endif /* LWIP_IPV4 */ + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + } msg; +}; + + +/* API for application */ +err_t netifapi_netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input); + +#if LWIP_IPV4 +err_t netifapi_netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, const ip4_addr_t *gw); +#endif /* LWIP_IPV4*/ + +err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +/** @ingroup netifapi_netif */ +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL) + +/** + * @defgroup netifapi_dhcp4 DHCPv4 + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) + +/** + * @defgroup netifapi_autoip AUTOIP + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_autoip */ +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +/** @ingroup netifapi_autoip */ +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* LWIP_HDR_NETIFAPI_H */ diff --git a/Sming/third-party/lwip2/include/lwip/opt.h b/Sming/third-party/lwip2/include/lwip/opt.h new file mode 100644 index 0000000000..fd459af144 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/opt.h @@ -0,0 +1,2876 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - + * without this, doxygen does not see the actual #define + */ + +#if !defined LWIP_HDR_OPT_H +#define LWIP_HDR_OPT_H + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/** + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts + */ + + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ +#define NO_SYS 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif + +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 1 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 0 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 + */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 16 +#endif + +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#if !defined LWIP_ARP || defined __DOXYGEN__ +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 10 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 0 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 3 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF 0 +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#if !defined IP_FORWARD || defined __DOXYGEN__ +#define IP_FORWARD 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ +#define IP_REASSEMBLY 1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#if !defined IP_FRAG || defined __DOXYGEN__ +#define IP_FRAG 1 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL (IP_DEFAULT_TTL) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ +#define LWIP_DHCP 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has + * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and + * netif drivers might not set this flag, the default is off. If enabled, + * netif_set_link_up() must be called to continue dhcp starting. + */ +#if !defined LWIP_DHCP_CHECK_LINK_UP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#endif + +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 0 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DHCP servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ +#define LWIP_AUTOIP 0 +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- Multicast/IGMP options ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ +#define LWIP_IGMP 0 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS (LWIP_IGMP && LWIP_UDP) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#if !defined LWIP_DNS || defined __DOXYGEN__ +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#if !defined LWIP_UDP || defined __DOXYGEN__ +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF (2 * TCP_MSS) +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 0u +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif. + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF LWIP_NETIF_LOOPBACK +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 1 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 1 +#endif + +/* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete + * successfully, as required by POSIX. Default is POSIX-compliant. + */ +#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ +#define LWIP_SOCKET_SET_ERRNO 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} + */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#endif + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to #include in files that provide hooks. + * Declare your hook function prototypes in there, you may also #include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(dest, src): + * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * - called from etharp_output() (IPv4) + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Returns the IPv4 address of the gateway to handle the specified destination + * IPv4 address. If NULL is returned, the netif's default gateway is used. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * - called from ip6_input() (IPv6) + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * - called from ip6_route() (IPv6) + * - src: sourc IPv6 address + * - dest: destination IPv6 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * - called from nd6_get_next_hop_entry() (IPv6) + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Returns the IPv6 address of the next hop to handle the specified destination + * IPv6 address. If NULL is returned, a NDP-discovered router is used instead. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * - called from ethernet_input() if VLAN support is enabled + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature: s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * - called from memp_free() when a memp pool was empty and an item is now available + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Return ERR_OK if packet is accepted, any error code otherwise. + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_OFF +#endif +/** + * @} + */ + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + +#endif /* LWIP_HDR_OPT_H */ diff --git a/Sming/third-party/lwip2/include/lwip/pbuf.h b/Sming/third-party/lwip2/include/lwip/pbuf.h new file mode 100644 index 0000000000..90610461ea --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/pbuf.h @@ -0,0 +1,263 @@ +/** + * @file + * pbuf API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_PBUF_H +#define LWIP_HDR_PBUF_H + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** LWIP_SUPPORT_CUSTOM_PBUF==1: Custom pbufs behave much like their pbuf type + * but they are allocated by external code (initialised by calling + * pbuf_alloced_custom()) and when pbuf_free gives up their last reference, they + * are freed by calling pbuf_custom->custom_free_function(). + * Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG, unless required by external driver/application code. */ +#ifndef LWIP_SUPPORT_CUSTOM_PBUF +#define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) +#endif + +/* @todo: We need a mechanism to prevent wasting memory in every pbuf + (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ + +#define PBUF_TRANSPORT_HLEN 20 +#if LWIP_IPV6 +#define PBUF_IP_HLEN 40 +#else +#define PBUF_IP_HLEN 20 +#endif + +/** + * @ingroup pbuf + * Enumeration of pbuf layers + */ +typedef enum { + /** Includes spare room for transport layer header, e.g. UDP header. + * Use this if you intend to pass the pbuf to functions like udp_send(). + */ + PBUF_TRANSPORT, + /** Includes spare room for IP header. + * Use this if you intend to pass the pbuf to functions like raw_send(). + */ + PBUF_IP, + /** Includes spare room for link layer header (ethernet header). + * Use this if you intend to pass the pbuf to functions like ethernet_output(). + * @see PBUF_LINK_HLEN + */ + PBUF_LINK, + /** Includes spare room for additional encapsulation header before ethernet + * headers (e.g. 802.11). + * Use this if you intend to pass the pbuf to functions like netif->linkoutput(). + * @see PBUF_LINK_ENCAPSULATION_HLEN + */ + PBUF_RAW_TX, + /** Use this for input packets in a netif driver when calling netif->input() + * in the most common case - ethernet-layer netif driver. */ + PBUF_RAW +} pbuf_layer; + +/** + * @ingroup pbuf + * Enumeration of pbuf types + */ +typedef enum { + /** pbuf data is stored in RAM, used for TX mostly, struct pbuf and its payload + are allocated in one piece of contiguous memory (so the first payload byte + can be calculated from struct pbuf). + pbuf_alloc() allocates PBUF_RAM pbufs as unchained pbufs (although that might + change in future versions). + This should be used for all OUTGOING packets (TX).*/ + PBUF_RAM, + /** pbuf data is stored in ROM, i.e. struct pbuf and its payload are located in + totally different memory areas. Since it points to ROM, payload does not + have to be copied when queued for transmission. */ + PBUF_ROM, + /** pbuf comes from the pbuf pool. Much like PBUF_ROM but payload might change + so it has to be duplicated when queued before transmitting, depending on + who has a 'ref' to it. */ + PBUF_REF, + /** pbuf payload refers to RAM. This one comes from a pool and should be used + for RX. Payload can be chained (scatter-gather RX) but like PBUF_RAM, struct + pbuf and its payload are allocated in one piece of contiguous memory (so + the first payload byte can be calculated from struct pbuf). + Don't use this for TX, if the pool becomes empty e.g. because of TCP queuing, + you are unable to receive TCP acks! */ + PBUF_POOL +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free calls pbuf_custom->custom_free_function() + when the last reference is released (plus custom PBUF_RAM cannot be trimmed) */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U +/** indicates this pbuf was received as link-level broadcast */ +#define PBUF_FLAG_LLBCAST 0x08U +/** indicates this pbuf was received as link-level multicast */ +#define PBUF_FLAG_LLMCAST 0x10U +/** indicates this pbuf includes a TCP FIN flag */ +#define PBUF_FLAG_TCP_FIN 0x20U + +/** Main packet buffer struct */ +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** pbuf_type as u8_t instead of enum to save space */ + u8_t /*pbuf_type*/ type; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; +}; + + +/** Helper struct for const-correctness only. + * The only meaning of this one is to provide a const payload pointer + * for PBUF_ROM type. + */ +struct pbuf_rom { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + const void *payload; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ +#ifndef PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_FREE_OOSEQ 1 +#endif /* PBUF_POOL_FREE_OOSEQ */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ +extern volatile u8_t pbuf_free_ooseq_pending; +void pbuf_free_ooseq(void); +/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level to check if ooseq pbufs need to be + freed! */ +#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ + /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ + ooseq queued pbufs now */ \ + pbuf_free_ooseq(); }}while(0) +#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */ + /* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */ + #define PBUF_CHECK_FREE_OOSEQ() +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len); +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size); +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +u8_t pbuf_header_force(struct pbuf *p, s16_t header_size); +void pbuf_ref(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u16_t pbuf_clen(const struct pbuf *p); +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from); +u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset); +struct pbuf *pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE +void pbuf_split_64k(struct pbuf *p, struct pbuf **rest); +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + +u8_t pbuf_get_at(const struct pbuf* p, u16_t offset); +int pbuf_try_get_at(const struct pbuf* p, u16_t offset); +void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data); +u16_t pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n); +u16_t pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); +u16_t pbuf_strstr(const struct pbuf* p, const char* substr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PBUF_H */ diff --git a/Sming/third-party/lwip2/include/lwip/priv/api_msg.h b/Sming/third-party/lwip2/include/lwip/priv/api_msg.h new file mode 100644 index 0000000000..f12b8b7d4f --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/api_msg.h @@ -0,0 +1,216 @@ +/** + * @file + * netconn API lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_MSG_H +#define LWIP_HDR_API_MSG_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/arch.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MPU_COMPATIBLE +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_MSG_M_DEF_SEM(m) *m +#else +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif +#else /* LWIP_MPU_COMPATIBLE */ +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif /* LWIP_MPU_COMPATIBLE */ + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for lwip_netconn_do_send */ + struct netbuf *b; + /** used for lwip_netconn_do_newconn */ + struct { + u8_t proto; + } n; + /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ + struct { + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; + } bc; + /** used for lwip_netconn_do_getaddr */ + struct { + ip_addr_t API_MSG_M_DEF(ipaddr); + u16_t API_MSG_M_DEF(port); + u8_t local; + } ad; + /** used for lwip_netconn_do_write */ + struct { + const void *dataptr; + size_t len; + u8_t apiflags; +#if LWIP_SO_SNDTIMEO + u32_t time_started; +#endif /* LWIP_SO_SNDTIMEO */ + } w; + /** used for lwip_netconn_do_recv */ + struct { + u32_t len; + } r; +#if LWIP_TCP + /** used for lwip_netconn_do_close (/shutdown) */ + struct { + u8_t shut; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + u32_t time_started; +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + u8_t polls_left; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + } sd; +#endif /* LWIP_TCP */ +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) + /** used for lwip_netconn_do_join_leave_group */ + struct { + API_MSG_M_DEF_C(ip_addr_t, multiaddr); + API_MSG_M_DEF_C(ip_addr_t, netif_addr); + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +#if LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t* op_completed_sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +}; + +#if LWIP_NETCONN_SEM_PER_THREAD +#define LWIP_API_MSG_SEM(msg) ((msg)->op_completed_sem) +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define LWIP_API_MSG_SEM(msg) (&(msg)->conn->op_completed) +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + +#if LWIP_DNS +/** As lwip_netconn_do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ +#if LWIP_MPU_COMPATIBLE + char name[DNS_MAX_NAME_LENGTH]; +#else /* LWIP_MPU_COMPATIBLE */ + const char *name; +#endif /* LWIP_MPU_COMPATIBLE */ + /** The resolved address is stored here */ + ip_addr_t API_MSG_M_DEF(addr); +#if LWIP_IPV4 && LWIP_IPV6 + /** Type of resolve call */ + u8_t dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t API_MSG_M_DEF_SEM(sem); + /** Errors are given back here */ + err_t API_MSG_M_DEF(err); +}; +#endif /* LWIP_DNS */ + +#if LWIP_TCP +extern u8_t netconn_aborted; +#endif /* LWIP_TCP */ + +void lwip_netconn_do_newconn (void *m); +void lwip_netconn_do_delconn (void *m); +void lwip_netconn_do_bind (void *m); +void lwip_netconn_do_connect (void *m); +void lwip_netconn_do_disconnect (void *m); +void lwip_netconn_do_listen (void *m); +void lwip_netconn_do_send (void *m); +void lwip_netconn_do_recv (void *m); +#if TCP_LISTEN_BACKLOG +void lwip_netconn_do_accepted (void *m); +#endif /* TCP_LISTEN_BACKLOG */ +void lwip_netconn_do_write (void *m); +void lwip_netconn_do_getaddr (void *m); +void lwip_netconn_do_close (void *m); +void lwip_netconn_do_shutdown (void *m); +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +void lwip_netconn_do_join_leave_group(void *m); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +void lwip_netconn_do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_API_MSG_H */ diff --git a/Sming/third-party/lwip2/include/lwip/priv/memp_priv.h b/Sming/third-party/lwip2/include/lwip/priv/memp_priv.h new file mode 100644 index 0000000000..f246061dad --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/memp_priv.h @@ -0,0 +1,183 @@ +/** + * @file + * memory pools lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_PRIV_H +#define LWIP_HDR_MEMP_PRIV_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/mem.h" + +#if MEMP_OVERFLOW_CHECK +/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning + * and at the end of each element, initialize them as 0xcd and check + * them later. */ +/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, + * every single element in each pool is checked! + * This is VERY SLOW but also very helpful. */ +/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in + * lwipopts.h to change the amount reserved for checking. */ +#ifndef MEMP_SANITY_REGION_BEFORE +#define MEMP_SANITY_REGION_BEFORE 16 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#if MEMP_SANITY_REGION_BEFORE > 0 +#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) +#else +#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#ifndef MEMP_SANITY_REGION_AFTER +#define MEMP_SANITY_REGION_AFTER 16 +#endif /* MEMP_SANITY_REGION_AFTER*/ +#if MEMP_SANITY_REGION_AFTER > 0 +#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) +#else +#define MEMP_SANITY_REGION_AFTER_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_AFTER*/ + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE 0 +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + +#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK +struct memp { + struct memp *next; +#if MEMP_OVERFLOW_CHECK + const char *file; + int line; +#endif /* MEMP_OVERFLOW_CHECK */ +}; +#endif /* !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK */ + +#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/priv/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/priv/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS */ + +/** Memory pool descriptor */ +struct memp_desc { +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY + /** Textual description */ + const char *desc; +#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */ +#if MEMP_STATS + /** Statistics */ + struct stats_mem *stats; +#endif + + /** Element size */ + u16_t size; + +#if !MEMP_MEM_MALLOC + /** Number of elements */ + u16_t num; + + /** Base address */ + u8_t *base; + + /** First free element of each pool. Elements form a linked list. */ + struct memp **tab; +#endif /* MEMP_MEM_MALLOC */ +}; + +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY +#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc), +#else +#define DECLARE_LWIP_MEMPOOL_DESC(desc) +#endif + +#if MEMP_STATS +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) static struct stats_mem name; +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) &name, +#else +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) +#endif + +void memp_init_pool(const struct memp_desc *desc); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_pool_fn(const struct memp_desc* desc, const char* file, const int line); +#define memp_malloc_pool(d) memp_malloc_pool_fn((d), __FILE__, __LINE__) +#else +void *memp_malloc_pool(const struct memp_desc *desc); +#endif +void memp_free_pool(const struct memp_desc* desc, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/Sming/third-party/lwip2/include/lwip/priv/memp_std.h b/Sming/third-party/lwip2/include/lwip/priv/memp_std.h new file mode 100644 index 0000000000..ce9fd50031 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/memp_std.h @@ -0,0 +1,146 @@ +/** + * @file + * lwIP internal memory pools (do not use in application code) + * This file is deliberately included multiple times: once with empty + * definition of LWIP_MEMPOOL() to handle all includes and multiple times + * to build up various lists of mem pools. + */ + +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))), "MALLOC_"#size) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB") +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB") +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB") +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG") +#endif /* LWIP_TCP */ + +#if LWIP_IPV4 && IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") +#endif /* LWIP_IPV4 && IP_REASSEMBLY */ +#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG) +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") +#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */ + +#if LWIP_NETCONN || LWIP_SOCKET +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL(API_MSG, MEMP_NUM_API_MSG, sizeof(struct api_msg), "API_MSG") +#if LWIP_DNS +LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg), "DNS_API_MSG") +#endif +#if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKING +LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") +#endif +#if LWIP_NETIF_API +LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") +#endif +#endif /* LWIP_MPU_COMPATIBLE */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") +#endif /* LWIP_IGMP */ + +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") +#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ + +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#if LWIP_IPV6 && LWIP_ND6_QUEUEING +LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") +#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ + +#if LWIP_IPV6 && LWIP_IPV6_REASS +LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM") +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL") + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/Sming/third-party/lwip2/include/lwip/priv/nd6_priv.h b/Sming/third-party/lwip2/include/lwip/priv/nd6_priv.h new file mode 100644 index 0000000000..4bda0b793a --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/nd6_priv.h @@ -0,0 +1,144 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_PRIV_H +#define LWIP_HDR_ND6_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ND6_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct nd6_q_entry { + struct nd6_q_entry *next; + struct pbuf *p; +}; +#endif /* LWIP_ND6_QUEUEING */ + +/** Struct for tables. */ +struct nd6_neighbor_cache_entry { + ip6_addr_t next_hop_address; + struct netif *netif; + u8_t lladdr[NETIF_MAX_HWADDR_LEN]; + /*u32_t pmtu;*/ +#if LWIP_ND6_QUEUEING + /** Pointer to queue of pending outgoing packets on this entry. */ + struct nd6_q_entry *q; +#else /* LWIP_ND6_QUEUEING */ + /** Pointer to a single pending outgoing packet on this entry. */ + struct pbuf *q; +#endif /* LWIP_ND6_QUEUEING */ + u8_t state; + u8_t isrouter; + union { + u32_t reachable_time; /* in ms since value may originate from network packet */ + u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */ + u32_t probes_sent; + u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */ + } counter; +}; + +struct nd6_destination_cache_entry { + ip6_addr_t destination_addr; + ip6_addr_t next_hop_addr; + u16_t pmtu; + u32_t age; +}; + +struct nd6_prefix_list_entry { + ip6_addr_t prefix; + struct netif *netif; + u32_t invalidation_timer; /* in ms since value may originate from network packet */ +#if LWIP_IPV6_AUTOCONFIG + u8_t flags; +#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 +#endif /* LWIP_IPV6_AUTOCONFIG */ +}; + +struct nd6_router_list_entry { + struct nd6_neighbor_cache_entry *neighbor_entry; + u32_t invalidation_timer; /* in ms since value may originate from network packet */ + u8_t flags; +}; + +enum nd6_neighbor_cache_entry_state { + ND6_NO_ENTRY = 0, + ND6_INCOMPLETE, + ND6_REACHABLE, + ND6_STALE, + ND6_DELAY, + ND6_PROBE +}; + +/* Router tables. */ +/* @todo make these static? and entries accessible through API? */ +extern struct nd6_neighbor_cache_entry neighbor_cache[]; +extern struct nd6_destination_cache_entry destination_cache[]; +extern struct nd6_prefix_list_entry prefix_list[]; +extern struct nd6_router_list_entry default_router_list[]; + +/* Default values, can be updated by a RA message. */ +extern u32_t reachable_time; +extern u32_t retrans_timer; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_PRIV_H */ diff --git a/Sming/third-party/lwip2/include/lwip/priv/tcp_priv.h b/Sming/third-party/lwip2/include/lwip/priv/tcp_priv.h new file mode 100644 index 0000000000..73e8967e47 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/tcp_priv.h @@ -0,0 +1,507 @@ +/** + * @file + * TCP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_PRIV_H +#define LWIP_HDR_TCP_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/tcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +void tcp_init (void); /* Initialize this module. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + +/* Call this from a netif driver (watch out for threading issues!) that has + returned a memory error on transmit and now has free buffers to send more. + This iterates all active pcbs that had an error and tries to call + tcp_output, so use this with care as it might slow down the system. */ +void tcp_txnow (void); + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +err_t tcp_send_empty_ack(struct tcp_pcb *pcb); +void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); +void tcp_rexmit_fast (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); +err_t tcp_process_refused_data(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) || \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +#define TCP_TCPLEN(seg) ((seg)->len + (((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0) ? 1U : 0U)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was successfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) ret = lwip_tcp_event(arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) do { if ((pcb)->state != SYN_RCVD) { \ + ret = lwip_tcp_event((pcb)->callback_arg, (pcb), LWIP_EVENT_POLL, NULL, 0, ERR_OK); \ + } else { \ + ret = ERR_ARG; } } while(0) +#define TCP_EVENT_ERR(last_state,errf,arg,err) do { if (last_state != SYN_RCVD) { \ + lwip_tcp_event((arg), NULL, LWIP_EVENT_ERR, NULL, 0, (err)); } } while(0) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) \ + do { \ + if((lpcb)->accept != NULL) \ + (ret) = (lpcb)->accept((arg),(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(last_state,errf,arg,err) \ + do { \ + LWIP_UNUSED_ARG(last_state); \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segments on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversize only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ +#define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_EOL 0 +#define LWIP_TCP_OPT_NOP 1 +#define LWIP_TCP_OPT_MSS 2 +#define LWIP_TCP_OPT_WS 3 +#define LWIP_TCP_OPT_TS 8 + +#define LWIP_TCP_OPT_LEN_MSS 4 +#if LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_OPT_LEN_TS 10 +#define LWIP_TCP_OPT_LEN_TS_OUT 12 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_TS_OUT 0 +#endif +#if LWIP_WND_SCALE +#define LWIP_TCP_OPT_LEN_WS 3 +#define LWIP_TCP_OPT_LEN_WS_OUT 4 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_WS_OUT 0 +#endif + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? LWIP_TCP_OPT_LEN_MSS : 0) + \ + (flags & TF_SEG_OPTS_TS ? LWIP_TCP_OPT_LEN_TS_OUT : 0) + \ + (flags & TF_SEG_OPTS_WND_SCALE ? LWIP_TCP_OPT_LEN_WS_OUT : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(mss) lwip_htonl(0x02040000 | ((mss) & 0xFFFF)) + +#if LWIP_WND_SCALE +#define TCPWNDSIZE_F U32_F +#define TCPWND_MAX 0xFFFFFFFFU +#define TCPWND_CHECK16(x) LWIP_ASSERT("window size > 0xFFFF", (x) <= 0xFFFF) +#define TCPWND_MIN16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#else /* LWIP_WND_SCALE */ +#define TCPWNDSIZE_F U16_F +#define TCPWND_MAX 0xFFFFU +#define TCPWND_CHECK16(x) +#define TCPWND_MIN16(x) x +#endif /* LWIP_WND_SCALE */ + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; +extern u8_t tcp_active_pcbs_changed; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 +#define NUM_TCP_PCB_LISTS 4 +extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for (tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for (tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + struct tcp_pcb *tcp_tmp_pcb; \ + for (tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + +#define TCP_REG_ACTIVE(npcb) \ + do { \ + TCP_REG(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_RMV_ACTIVE(npcb) \ + do { \ + TCP_RMV(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_PCB_REMOVE_ACTIVE(pcb) \ + do { \ + tcp_pcb_remove(&tcp_active_pcbs, pcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +void tcp_segs_free(struct tcp_seg *seg); +void tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb); +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(struct tcp_pcb *pcb); + +err_t tcp_keepalive(struct tcp_pcb *pcb); +err_t tcp_zero_window_probe(struct tcp_pcb *pcb); +void tcp_trigger_input_pcb_close(void); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest +#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING + , const ip_addr_t *src +#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ + ); +#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING +#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest, src) +#else /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ +#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest) +#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void); + +void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_PRIV_H */ diff --git a/Sming/third-party/lwip2/include/lwip/priv/tcpip_priv.h b/Sming/third-party/lwip2/include/lwip/priv/tcpip_priv.h new file mode 100644 index 0000000000..630efb1402 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/priv/tcpip_priv.h @@ -0,0 +1,160 @@ +/** + * @file + * TCPIP API internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_PRIV_H +#define LWIP_HDR_TCPIP_PRIV_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pbuf; +struct netif; + +#if LWIP_MPU_COMPATIBLE +#define API_VAR_REF(name) (*(name)) +#define API_VAR_DECLARE(type, name) type * name +#define API_VAR_ALLOC(type, pool, name, errorval) do { \ + name = (type *)memp_malloc(pool); \ + if (name == NULL) { \ + return errorval; \ + } \ + } while(0) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) do { \ + name = (type *)LWIP_MEMPOOL_ALLOC(pool); \ + if (name == NULL) { \ + return errorval; \ + } \ + } while(0) +#define API_VAR_FREE(pool, name) memp_free(pool, name) +#define API_VAR_FREE_POOL(pool, name) LWIP_MEMPOOL_FREE(pool, name) +#define API_EXPR_REF(expr) (&(expr)) +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_EXPR_REF_SEM(expr) (expr) +#else +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#endif +#define API_EXPR_DEREF(expr) expr +#define API_MSG_M_DEF(m) m +#define API_MSG_M_DEF_C(t, m) t m +#else /* LWIP_MPU_COMPATIBLE */ +#define API_VAR_REF(name) name +#define API_VAR_DECLARE(type, name) type name +#define API_VAR_ALLOC(type, pool, name, errorval) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) +#define API_VAR_FREE(pool, name) +#define API_VAR_FREE_POOL(pool, name) +#define API_EXPR_REF(expr) expr +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#define API_EXPR_DEREF(expr) (*(expr)) +#define API_MSG_M_DEF(m) *m +#define API_MSG_M_DEF_C(t, m) const t * m +#endif /* LWIP_MPU_COMPATIBLE */ + +err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem); + +struct tcpip_api_call_data +{ +#if !LWIP_TCPIP_CORE_LOCKING + err_t err; +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +#else /* !LWIP_TCPIP_CORE_LOCKING */ + u8_t dummy; /* avoid empty struct :-( */ +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +}; +typedef err_t (*tcpip_api_call_fn)(struct tcpip_api_call_data* call); +err_t tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call); + +enum tcpip_msg_type { + TCPIP_MSG_API, + TCPIP_MSG_API_CALL, + TCPIP_MSG_INPKT, +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + TCPIP_MSG_CALLBACK, + TCPIP_MSG_CALLBACK_STATIC +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + union { + struct { + tcpip_callback_fn function; + void* msg; + } api_msg; + struct { + tcpip_api_call_fn function; + struct tcpip_api_call_data *arg; + sys_sem_t *sem; + } api_call; + struct { + struct pbuf *p; + struct netif *netif; + netif_input_fn input_fn; + } inp; + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_PRIV_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/autoip.h b/Sming/third-party/lwip2/include/lwip/prot/autoip.h new file mode 100644 index 0000000000..fd3af8a9fc --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/autoip.h @@ -0,0 +1,78 @@ +/** + * @file + * AutoIP protocol definitions + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_PROT_AUTOIP_H +#define LWIP_HDR_PROT_AUTOIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* 169.254.0.0 */ +#define AUTOIP_NET 0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +typedef enum { + AUTOIP_STATE_OFF = 0, + AUTOIP_STATE_PROBING = 1, + AUTOIP_STATE_ANNOUNCING = 2, + AUTOIP_STATE_BOUND = 3 +} autoip_state_enum_t; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_AUTOIP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/dhcp.h b/Sming/third-party/lwip2/include/lwip/prot/dhcp.h new file mode 100644 index 0000000000..112953cb8b --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/dhcp.h @@ -0,0 +1,183 @@ +/** + * @file + * DHCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_PROT_DHCP_H +#define LWIP_HDR_PROT_DHCP_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + + + /* DHCP message item offsets and length */ +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_OFS 44U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_OFS 108U +#define DHCP_FILE_LEN 128U +#define DHCP_MSG_LEN 236U +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4U) /* 4 byte: cookie */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FLD_8(u8_t op); + PACK_STRUCT_FLD_8(u8_t htype); + PACK_STRUCT_FLD_8(u8_t hlen); + PACK_STRUCT_FLD_8(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FLD_S(ip4_addr_p_t ciaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t yiaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t siaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t giaddr); + PACK_STRUCT_FLD_8(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FLD_8(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FLD_8(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FLD_8(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +/* DHCP client states */ +typedef enum { + DHCP_STATE_OFF = 0, + DHCP_STATE_REQUESTING = 1, + DHCP_STATE_INIT = 2, + DHCP_STATE_REBOOTING = 3, + DHCP_STATE_REBINDING = 4, + DHCP_STATE_RENEWING = 5, + DHCP_STATE_SELECTING = 6, + DHCP_STATE_INFORMING = 7, + DHCP_STATE_CHECKING = 8, + DHCP_STATE_PERMANENT = 9, /* not yet implemented */ + DHCP_STATE_BOUND = 10, + DHCP_STATE_RELEASING = 11, /* not yet implemented */ + DHCP_STATE_BACKING_OFF = 12 +} dhcp_state_enum_t; + +/* DHCP op codes */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ +#define DHCP_HTYPE_ETH 1 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/* BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_NTP 42 +#define DHCP_OPTION_END 255 + +/* DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/* possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + + +#ifdef __cplusplus +} +#endif + +#endif /*LWIP_HDR_PROT_DHCP_H*/ diff --git a/Sming/third-party/lwip2/include/lwip/prot/dns.h b/Sming/third-party/lwip2/include/lwip/prot/dns.h new file mode 100644 index 0000000000..94782d6e9c --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/dns.h @@ -0,0 +1,140 @@ +/** + * @file + * DNS - host name to IP address resolver. + */ + +/* + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + * + * security fixes and more by Simon Goldschmidt + * + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_PROT_DNS_H +#define LWIP_HDR_PROT_DNS_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS server port address */ +#ifndef DNS_SERVER_PORT +#define DNS_SERVER_PORT 53 +#endif + +/* DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_AAAA 28 /* IPv6 address */ +#define DNS_RRTYPE_SRV 33 /* service location */ +#define DNS_RRTYPE_ANY 255 /* any type */ + +/* DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_ANY 255 /* any class */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +#define DNS_HDR_GET_OPCODE(hdr) ((((hdr)->flags1) >> 3) & 0xF) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS message header */ +struct dns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FLD_8(u8_t flags1); + PACK_STRUCT_FLD_8(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_HDR 12 + + +/* Multicast DNS definitions */ + +/** UDP port for multicast DNS queries */ +#ifndef DNS_MQUERY_PORT +#define DNS_MQUERY_PORT 5353 +#endif + +/* IPv4 group for multicast DNS queries: 224.0.0.251 */ +#ifndef DNS_MQUERY_IPV4_GROUP_INIT +#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251) +#endif + +/* IPv6 group for multicast DNS queries: FF02::FB */ +#ifndef DNS_MQUERY_IPV6_GROUP_INIT +#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_DNS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/etharp.h b/Sming/third-party/lwip2/include/lwip/prot/etharp.h new file mode 100644 index 0000000000..ec78305b82 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/etharp.h @@ -0,0 +1,91 @@ +/** + * @file + * ARP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHARP_H +#define LWIP_HDR_PROT_ETHARP_H + +#include "lwip/arch.h" +#include "lwip/prot/ethernet.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN ETH_HWADDR_LEN +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message, see RFC 826 ("Packet format") */ +struct etharp_hdr { + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FLD_8(u8_t hwlen); + PACK_STRUCT_FLD_8(u8_t protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FLD_S(struct eth_addr shwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr2 sipaddr); + PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETHARP_HDR 28 + +/* ARP hwtype values */ +enum etharp_hwtype { + HWTYPE_ETHERNET = 1 + /* others not used */ +}; + +/* ARP message types (opcodes) */ +enum etharp_opcode { + ARP_REQUEST = 1, + ARP_REPLY = 2 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHARP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/ethernet.h b/Sming/third-party/lwip2/include/lwip/prot/ethernet.h new file mode 100644 index 0000000000..e4baa29dc4 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/ethernet.h @@ -0,0 +1,170 @@ +/** + * @file + * Ethernet protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHERNET_H +#define LWIP_HDR_PROT_ETHERNET_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETH_HWADDR_LEN +#ifdef ETHARP_HWADDR_LEN +#define ETH_HWADDR_LEN ETHARP_HWADDR_LEN /* compatibility mode */ +#else +#define ETH_HWADDR_LEN 6 +#endif +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** Ethernet header */ +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FLD_8(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FLD_S(struct eth_addr dest); + PACK_STRUCT_FLD_S(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ +struct eth_vlan_hdr { + PACK_STRUCT_FIELD(u16_t prio_vid); + PACK_STRUCT_FIELD(u16_t tpid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (lwip_htons((vlan_hdr)->prio_vid) & 0xFFF) + +/** + * @ingroup ethernet + * A list of often ethtypes (although lwIP does not use all of them): */ +enum eth_type { + /** Internet protocol v4 */ + ETHTYPE_IP = 0x0800U, + /** Address resolution protocol */ + ETHTYPE_ARP = 0x0806U, + /** Wake on lan */ + ETHTYPE_WOL = 0x0842U, + /** RARP */ + ETHTYPE_RARP = 0x8035U, + /** Virtual local area network */ + ETHTYPE_VLAN = 0x8100U, + /** Internet protocol v6 */ + ETHTYPE_IPV6 = 0x86DDU, + /** PPP Over Ethernet Discovery Stage */ + ETHTYPE_PPPOEDISC = 0x8863U, + /** PPP Over Ethernet Session Stage */ + ETHTYPE_PPPOE = 0x8864U, + /** Jumbo Frames */ + ETHTYPE_JUMBO = 0x8870U, + /** Process field network */ + ETHTYPE_PROFINET = 0x8892U, + /** Ethernet for control automation technology */ + ETHTYPE_ETHERCAT = 0x88A4U, + /** Link layer discovery protocol */ + ETHTYPE_LLDP = 0x88CCU, + /** Serial real-time communication system */ + ETHTYPE_SERCOS = 0x88CDU, + /** Media redundancy protocol */ + ETHTYPE_MRP = 0x88E3U, + /** Precision time protocol */ + ETHTYPE_PTP = 0x88F7U, + /** Q-in-Q, 802.1ad */ + ETHTYPE_QINQ = 0x9100U +}; + +/** The 24-bit IANA IPv4-multicast OUI is 01-00-5e: */ +#define LL_IP4_MULTICAST_ADDR_0 0x01 +#define LL_IP4_MULTICAST_ADDR_1 0x00 +#define LL_IP4_MULTICAST_ADDR_2 0x5e + +/** IPv6 multicast uses this prefix */ +#define LL_IP6_MULTICAST_ADDR_0 0x33 +#define LL_IP6_MULTICAST_ADDR_1 0x33 + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables + * or known to be 32-bit aligned within the protocol header. */ +#ifndef ETHADDR32_COPY +#define ETHADDR32_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) +#endif + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local + * variables and known to be 16-bit aligned within the protocol header. */ +#ifndef ETHADDR16_COPY +#define ETHADDR16_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) +#endif + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHERNET_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/icmp.h b/Sming/third-party/lwip2/include/lwip/prot/icmp.h new file mode 100644 index 0000000000..7d19385c72 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/icmp.h @@ -0,0 +1,91 @@ +/** + * @file + * ICMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP_H +#define LWIP_HDR_PROT_ICMP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ +#define ICMP_AM 17 /* address mask request */ +#define ICMP_AMR 18 /* address mask reply */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is split to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Compatibility defines, old versions used to combine type and code to an u16_t */ +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/icmp6.h b/Sming/third-party/lwip2/include/lwip/prot/icmp6.h new file mode 100644 index 0000000000..3461120421 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/icmp6.h @@ -0,0 +1,170 @@ +/** + * @file + * ICMP6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP6_H +#define LWIP_HDR_PROT_ICMP6_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP type */ +enum icmp6_type { + /** Destination unreachable */ + ICMP6_TYPE_DUR = 1, + /** Packet too big */ + ICMP6_TYPE_PTB = 2, + /** Time exceeded */ + ICMP6_TYPE_TE = 3, + /** Parameter problem */ + ICMP6_TYPE_PP = 4, + /** Private experimentation */ + ICMP6_TYPE_PE1 = 100, + /** Private experimentation */ + ICMP6_TYPE_PE2 = 101, + /** Reserved for expansion of error messages */ + ICMP6_TYPE_RSV_ERR = 127, + + /** Echo request */ + ICMP6_TYPE_EREQ = 128, + /** Echo reply */ + ICMP6_TYPE_EREP = 129, + /** Multicast listener query */ + ICMP6_TYPE_MLQ = 130, + /** Multicast listener report */ + ICMP6_TYPE_MLR = 131, + /** Multicast listener done */ + ICMP6_TYPE_MLD = 132, + /** Router solicitation */ + ICMP6_TYPE_RS = 133, + /** Router advertisement */ + ICMP6_TYPE_RA = 134, + /** Neighbor solicitation */ + ICMP6_TYPE_NS = 135, + /** Neighbor advertisement */ + ICMP6_TYPE_NA = 136, + /** Redirect */ + ICMP6_TYPE_RD = 137, + /** Multicast router advertisement */ + ICMP6_TYPE_MRA = 151, + /** Multicast router solicitation */ + ICMP6_TYPE_MRS = 152, + /** Multicast router termination */ + ICMP6_TYPE_MRT = 153, + /** Private experimentation */ + ICMP6_TYPE_PE3 = 200, + /** Private experimentation */ + ICMP6_TYPE_PE4 = 201, + /** Reserved for expansion of informational messages */ + ICMP6_TYPE_RSV_INF = 255 +}; + +/** ICMP destination unreachable codes */ +enum icmp6_dur_code { + /** No route to destination */ + ICMP6_DUR_NO_ROUTE = 0, + /** Communication with destination administratively prohibited */ + ICMP6_DUR_PROHIBITED = 1, + /** Beyond scope of source address */ + ICMP6_DUR_SCOPE = 2, + /** Address unreachable */ + ICMP6_DUR_ADDRESS = 3, + /** Port unreachable */ + ICMP6_DUR_PORT = 4, + /** Source address failed ingress/egress policy */ + ICMP6_DUR_POLICY = 5, + /** Reject route to destination */ + ICMP6_DUR_REJECT_ROUTE = 6 +}; + +/** ICMP time exceeded codes */ +enum icmp6_te_code { + /** Hop limit exceeded in transit */ + ICMP6_TE_HL = 0, + /** Fragment reassembly time exceeded */ + ICMP6_TE_FRAG = 1 +}; + +/** ICMP parameter code */ +enum icmp6_pp_code { + /** Erroneous header field encountered */ + ICMP6_PP_FIELD = 0, + /** Unrecognized next header type encountered */ + ICMP6_PP_HEADER = 1, + /** Unrecognized IPv6 option encountered */ + ICMP6_PP_OPTION = 2 +}; + +/** This is the standard ICMP6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t data); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** This is the ICMP6 header adapted for echo req/resp. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/igmp.h b/Sming/third-party/lwip2/include/lwip/prot/igmp.h new file mode 100644 index 0000000000..d60cb31ee7 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/igmp.h @@ -0,0 +1,90 @@ +/** + * @file + * IGMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IGMP_H +#define LWIP_HDR_PROT_IGMP_H + +#include "lwip/arch.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * IGMP constants + */ +#define IGMP_TTL 1 +#define IGMP_MINLEN 8 +#define ROUTER_ALERT 0x9404U +#define ROUTER_ALERTLEN 4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY 0x11 /* Membership query */ +#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ + +/* Group membership states */ +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 + +/** + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FLD_8(u8_t igmp_msgtype); + PACK_STRUCT_FLD_8(u8_t igmp_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_checksum); + PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IGMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/ip.h b/Sming/third-party/lwip2/include/lwip/prot/ip.h new file mode 100644 index 0000000000..bbfae36752 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/ip.h @@ -0,0 +1,51 @@ +/** + * @file + * IP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP_H +#define LWIP_HDR_PROT_IP_H + +#include "lwip/arch.h" + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/** This operates on a void* by loading the first byte */ +#define IP_HDR_GET_VERSION(ptr) ((*(u8_t*)(ptr)) >> 4) + +#endif /* LWIP_HDR_PROT_IP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/ip4.h b/Sming/third-party/lwip2/include/lwip/prot/ip4.h new file mode 100644 index 0000000000..bd442c6892 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/ip4.h @@ -0,0 +1,127 @@ +/** + * @file + * IPv4 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP4_H +#define LWIP_HDR_PROT_IP4_H + +#include "lwip/arch.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the packed version of ip4_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +typedef struct ip4_addr_packed ip4_addr_p_t; + +/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ +#define IP_HLEN 20 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/* The IPv4 header */ +struct ip_hdr { + /* version / header length */ + PACK_STRUCT_FLD_8(u8_t _v_hl); + /* type of service */ + PACK_STRUCT_FLD_8(u8_t _tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000U /* reserved fragment flag */ +#define IP_DF 0x4000U /* don't fragment flag */ +#define IP_MF 0x2000U /* more fragments flag */ +#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FLD_8(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FLD_8(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip4_addr_p_t src); + PACK_STRUCT_FLD_S(ip4_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Macros to get struct ip_hdr fields: */ +#define IPH_V(hdr) ((hdr)->_v_hl >> 4) +#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) +#define IPH_TOS(hdr) ((hdr)->_tos) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +/* Macros to set struct ip_hdr fields: */ +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) +#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP4_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/ip6.h b/Sming/third-party/lwip2/include/lwip/prot/ip6.h new file mode 100644 index 0000000000..6e1e2632bf --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/ip6.h @@ -0,0 +1,169 @@ +/** + * @file + * IPv6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP6_H +#define LWIP_HDR_PROT_IP6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the packed version of ip6_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_addr_packed { + PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +typedef struct ip6_addr_packed ip6_addr_p_t; + +#define IP6_HLEN 40 + +#define IP6_NEXTH_HOPBYHOP 0 +#define IP6_NEXTH_TCP 6 +#define IP6_NEXTH_UDP 17 +#define IP6_NEXTH_ENCAPS 41 +#define IP6_NEXTH_ROUTING 43 +#define IP6_NEXTH_FRAGMENT 44 +#define IP6_NEXTH_ICMP6 58 +#define IP6_NEXTH_NONE 59 +#define IP6_NEXTH_DESTOPTS 60 +#define IP6_NEXTH_UDPLITE 136 + +/** The IPv6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hdr { + /** version / traffic class / flow label */ + PACK_STRUCT_FIELD(u32_t _v_tc_fl); + /** payload length */ + PACK_STRUCT_FIELD(u16_t _plen); + /** next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /** hop limit */ + PACK_STRUCT_FLD_8(u8_t _hoplim); + /** source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip6_addr_p_t src); + PACK_STRUCT_FLD_S(ip6_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Hop-by-hop router alert option. */ +#define IP6_HBH_HLEN 8 +#define IP6_PAD1_OPTION 0 +#define IP6_PADN_ALERT_OPTION 1 +#define IP6_ROUTER_ALERT_OPTION 5 +#define IP6_ROUTER_ALERT_VALUE_MLD 0 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hbh_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* header length */ + PACK_STRUCT_FLD_8(u8_t _hlen); + /* router alert option type */ + PACK_STRUCT_FLD_8(u8_t _ra_opt_type); + /* router alert option data len */ + PACK_STRUCT_FLD_8(u8_t _ra_opt_dlen); + /* router alert option data */ + PACK_STRUCT_FIELD(u16_t _ra_opt_data); + /* PadN option type */ + PACK_STRUCT_FLD_8(u8_t _padn_opt_type); + /* PadN option data len */ + PACK_STRUCT_FLD_8(u8_t _padn_opt_dlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Fragment header. */ +#define IP6_FRAG_HLEN 8 +#define IP6_FRAG_OFFSET_MASK 0xfff8 +#define IP6_FRAG_MORE_FLAG 0x0001 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_frag_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FLD_8(u8_t reserved); + /* fragment offset */ + PACK_STRUCT_FIELD(u16_t _fragment_offset); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u32_t _identification); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) + +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/mld6.h b/Sming/third-party/lwip2/include/lwip/prot/mld6.h new file mode 100644 index 0000000000..be3a006af2 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/mld6.h @@ -0,0 +1,70 @@ +/** + * @file + * MLD6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_MLD6_H +#define LWIP_HDR_PROT_MLD6_H + +#include "lwip/arch.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Multicast listener report/query/done message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mld_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t max_resp_delay); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t multicast_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_MLD6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/nd6.h b/Sming/third-party/lwip2/include/lwip/prot/nd6.h new file mode 100644 index 0000000000..2d4903d15b --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/nd6.h @@ -0,0 +1,277 @@ +/** + * @file + * ND6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ND6_H +#define LWIP_HDR_PROT_ND6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Neighbor solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ns_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Neighbor advertisement message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct na_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FLD_8(u8_t reserved[3]); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define ND6_FLAG_ROUTER (0x80) +#define ND6_FLAG_SOLICITED (0x40) +#define ND6_FLAG_OVERRIDE (0x20) + +/** Router solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rs_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Router advertisement message header. */ +#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) +#define ND6_RA_FLAG_OTHER_CONFIG (0x40) +#define ND6_RA_FLAG_HOME_AGENT (0x20) +#define ND6_RA_PREFERENCE_MASK (0x18) +#define ND6_RA_PREFERENCE_HIGH (0x08) +#define ND6_RA_PREFERENCE_MEDIUM (0x00) +#define ND6_RA_PREFERENCE_LOW (0x18) +#define ND6_RA_PREFERENCE_DISABLED (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ra_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t current_hop_limit); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u16_t router_lifetime); + PACK_STRUCT_FIELD(u32_t reachable_time); + PACK_STRUCT_FIELD(u32_t retrans_timer); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirect message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirect_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + PACK_STRUCT_FLD_S(ip6_addr_p_t destination_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Link-layer address option. */ +#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) +#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct lladdr_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t addr[NETIF_MAX_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Prefix information option. */ +#define ND6_OPTION_TYPE_PREFIX_INFO (0x03) +#define ND6_PREFIX_FLAG_ON_LINK (0x80) +#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) +#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) +#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct prefix_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u32_t valid_lifetime); + PACK_STRUCT_FIELD(u32_t preferred_lifetime); + PACK_STRUCT_FLD_8(u8_t reserved2[3]); + PACK_STRUCT_FLD_8(u8_t site_prefix_length); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirected header option. */ +#define ND6_OPTION_TYPE_REDIR_HDR (0x04) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirected_header_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t reserved[6]); + /* Portion of redirected packet follows. */ + /* PACK_STRUCT_FLD_8(u8_t redirected[8]); */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** MTU option. */ +#define ND6_OPTION_TYPE_MTU (0x05) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mtu_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t mtu); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Route information option. */ +#define ND6_OPTION_TYPE_ROUTE_INFO (24) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct route_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t preference); + PACK_STRUCT_FIELD(u32_t route_lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Recursive DNS Server Option. */ +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS +#define LWIP_RDNSS_OPTION_MAX_SERVERS LWIP_ND6_RDNSS_MAX_DNS_SERVERS +#else +#define LWIP_RDNSS_OPTION_MAX_SERVERS 1 +#endif +#define ND6_OPTION_TYPE_RDNSS (25) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rdnss_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t rdnss_address[LWIP_RDNSS_OPTION_MAX_SERVERS]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ND6_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/tcp.h b/Sming/third-party/lwip2/include/lwip/prot/tcp.h new file mode 100644 index 0000000000..67fe7b9e5f --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/tcp.h @@ -0,0 +1,97 @@ +/** + * @file + * TCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_TCP_H +#define LWIP_HDR_PROT_TCP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* TCP header flags bits */ +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U +/* Valid TCP header flags */ +#define TCP_FLAGS 0x3fU + +#define TCPH_HDRLEN(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)) +#define TCPH_FLAGS(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)) + +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | lwip_htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = (u16_t)(lwip_htons((u16_t)((len) << 12) | (flags))) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | lwip_htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~lwip_htons(flags)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_TCP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/prot/udp.h b/Sming/third-party/lwip2/include/lwip/prot/udp.h new file mode 100644 index 0000000000..664f19a3e7 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/prot/udp.h @@ -0,0 +1,68 @@ +/** + * @file + * UDP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_UDP_H +#define LWIP_HDR_PROT_UDP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_UDP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/raw.h b/Sming/third-party/lwip2/include/lwip/raw.h new file mode 100644 index 0000000000..30aa147109 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/raw.h @@ -0,0 +1,118 @@ +/** + * @file + * raw API (to be used from TCPIP thread)\n + * See also @ref raw_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_RAW_H +#define LWIP_HDR_RAW_H + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr); + +/** the RAW protocol control block */ +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +#if LWIP_IPV6 + /* fields for handling checksum computations as per RFC3542. */ + u16_t chksum_offset; + u8_t chksum_reqd; +#endif +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto); +struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); +void raw_remove (struct raw_pcb *pcb); +err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); + +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp); +#define raw_init() /* Compatibility define, no init needed. */ + +void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +/* for compatibility with older implementation */ +#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* LWIP_HDR_RAW_H */ diff --git a/Sming/third-party/lwip2/include/lwip/sio.h b/Sming/third-party/lwip2/include/lwip/sio.h new file mode 100644 index 0000000000..7643e19569 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/sio.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef SIO_H +#define SIO_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum); +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd); +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd); +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SIO_H */ diff --git a/Sming/third-party/lwip2/include/lwip/snmp.h b/Sming/third-party/lwip2/include/lwip/snmp.h new file mode 100644 index 0000000000..8704d0b4d2 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/snmp.h @@ -0,0 +1,213 @@ +/** + * @file + * SNMP support API for implementing netifs and statitics for MIB2 + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_H +#define LWIP_HDR_SNMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct udp_pcb; +struct netif; + +/** + * @defgroup netif_mib2 MIB2 statistics + * @ingroup netif + */ + +/* MIB2 statistics functions */ +#if MIB2_STATS /* don't build if not configured for use in lwipopts.h */ +/** + * @ingroup netif_mib2 + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +/** This macro has a precision of ~49 days because sys_now returns u32_t. \#define your own if you want ~490 days. */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) (*(ptrToVal) = (sys_now() / 10)) +#endif + +/** + * @ingroup netif_mib2 + * Increment stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_INC(n, x) do { ++(n)->mib2_counters.x; } while(0) +/** + * @ingroup netif_mib2 + * Add value to stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_ADD(n, x, val) do { (n)->mib2_counters.x += (val); } while(0) + +/** + * @ingroup netif_mib2 + * Init MIB2 statistic counters in netif + * @param netif Netif to init + * @param type one of enum @ref snmp_ifType + * @param speed your link speed here (units: bits per second) + */ +#define MIB2_INIT_NETIF(netif, type, speed) do { \ + (netif)->link_type = (type); \ + (netif)->link_speed = (speed);\ + (netif)->ts = 0; \ + (netif)->mib2_counters.ifinoctets = 0; \ + (netif)->mib2_counters.ifinucastpkts = 0; \ + (netif)->mib2_counters.ifinnucastpkts = 0; \ + (netif)->mib2_counters.ifindiscards = 0; \ + (netif)->mib2_counters.ifinerrors = 0; \ + (netif)->mib2_counters.ifinunknownprotos = 0; \ + (netif)->mib2_counters.ifoutoctets = 0; \ + (netif)->mib2_counters.ifoutucastpkts = 0; \ + (netif)->mib2_counters.ifoutnucastpkts = 0; \ + (netif)->mib2_counters.ifoutdiscards = 0; \ + (netif)->mib2_counters.ifouterrors = 0; } while(0) +#else /* MIB2_STATS */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) +#endif +#define MIB2_INIT_NETIF(netif, type, speed) +#define MIB2_STATS_NETIF_INC(n, x) +#define MIB2_STATS_NETIF_ADD(n, x, val) +#endif /* MIB2_STATS */ + +/* LWIP MIB2 callbacks */ +#if LWIP_MIB2_CALLBACKS /* don't build if not configured for use in lwipopts.h */ +/* network interface */ +void mib2_netif_added(struct netif *ni); +void mib2_netif_removed(struct netif *ni); + +#if LWIP_IPV4 && LWIP_ARP +/* ARP (for atTable and ipNetToMediaTable) */ +void mib2_add_arp_entry(struct netif *ni, ip4_addr_t *ip); +void mib2_remove_arp_entry(struct netif *ni, ip4_addr_t *ip); +#else /* LWIP_IPV4 && LWIP_ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) +#endif /* LWIP_IPV4 && LWIP_ARP */ + +/* IP */ +#if LWIP_IPV4 +void mib2_add_ip4(struct netif *ni); +void mib2_remove_ip4(struct netif *ni); +void mib2_add_route_ip4(u8_t dflt, struct netif *ni); +void mib2_remove_route_ip4(u8_t dflt, struct netif *ni); +#endif /* LWIP_IPV4 */ + +/* UDP */ +#if LWIP_UDP +void mib2_udp_bind(struct udp_pcb *pcb); +void mib2_udp_unbind(struct udp_pcb *pcb); +#endif /* LWIP_UDP */ + +#else /* LWIP_MIB2_CALLBACKS */ +/* LWIP_MIB2_CALLBACKS support not available */ +/* define everything to be empty */ + +/* network interface */ +#define mib2_netif_added(ni) +#define mib2_netif_removed(ni) + +/* ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) + +/* IP */ +#define mib2_add_ip4(ni) +#define mib2_remove_ip4(ni) +#define mib2_add_route_ip4(dflt, ni) +#define mib2_remove_route_ip4(dflt, ni) + +/* UDP */ +#define mib2_udp_bind(pcb) +#define mib2_udp_unbind(pcb) +#endif /* LWIP_MIB2_CALLBACKS */ + +/* for source-code compatibility reasons only, can be removed (not used internally) */ +#define NETIF_INIT_SNMP MIB2_INIT_NETIF +#define snmp_add_ifinoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifinoctets, value) +#define snmp_inc_ifinucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinucastpkts) +#define snmp_inc_ifinnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinnucastpkts) +#define snmp_inc_ifindiscards(ni) MIB2_STATS_NETIF_INC(ni, ifindiscards) +#define snmp_inc_ifinerrors(ni) MIB2_STATS_NETIF_INC(ni, ifinerrors) +#define snmp_inc_ifinunknownprotos(ni) MIB2_STATS_NETIF_INC(ni, ifinunknownprotos) +#define snmp_add_ifoutoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifoutoctets, value) +#define snmp_inc_ifoutucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutucastpkts) +#define snmp_inc_ifoutnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutnucastpkts) +#define snmp_inc_ifoutdiscards(ni) MIB2_STATS_NETIF_INC(ni, ifoutdiscards) +#define snmp_inc_ifouterrors(ni) MIB2_STATS_NETIF_INC(ni, ifouterrors) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SNMP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/sockets.h b/Sming/third-party/lwip2/include/lwip/sockets.h new file mode 100644 index 0000000000..2522056dba --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/sockets.h @@ -0,0 +1,593 @@ +/** + * @file + * Socket API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef LWIP_HDR_SOCKETS_H +#define LWIP_HDR_SOCKETS_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) +typedef u8_t sa_family_t; +#endif +/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) +typedef u16_t in_port_t; +#endif + +#if LWIP_IPV4 +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; +#define SIN_ZERO_LEN 8 + char sin_zero[SIN_ZERO_LEN]; +}; +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +struct sockaddr_in6 { + u8_t sin6_len; /* length of this structure */ + sa_family_t sin6_family; /* AF_INET6 */ + in_port_t sin6_port; /* Transport layer port # */ + u32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + u32_t sin6_scope_id; /* Set of interfaces for scope */ +}; +#endif /* LWIP_IPV6 */ + +struct sockaddr { + u8_t sa_len; + sa_family_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_storage { + u8_t s2_len; + sa_family_t ss_family; + char s2_data1[2]; + u32_t s2_data2[3]; +#if LWIP_IPV6 + u32_t s2_data3[3]; +#endif /* LWIP_IPV6 */ +}; + +/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) +typedef u32_t socklen_t; +#endif + +struct lwip_sock; + +#if !LWIP_TCPIP_CORE_LOCKING +/** Maximum optlen used by setsockopt/getsockopt */ +#define LWIP_SETGETSOCKOPT_MAXOPTLEN 16 + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { + /** socket index for which to change options */ + int s; + /** level of the option to process */ + int level; + /** name of the option to process */ + int optname; + /** set: value to set the option to + * get: value of the option is stored here */ +#if LWIP_MPU_COMPATIBLE + u8_t optval[LWIP_SETGETSOCKOPT_MAXOPTLEN]; +#else + union { + void *p; + const void *pc; + } optval; +#endif + /** size of *optval */ + socklen_t optlen; + /** if an error occurs, it is temporarily stored here */ + err_t err; + /** semaphore to wake up the calling task */ + void* completed_sem; +}; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + +#if !defined(iovec) +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + + +/* + * Additional options, not kept in so_options. + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_DONTLINGER ((int)(~SO_LINGER)) +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time in seconds */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#if LWIP_IPV6 +#define AF_INET6 10 +#else /* LWIP_IPV6 */ +#define AF_INET6 AF_UNSPEC +#endif /* LWIP_IPV6 */ +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#if LWIP_IPV6 +#define IPPROTO_IPV6 41 +#define IPPROTO_ICMPV6 58 +#endif /* LWIP_IPV6 */ +#define IPPROTO_UDPLITE 136 +#define IPPROTO_RAW 255 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* + * Options for level IPPROTO_IPV6 + */ +#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ +#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_MULTICAST_TX_OPTIONS +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_IGMP +/* + * Options and types related to multicast membership + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +#undef FD_SETSIZE +/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +#define FD_SETSIZE MEMP_NUM_NETCONN +#define FDSETSAFESET(n, code) do { \ + if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ + code; }} while(0) +#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ + (code) : 0) +#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] |= (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] &= ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) + +typedef struct fd_set +{ + unsigned char fd_bits [(FD_SETSIZE+7)/8]; +} fd_set; + +#elif LWIP_SOCKET_OFFSET +#error LWIP_SOCKET_OFFSET does not work with external FD_SET! +#elif FD_SETSIZE < MEMP_NUM_NETCONN +#error "external FD_SETSIZE too small for number of sockets" +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +#define lwip_socket_init() /* Compatibility define, no init needed. */ +void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ + +#if LWIP_COMPAT_SOCKETS == 2 +/* This helps code parsers/code completion by not having the COMPAT functions as defines */ +#define lwip_accept accept +#define lwip_bind bind +#define lwip_shutdown shutdown +#define lwip_getpeername getpeername +#define lwip_getsockname getsockname +#define lwip_setsockopt setsockopt +#define lwip_getsockopt getsockopt +#define lwip_close closesocket +#define lwip_connect connect +#define lwip_listen listen +#define lwip_recv recv +#define lwip_recvfrom recvfrom +#define lwip_send send +#define lwip_sendmsg sendmsg +#define lwip_sendto sendto +#define lwip_socket socket +#define lwip_select select +#define lwip_ioctlsocket ioctl + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define lwip_read read +#define lwip_write write +#define lwip_writev writev +#undef lwip_close +#define lwip_close close +#define closesocket(s) close(s) +#define lwip_fcntl fcntl +#define lwip_ioctl ioctl +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS == 2 */ + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendmsg(int s, const struct msghdr *message, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_writev(int s, const struct iovec *iov, int iovcnt); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); + +#if LWIP_COMPAT_SOCKETS +#if LWIP_COMPAT_SOCKETS != 2 +/** @ingroup socket */ +#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) +/** @ingroup socket */ +#define bind(s,name,namelen) lwip_bind(s,name,namelen) +/** @ingroup socket */ +#define shutdown(s,how) lwip_shutdown(s,how) +/** @ingroup socket */ +#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) +/** @ingroup socket */ +#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) +/** @ingroup socket */ +#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define closesocket(s) lwip_close(s) +/** @ingroup socket */ +#define connect(s,name,namelen) lwip_connect(s,name,namelen) +/** @ingroup socket */ +#define listen(s,backlog) lwip_listen(s,backlog) +/** @ingroup socket */ +#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) +/** @ingroup socket */ +#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) +/** @ingroup socket */ +#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) +/** @ingroup socket */ +#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) +/** @ingroup socket */ +#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) +/** @ingroup socket */ +#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) +/** @ingroup socket */ +#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) +/** @ingroup socket */ +#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +/** @ingroup socket */ +#define read(s,mem,len) lwip_read(s,mem,len) +/** @ingroup socket */ +#define write(s,dataptr,len) lwip_write(s,dataptr,len) +/** @ingroup socket */ +#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) +/** @ingroup socket */ +#define close(s) lwip_close(s) +/** @ingroup socket */ +#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) +/** @ingroup socket */ +#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS != 2 */ + +#if LWIP_IPV4 && LWIP_IPV6 +/** @ingroup socket */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) \ + : (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL)) +/** @ingroup socket */ +#define inet_pton(af,src,dst) \ + (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) \ + : (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0)) +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0) +#else /* LWIP_IPV4 && LWIP_IPV6 */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) : NULL) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) : 0) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_HDR_SOCKETS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/stats.h b/Sming/third-party/lwip2/include/lwip/stats.h new file mode 100644 index 0000000000..bcda2ace6e --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/stats.h @@ -0,0 +1,491 @@ +/** + * @file + * Statistics API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_STATS_H +#define LWIP_HDR_STATS_H + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +/** Protocol related stats */ +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +/** IGMP stats */ +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +/** Memory stats */ +struct stats_mem { +#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY + const char *name; +#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ + STAT_COUNTER err; + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER illegal; +}; + +/** System element stats */ +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +/** System stats */ +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +/** SNMP MIB2 stats */ +struct stats_mib2 { + /* IP */ + u32_t ipinhdrerrors; + u32_t ipinaddrerrors; + u32_t ipinunknownprotos; + u32_t ipindiscards; + u32_t ipindelivers; + u32_t ipoutrequests; + u32_t ipoutdiscards; + u32_t ipoutnoroutes; + u32_t ipreasmoks; + u32_t ipreasmfails; + u32_t ipfragoks; + u32_t ipfragfails; + u32_t ipfragcreates; + u32_t ipreasmreqds; + u32_t ipforwdatagrams; + u32_t ipinreceives; + + /* TCP */ + u32_t tcpactiveopens; + u32_t tcppassiveopens; + u32_t tcpattemptfails; + u32_t tcpestabresets; + u32_t tcpoutsegs; + u32_t tcpretranssegs; + u32_t tcpinsegs; + u32_t tcpinerrs; + u32_t tcpoutrsts; + + /* UDP */ + u32_t udpindatagrams; + u32_t udpnoports; + u32_t udpinerrors; + u32_t udpoutdatagrams; + + /* ICMP */ + u32_t icmpinmsgs; + u32_t icmpinerrors; + u32_t icmpindestunreachs; + u32_t icmpintimeexcds; + u32_t icmpinparmprobs; + u32_t icmpinsrcquenchs; + u32_t icmpinredirects; + u32_t icmpinechos; + u32_t icmpinechoreps; + u32_t icmpintimestamps; + u32_t icmpintimestampreps; + u32_t icmpinaddrmasks; + u32_t icmpinaddrmaskreps; + u32_t icmpoutmsgs; + u32_t icmpouterrors; + u32_t icmpoutdestunreachs; + u32_t icmpouttimeexcds; + u32_t icmpoutechos; /* can be incremented by user application ('ping') */ + u32_t icmpoutechoreps; +}; + +/** + * @ingroup netif_mib2 + * SNMP MIB2 interface stats + */ +struct stats_mib2_netif_ctrs { + /** The total number of octets received on the interface, including framing characters */ + u32_t ifinoctets; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * not addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinucastpkts; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinnucastpkts; + /** The number of inbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being deliverable to a higher-layer protocol. One possible + * reason for discarding such a packet could be to free up buffer space */ + u32_t ifindiscards; + /** For packet-oriented interfaces, the number of inbound packets that contained errors + * preventing them from being deliverable to a higher-layer protocol. For character- + * oriented or fixed-length interfaces, the number of inbound transmission units that + * contained errors preventing them from being deliverable to a higher-layer protocol. */ + u32_t ifinerrors; + /** For packet-oriented interfaces, the number of packets received via the interface which + * were discarded because of an unknown or unsupported protocol. For character-oriented + * or fixed-length interfaces that support protocol multiplexing the number of transmission + * units received via the interface which were discarded because of an unknown or unsupported + * protocol. For any interface that does not support protocol multiplexing, this counter will + * always be 0 */ + u32_t ifinunknownprotos; + /** The total number of octets transmitted out of the interface, including framing characters. */ + u32_t ifoutoctets; + /** The total number of packets that higher-level protocols requested be transmitted, and + * which were not addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutucastpkts; + /** The total number of packets that higher-level protocols requested be transmitted, and which + * were addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutnucastpkts; + /** The number of outbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being transmitted. One possible reason for discarding + * such a packet could be to free up buffer space. */ + u32_t ifoutdiscards; + /** For packet-oriented interfaces, the number of outbound packets that could not be transmitted + * because of errors. For character-oriented or fixed-length interfaces, the number of outbound + * transmission units that could not be transmitted because of errors. */ + u32_t ifouterrors; +}; + +/** lwIP stats container */ +struct stats_ { +#if LINK_STATS + /** Link level */ + struct stats_proto link; +#endif +#if ETHARP_STATS + /** ARP */ + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + /** Fragmentation */ + struct stats_proto ip_frag; +#endif +#if IP_STATS + /** IP */ + struct stats_proto ip; +#endif +#if ICMP_STATS + /** ICMP */ + struct stats_proto icmp; +#endif +#if IGMP_STATS + /** IGMP */ + struct stats_igmp igmp; +#endif +#if UDP_STATS + /** UDP */ + struct stats_proto udp; +#endif +#if TCP_STATS + /** TCP */ + struct stats_proto tcp; +#endif +#if MEM_STATS + /** Heap */ + struct stats_mem mem; +#endif +#if MEMP_STATS + /** Internal memory pools */ + struct stats_mem *memp[MEMP_MAX]; +#endif +#if SYS_STATS + /** System */ + struct stats_sys sys; +#endif +#if IP6_STATS + /** IPv6 */ + struct stats_proto ip6; +#endif +#if ICMP6_STATS + /** ICMP6 */ + struct stats_proto icmp6; +#endif +#if IP6_FRAG_STATS + /** IPv6 fragmentation */ + struct stats_proto ip6_frag; +#endif +#if MLD6_STATS + /** Multicast listener discovery */ + struct stats_igmp mld6; +#endif +#if ND6_STATS + /** Neighbor discovery */ + struct stats_proto nd6; +#endif +#if MIB2_STATS + /** SNMP MIB2 */ + struct stats_mib2 mib2; +#endif +}; + +/** Global variable containing lwIP internal statistics. Add this to your debugger's watchlist. */ +extern struct stats_ lwip_stats; + +/** Init statistics */ +void stats_init(void); + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#define STATS_GET(x) lwip_stats.x +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP") +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + + #if MEMP_STATS +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i]->x) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(lwip_stats.memp[i], i) +#define MEMP_STATS_GET(x, i) STATS_GET(memp[i]->x) + #else +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_DISPLAY(i) +#define MEMP_STATS_GET(x, i) 0 +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +#if IP6_STATS +#define IP6_STATS_INC(x) STATS_INC(x) +#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") +#else +#define IP6_STATS_INC(x) +#define IP6_STATS_DISPLAY() +#endif + +#if ICMP6_STATS +#define ICMP6_STATS_INC(x) STATS_INC(x) +#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") +#else +#define ICMP6_STATS_INC(x) +#define ICMP6_STATS_DISPLAY() +#endif + +#if IP6_FRAG_STATS +#define IP6_FRAG_STATS_INC(x) STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") +#else +#define IP6_FRAG_STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() +#endif + +#if MLD6_STATS +#define MLD6_STATS_INC(x) STATS_INC(x) +#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") +#else +#define MLD6_STATS_INC(x) +#define MLD6_STATS_DISPLAY() +#endif + +#if ND6_STATS +#define ND6_STATS_INC(x) STATS_INC(x) +#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") +#else +#define ND6_STATS_INC(x) +#define ND6_STATS_DISPLAY() +#endif + +#if MIB2_STATS +#define MIB2_STATS_INC(x) STATS_INC(x) +#else +#define MIB2_STATS_INC(x) +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +void stats_display_proto(struct stats_proto *proto, const char *name); +void stats_display_igmp(struct stats_igmp *igmp, const char *name); +void stats_display_mem(struct stats_mem *mem, const char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp, name) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_STATS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/sys.h b/Sming/third-party/lwip2/include/lwip/sys.h new file mode 100644 index 0000000000..d12bae0f96 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/sys.h @@ -0,0 +1,455 @@ +/** + * @file + * OS abstraction layer + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#ifndef LWIP_HDR_SYS_H +#define LWIP_HDR_SYS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_sem_valid(s) 0 +#define sys_sem_valid_val(s) 0 +#define sys_sem_set_invalid(s) +#define sys_sem_set_invalid_val(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mutex_valid(mu) 0 +#define sys_mutex_set_invalid(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) +#define sys_mbox_valid(m) +#define sys_mbox_valid_val(m) +#define sys_mbox_set_invalid(m) +#define sys_mbox_set_invalid_val(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#ifndef LWIP_COMPAT_MUTEX +#define LWIP_COMPAT_MUTEX 0 +#endif + +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** + * @ingroup sys_mutex + * Create a new mutex. + * Note that mutexes are expected to not be taken recursively by the lwIP code, + * so both implementation types (recursive or non-recursive) should work. + * @param mutex pointer to the mutex to create + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Lock a mutex + * @param mutex the mutex to lock + */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Unlock a mutex + * @param mutex the mutex to unlock + */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Delete a semaphore + * @param mutex the mutex to delete + */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** + * @ingroup sys_mutex + * Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** + * @ingroup sys_mutex + * Set a mutex invalid so that sys_mutex_valid returns 0 + */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** + * @ingroup sys_sem + * Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** + * @ingroup sys_sem + * Signals a semaphore + * @param sem the semaphore to signal + */ +void sys_sem_signal(sys_sem_t *sem); +/** + * @ingroup sys_sem + * Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout + */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** + * @ingroup sys_sem + * Delete a semaphore + * @param sem semaphore to delete + */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** + * @ingroup sys_sem + * Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** + * @ingroup sys_sem + * Set a semaphore invalid so that sys_sem_valid returns 0 + */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif +#ifndef sys_sem_valid_val +/** + * Same as sys_sem_valid() but taking a value, not a pointer + */ +#define sys_sem_valid_val(sem) sys_sem_valid(&(sem)) +#endif +#ifndef sys_sem_set_invalid_val +/** + * Same as sys_sem_set_invalid() but taking a value, not a pointer + */ +#define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem)) +#endif + +#ifndef sys_msleep +/** + * @ingroup sys_misc + * Sleep for specified number of ms + */ +void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ +#endif + +/* Mailbox functions. */ + +/** + * @ingroup sys_mbox + * Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (minimum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** + * @ingroup sys_mbox + * Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! + */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** + * @ingroup sys_mbox + * Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty + */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** + * For now, we map straight to sys_arch implementation. + */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** + * @ingroup sys_mbox + * Delete an mbox + * @param mbox mbox to delete + */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** + * @ingroup sys_mbox + * Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** + * @ingroup sys_mbox + * Set an mbox invalid so that sys_mbox_valid returns 0 + */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_valid_val +/** + * Same as sys_mbox_valid() but taking a value, not a pointer + */ +#define sys_mbox_valid_val(mbox) sys_mbox_valid(&(mbox)) +#endif +#ifndef sys_mbox_set_invalid_val +/** + * Same as sys_mbox_set_invalid() but taking a value, not a pointer + */ +#define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox)) +#endif + + +/** + * @ingroup sys_misc + * The only thread function: + * Creates a new thread + * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/* sys_init() must be called before anything else. */ +void sys_init(void); + +#ifndef sys_jiffies +/** + * Ticks/jiffies since power up. + */ +u32_t sys_jiffies(void); +#endif + +/** + * @ingroup sys_time + * Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. + */ +u32_t sys_now(void); + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** + * @ingroup sys_prot + * SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** + * @ingroup sys_prot + * SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** + * @ingroup sys_prot + * SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SYS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/tcp.h b/Sming/third-party/lwip2/include/lwip/tcp.h new file mode 100644 index 0000000000..34d1c10158 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/tcp.h @@ -0,0 +1,433 @@ +/** + * @file + * TCP API (to be used from TCPIP thread)\n + * See also @ref tcp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_H +#define LWIP_HDR_TCP_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) @todo! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +#if LWIP_WND_SCALE +#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) +#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) +#define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) +typedef u32_t tcpwnd_size_t; +#else +#define RCV_WND_SCALE(pcb, wnd) (wnd) +#define SND_WND_SCALE(pcb, wnd) (wnd) +#define TCPWND16(x) (x) +#define TCP_WND_MAX(pcb) TCP_WND +typedef u16_t tcpwnd_size_t; +#endif + +#if LWIP_WND_SCALE || TCP_LISTEN_BACKLOG || LWIP_TCP_TIMESTAMPS +typedef u16_t tcpflags_t; +#else +typedef u8_t tcpflags_t; +#endif + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + void *callback_arg; \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + /* ports are in host byte order */ \ + u16_t local_port + + +/** the TCP protocol control block for listening pcbs */ +struct tcp_pcb_listen { +/** Common members of all PCB types */ + IP_PCB; +/** Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. */ + tcp_accept_fn accept; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + + +/** the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + tcpflags_t flags; +#define TF_ACK_DELAY 0x01U /* Delayed ACK. */ +#define TF_ACK_NOW 0x02U /* Immediate ACK. */ +#define TF_INFR 0x04U /* In fast recovery. */ +#define TF_CLOSEPEND 0x08U /* If this is set, tcp_close failed to enqueue the FIN (retried in tcp_tmr) */ +#define TF_RXCLOSED 0x10U /* rx closed by tcp_shutdown */ +#define TF_FIN 0x20U /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY 0x40U /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ +#if LWIP_WND_SCALE +#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */ +#endif +#if TCP_LISTEN_BACKLOG +#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */ +#endif +#if LWIP_TCP_TIMESTAMPS +#define TF_TIMESTAMP 0x0400U /* Timestamp option enabled */ +#endif + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + + /* Timers */ + u8_t polltmr, pollinterval; + u8_t last_timer; + u32_t tmr; + + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + tcpwnd_size_t rcv_wnd; /* receiver window available */ + tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + s16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u8_t dupacks; + u32_t lastack; /* Highest acknowledged seqno. */ + + /* congestion avoidance/control variables */ + tcpwnd_size_t cwnd; + tcpwnd_size_t ssthresh; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + tcpwnd_size_t snd_wnd; /* sender window */ + tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ + + tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) + u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + struct tcp_pcb_listen* listener; +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u8_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; + +#if LWIP_WND_SCALE + u8_t snd_scale; + u8_t rcv_scale; +#endif +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void); +struct tcp_pcb * tcp_new_ip_type (u8_t type); + +void tcp_arg (struct tcp_pcb *pcb, void *arg); +#if LWIP_CALLBACK_API +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); +#endif /* LWIP_CALLBACK_API */ +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); + +#if LWIP_TCP_TIMESTAMPS +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#else /* LWIP_TCP_TIMESTAMPS */ +#define tcp_mss(pcb) ((pcb)->mss) +#endif /* LWIP_TCP_TIMESTAMPS */ +#define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +/** @ingroup tcp_raw */ +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +/** @ingroup tcp_raw */ +#define tcp_nagle_enable(pcb) ((pcb)->flags = (tcpflags_t)((pcb)->flags & ~TF_NODELAY)) +/** @ingroup tcp_raw */ +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) + +#if TCP_LISTEN_BACKLOG +#define tcp_backlog_set(pcb, new_backlog) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \ + ((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0) +void tcp_backlog_delayed(struct tcp_pcb* pcb); +void tcp_backlog_accepted(struct tcp_pcb* pcb); +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_backlog_set(pcb, new_backlog) +#define tcp_backlog_delayed(pcb) +#define tcp_backlog_accepted(pcb) +#endif /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) /* compatibility define, not needed any more */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len); +err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected); + +struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +/** @ingroup tcp_raw */ +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb); +err_t tcp_close (struct tcp_pcb *pcb); +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags); + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +err_t tcp_output (struct tcp_pcb *pcb); + + +const char* tcp_debug_state_str(enum tcp_state s); + +/* for compatibility with older implementation */ +#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/tcpip.h b/Sming/third-party/lwip2/include/lwip/tcpip.h new file mode 100644 index 0000000000..f2f6b469f1 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/tcpip.h @@ -0,0 +1,106 @@ +/** + * @file + * Functions to sync with TCPIP thread + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_H +#define LWIP_HDR_TCPIP_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/timeouts.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +/** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +/** Unlock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +struct pbuf; +struct netif; + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +/* Forward declarations */ +struct tcpip_callback_msg; + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +err_t tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn); +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); +/** + * @ingroup lwip_os + * @see tcpip_callback_with_block + */ +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); +void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); +err_t tcpip_trycallback(struct tcpip_callback_msg* msg); + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_H */ diff --git a/Sming/third-party/lwip2/include/lwip/timeouts.h b/Sming/third-party/lwip2/include/lwip/timeouts.h new file mode 100644 index 0000000000..c9b93aa02a --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/timeouts.h @@ -0,0 +1,121 @@ +/** + * @file + * Timer implementations + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_TIMEOUTS_H +#define LWIP_HDR_TIMEOUTS_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#if !NO_SYS +#include "lwip/sys.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a stack-internal timer function that has to be + * called at a defined interval */ +typedef void (* lwip_cyclic_timer_handler)(void); + +/** This struct contains information about a stack-internal timer function + that has to be called at a defined interval */ +struct lwip_cyclic_timer { + u32_t interval_ms; + lwip_cyclic_timer_handler handler; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +/** This array contains all stack-internal cyclic timers. To get the number of + * timers, use LWIP_ARRAYSIZE() */ +extern const struct lwip_cyclic_timer lwip_cyclic_timers[]; + +#if LWIP_TIMERS + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void); + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg); +void sys_restart_timeouts(void); +#if NO_SYS +void sys_check_timeouts(void); +u32_t sys_timeouts_sleeptime(void); +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ + + +#endif /* LWIP_TIMERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_TIMEOUTS_H */ diff --git a/Sming/third-party/lwip2/include/lwip/udp.h b/Sming/third-party/lwip2/include/lwip/udp.h new file mode 100644 index 0000000000..b929907394 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwip/udp.h @@ -0,0 +1,182 @@ +/** + * @file + * UDP API (to be used from TCPIP thread)\n + * See also @ref udp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_UDP_H +#define LWIP_HDR_UDP_H + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' might point into the pbuf 'p' so freeing this pbuf + * can make 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port); + +/** the UDP protocol control block */ +struct udp_pcb { +/** Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_MULTICAST_TX_OPTIONS + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; + /** TTL for outgoing multicast packets */ + u8_t mcast_ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for external reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void); +struct udp_pcb * udp_new_ip_type(u8_t type); +void udp_remove (struct udp_pcb *pcb); +err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +err_t udp_connect (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +void udp_disconnect (struct udp_pcb *pcb); +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg); +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif); +err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, const ip_addr_t *src_ip); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port); +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum); +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum); +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum); +err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, + u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp); + +void udp_init (void); + +/* for compatibility with older implementation */ +#define udp_new_ip6() udp_new_ip_type(IPADDR_TYPE_V6) + +#if LWIP_MULTICAST_TX_OPTIONS +#define udp_set_multicast_netif_addr(pcb, ip4addr) ip_addr_copy_from_ip4((pcb)->multicast_ip, *(ip4addr)) +#define udp_get_multicast_netif_addr(pcb) ip_2_ip4(&(pcb)->multicast_ip) +#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) +#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* LWIP_HDR_UDP_H */ diff --git a/Sming/third-party/lwip2/include/lwipopts.h b/Sming/third-party/lwip2/include/lwipopts.h new file mode 100644 index 0000000000..410d3a4cb9 --- /dev/null +++ b/Sming/third-party/lwip2/include/lwipopts.h @@ -0,0 +1,2996 @@ +// this file will be overwritten upon lwip2 rebuild +#ifndef __CUSTOM_EXTRA_DEFINES__ +#define __CUSTOM_EXTRA_DEFINES__ +#define LWIP_NO_STDINT_H 1 +#endif + +#ifndef MYLWIPOPTS_H +#define MYLWIPOPTS_H + +// opt.h version lwip-2.0.3 for esp8266 + +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - + * without this, doxygen does not see the actual #define + */ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +//#include "lwip/debug.h" // done at end of this file + +/** + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts + */ + + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ +#define NO_SYS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif + +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * MEMMOVE: override this if you have a faster implementation at hand than the + * one included in your C library. lwIP currently uses MEMMOVE only when IPv6 + * fragmentation support is enabled. + */ +#if !defined MEMMOVE || defined __DOXYGEN__ +#define MEMMOVE(dst,src,len) os_memmove(dst,src,len) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 1 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 1 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 + */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 16000 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_PBUF 10 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ +//#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) // 5 +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 16 // 5 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 0 // 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 0 // 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 10 // 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ +#define MEMP_NUM_NETBUF 0 // 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 0 // 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 4 // 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 4 // 8 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 0 // 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 10 // 16 +#endif + +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#if !defined LWIP_ARP || defined __DOXYGEN__ +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 10 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 1 // 0 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 3 // 0 // 3 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#if !defined IP_FORWARD || defined __DOXYGEN__ +#define IP_FORWARD 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ +#define IP_REASSEMBLY 0 // 1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#if !defined IP_FRAG || defined __DOXYGEN__ +#define IP_FRAG 0 // 1 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 1 // 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL (IP_DEFAULT_TTL) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ +#define LWIP_DHCP 1 // 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK 0 // ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has + * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and + * netif drivers might not set this flag, the default is off. If enabled, + * netif_set_link_up() must be called to continue dhcp starting. + */ +#if !defined LWIP_DHCP_CHECK_LINK_UP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#endif + +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 1 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DHCP servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ +#define LWIP_AUTOIP 0 +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + -------- Multicast options ------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_multicast Multicast + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP, as well as (currently only) + * core support for the corresponding IPv6 options. + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW)) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ +#define LWIP_IGMP 1 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#if !defined LWIP_DNS || defined __DOXYGEN__ +#define LWIP_DNS 1 // 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#if !defined LWIP_UDP || defined __DOXYGEN__ +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 1 // 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +//#define TCP_WND (*(volatile uint32*)0x600011F0) // (4 * TCP_MSS) +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +//#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) // 12 +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +//#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) // 6 +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ 0 // (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF (2 * TCP_MSS) +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 36 // 0u # 36 is EP_OFFSET from original esp implementation +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif + +/** + * LWIP_PBUF_REF_T: Refcount type in pbuf. + * Default width of u8_t can be increased if 255 refs are not enough for you. + */ +#ifndef LWIP_PBUF_REF_T +#define LWIP_PBUF_REF_T u8_t +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for + * small real-life targets. Some code like routing etc. can be left out. + */ +#if !defined LWIP_SINGLE_NETIF || defined __DOXYGEN__ +#define LWIP_SINGLE_NETIF 0 // AP+STA = 2 different netif +#endif + +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 1 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 1 +#endif + +/** + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * for several netif related event that supports multiple subscribers. + * @see netif_ext_status_callback + */ +#if !defined LWIP_NETIF_EXT_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_EXT_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 // MANDATORY FOR ESP8266 BLOBS !! +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif. + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF (LWIP_NETIF_LOOPBACK && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 0 // 1 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 0 // 1 +#endif + +/** LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete + * successfully, as required by POSIX. Default is POSIX-compliant. + */ +#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ +#define LWIP_SOCKET_SET_ERRNO 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 // 1 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 1 // 0 +#endif + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 1 // 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 0 +#endif + +/** + * LWIP_SOCKET_SELECT==1 (default): enable select() for sockets (uses a netconn + * callback to keep track of events). + * This saves RAM (counters per socket) and code (netconn event callback), which + * should improve performance a bit). + */ +#if !defined LWIP_SOCKET_SELECT || defined __DOXYGEN__ +#define LWIP_SOCKET_SELECT 1 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 0 // 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} + */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 // 0 +#endif + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_SCOPES==1: Enable support for IPv6 address scopes, ensuring that + * e.g. link-local addresses are really treated as link-local. Disable this + * setting only for single-interface configurations. + */ +#if !defined LWIP_IPV6_SCOPES || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES (LWIP_IPV6 && !LWIP_SINGLE_NETIF) +#endif + +/** + * LWIP_IPV6_SCOPES_DEBUG==1: Perform run-time checks to verify that addresses + * are properly zoned (see ip6_zone.h on what that means) where it matters. + * Enabling this setting is highly recommended when upgrading from an existing + * installation that is not yet scope-aware; otherwise it may be too expensive. + */ +#if !defined LWIP_IPV6_SCOPES_DEBUG || defined __DOXYGEN__ +#define LWIP_IPV6_SCOPES_DEBUG 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT (LWIP_IPV6) // 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each + * IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled + * otherwise, in which case the application may assign address lifetimes with + * the appropriate macros. Addresses with no lifetime are assumed to be static. + * If this option is disabled, all addresses are assumed to be static. + */ +#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__ +#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to \#include in files that provide hooks. + * Declare your hook function prototypes in there, you may also \#include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(dest, src): + * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * - called from etharp_output() (IPv4) + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Returns the IPv4 address of the gateway to handle the specified destination + * IPv4 address. If NULL is returned, the netif's default gateway is used. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * - called from ip6_input() (IPv6) + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * - called from ip6_route() (IPv6) + * - src: sourc IPv6 address + * - dest: destination IPv6 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * - called from nd6_get_next_hop_entry() (IPv6) + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Returns the IPv6 address of the next hop to handle the specified destination + * IPv6 address. If NULL is returned, a NDP-discovered router is used instead. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * - called from ethernet_input() if VLAN support is enabled + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature: s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * - called from memp_free() when a memp pool was empty and an item is now available + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Return ERR_OK if packet is accepted, any error code otherwise. + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH) +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF//LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_TYPES_ON//LWIP_DBG_OFF +#endif +/** + * @} + */ + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + + +/* + -------------------------------------------------- + ------------------ SNTP options ------------------ + -------------------------------------------------- +*/ +#define SNTP_SERVER_DNS 1 // SNTP support DNS names through sntp_setservername / sntp_getservername +#define SNTP_SERVER_ADDRESS "pool.ntp.org" // default +#define SNTP_GET_SERVERS_FROM_DHCP 1 +#define SNTP_SET_SYSTEM_TIME(t) (sntp_set_system_time(t)) // implemented in lwip2-sntp.c + +/* + -------------------------------------------------- + -------------------------------------------------- +*/ + +#include "lwip/debug.h" +#include "arch/cc.h" +#include "lwip-git-hash.h" + +#endif // MYLWIPOPTS_H diff --git a/Sming/third-party/lwip2/include/netif/etharp.h b/Sming/third-party/lwip2/include/netif/etharp.h new file mode 100644 index 0000000000..b536fd280f --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/etharp.h @@ -0,0 +1,3 @@ +/* ARP has been moved to core/ipv4, provide this #include for compatibility only */ +#include "lwip/etharp.h" +#include "netif/ethernet.h" diff --git a/Sming/third-party/lwip2/include/netif/ethernet.h b/Sming/third-party/lwip2/include/netif/ethernet.h new file mode 100644 index 0000000000..49649cbf8b --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ethernet.h @@ -0,0 +1,77 @@ +/** + * @file + * Ethernet input function - handles INCOMING ethernet level traffic + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHERNET_H +#define LWIP_HDR_NETIF_ETHERNET_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ARP || LWIP_ETHERNET + +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + +err_t ethernet_input(struct pbuf *p, struct netif *netif); +err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type); + +extern const struct eth_addr ethbroadcast, ethzero; + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_ETHERNET_H */ diff --git a/Sming/third-party/lwip2/include/netif/lowpan6.h b/Sming/third-party/lwip2/include/netif/lowpan6.h new file mode 100644 index 0000000000..4174644bb3 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/lowpan6.h @@ -0,0 +1,86 @@ +/** + * @file + * + * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + */ + +/* + * Copyright (c) 2015 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_H +#define LWIP_HDR_LOWPAN6_H + +#include "netif/lowpan6_opts.h" + +#if LWIP_IPV6 && LWIP_6LOWPAN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period */ +#define LOWPAN6_TMR_INTERVAL 1000 + +void lowpan6_tmr(void); + +err_t lowpan6_set_context(u8_t index, const ip6_addr_t * context); +err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); + +#if LWIP_IPV4 +err_t lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4 */ +err_t lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); +err_t lowpan6_input(struct pbuf * p, struct netif *netif); +err_t lowpan6_if_init(struct netif *netif); + +/* pan_id in network byte order. */ +err_t lowpan6_set_pan_id(u16_t pan_id); + +#if !NO_SYS +err_t tcpip_6lowpan_input(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_6LOWPAN */ + +#endif /* LWIP_HDR_LOWPAN6_H */ diff --git a/Sming/third-party/lwip2/include/netif/lowpan6_opts.h b/Sming/third-party/lwip2/include/netif/lowpan6_opts.h new file mode 100644 index 0000000000..fb93ea05de --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/lowpan6_opts.h @@ -0,0 +1,70 @@ +/** + * @file + * 6LowPAN options list + */ + +/* + * Copyright (c) 2015 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_OPTS_H +#define LWIP_HDR_LOWPAN6_OPTS_H + +#include "lwip/opt.h" + +#ifndef LWIP_6LOWPAN +#define LWIP_6LOWPAN 0 +#endif + +#ifndef LWIP_6LOWPAN_NUM_CONTEXTS +#define LWIP_6LOWPAN_NUM_CONTEXTS 10 +#endif + +#ifndef LWIP_6LOWPAN_INFER_SHORT_ADDRESS +#define LWIP_6LOWPAN_INFER_SHORT_ADDRESS 1 +#endif + +#ifndef LWIP_6LOWPAN_IPHC +#define LWIP_6LOWPAN_IPHC 1 +#endif + +#ifndef LWIP_6LOWPAN_HW_CRC +#define LWIP_6LOWPAN_HW_CRC 1 +#endif + +#ifndef LOWPAN6_DEBUG +#define LOWPAN6_DEBUG LWIP_DBG_OFF +#endif + +#endif /* LWIP_HDR_LOWPAN6_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ccp.h b/Sming/third-party/lwip2/include/netif/ppp/ccp.h new file mode 100644 index 0000000000..14dd65962c --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ccp.h @@ -0,0 +1,156 @@ +/* + * ccp.h - Definitions for PPP Compression Control Protocol. + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ccp.h,v 1.12 2004/11/04 10:02:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CCP_H +#define CCP_H + +/* + * CCP codes. + */ + +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ + +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ + +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +#if BSDCOMPRESS_SUPPORT +/* + * Definitions for BSD-Compress. + */ + +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ +#endif /* BSDCOMPRESS_SUPPORT */ + +#if DEFLATE_SUPPORT +/* + * Definitions for Deflate. + */ + +#define CI_DEFLATE 26 /* config option for Deflate */ +#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 9 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + 8) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 +#endif /* DEFLATE_SUPPORT */ + +#if MPPE_SUPPORT +/* + * Definitions for MPPE. + */ + +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ +#endif /* MPPE_SUPPORT */ + +#if PREDICTOR_SUPPORT +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ +#endif /* PREDICTOR_SUPPORT */ + +typedef struct ccp_options { +#if DEFLATE_SUPPORT + unsigned int deflate :1; /* do Deflate? */ + unsigned int deflate_correct :1; /* use correct code for deflate? */ + unsigned int deflate_draft :1; /* use draft RFC code for deflate? */ +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + unsigned int bsd_compress :1; /* do BSD Compress? */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + unsigned int predictor_1 :1; /* do Predictor-1? */ + unsigned int predictor_2 :1; /* do Predictor-2? */ +#endif /* PREDICTOR_SUPPORT */ + +#if MPPE_SUPPORT + u8_t mppe; /* MPPE bitfield */ +#endif /* MPPE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + u_short bsd_bits; /* # bits/code for BSD Compress */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + u_short deflate_size; /* lg(window size) for Deflate */ +#endif /* DEFLATE_SUPPORT */ + u8_t method; /* code for chosen compression method */ +} ccp_options; + +extern const struct protent ccp_protent; + +void ccp_resetrequest(ppp_pcb *pcb); /* Issue a reset-request. */ + +#endif /* CCP_H */ +#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/chap-md5.h b/Sming/third-party/lwip2/include/netif/ppp/chap-md5.h new file mode 100644 index 0000000000..eb0269fe50 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/chap-md5.h @@ -0,0 +1,36 @@ +/* + * chap-md5.h - New CHAP/MD5 implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +extern const struct chap_digest_type md5_digest; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/chap-new.h b/Sming/third-party/lwip2/include/netif/ppp/chap-new.h new file mode 100644 index 0000000000..64eae32202 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/chap-new.h @@ -0,0 +1,192 @@ +/* + * chap-new.c - New CHAP implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAP_H +#define CHAP_H + +#include "ppp.h" + +/* + * CHAP packets begin with a standard header with code, id, len (2 bytes). + */ +#define CHAP_HDRLEN 4 + +/* + * Values for the code field. + */ +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +/* + * CHAP digest codes. + */ +#define CHAP_MD5 5 +#if MSCHAP_SUPPORT +#define CHAP_MICROSOFT 0x80 +#define CHAP_MICROSOFT_V2 0x81 +#endif /* MSCHAP_SUPPORT */ + +/* + * Semi-arbitrary limits on challenge and response fields. + */ +#define MAX_CHALLENGE_LEN 64 +#define MAX_RESPONSE_LEN 64 + +/* + * These limits apply to challenge and response packets we send. + * The +4 is the +1 that we actually need rounded up. + */ +#define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) +#define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) + +/* bitmask of supported algorithms */ +#if MSCHAP_SUPPORT +#define MDTYPE_MICROSOFT_V2 0x1 +#define MDTYPE_MICROSOFT 0x2 +#endif /* MSCHAP_SUPPORT */ +#define MDTYPE_MD5 0x4 +#define MDTYPE_NONE 0 + +#if MSCHAP_SUPPORT +/* Return the digest alg. ID for the most preferred digest type. */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + ((mdtype) & MDTYPE_MICROSOFT_V2)? CHAP_MICROSOFT_V2: \ + ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Return the bit flag (lsb set) for our most preferred digest type. */ +#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype) + +/* Return the bit flag for a given digest algorithm ID. */ +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MICROSOFT_V2)? MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Can we do the requested digest? */ +#if MSCHAP_SUPPORT +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MICROSOFT_V2)? (mdtype) & MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* + * The code for each digest type has to supply one of these. + */ +struct chap_digest_type { + int code; + +#if PPP_SERVER + /* + * Note: challenge and response arguments below are formatted as + * a length byte followed by the actual challenge/response data. + */ + void (*generate_challenge)(ppp_pcb *pcb, unsigned char *challenge); + int (*verify_response)(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space); +#endif /* PPP_SERVER */ + void (*make_response)(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *priv); + int (*check_success)(ppp_pcb *pcb, unsigned char *pkt, int len, unsigned char *priv); + void (*handle_failure)(ppp_pcb *pcb, unsigned char *pkt, int len); +}; + +/* + * Each interface is described by chap structure. + */ +#if CHAP_SUPPORT +typedef struct chap_client_state { + u8_t flags; + const char *name; + const struct chap_digest_type *digest; + unsigned char priv[64]; /* private area for digest's use */ +} chap_client_state; + +#if PPP_SERVER +typedef struct chap_server_state { + u8_t flags; + u8_t id; + const char *name; + const struct chap_digest_type *digest; + int challenge_xmits; + int challenge_pktlen; + unsigned char challenge[CHAL_MAX_PKTLEN]; +} chap_server_state; +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* Hook for a plugin to validate CHAP challenge */ +extern int (*chap_verify_hook)(char *name, char *ourname, int id, + const struct chap_digest_type *digest, + unsigned char *challenge, unsigned char *response, + char *message, int message_space); +#endif /* UNUSED */ + +#if PPP_SERVER +/* Called by authentication code to start authenticating the peer. */ +extern void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code); +#endif /* PPP_SERVER */ + +/* Called by auth. code to start authenticating us to the peer. */ +extern void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code); + +/* Represents the CHAP protocol to the main pppd code */ +extern const struct protent chap_protent; + +#endif /* CHAP_H */ +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/chap_ms.h b/Sming/third-party/lwip2/include/netif/ppp/chap_ms.h new file mode 100644 index 0000000000..0795291158 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/chap_ms.h @@ -0,0 +1,44 @@ +/* + * chap_ms.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: chap_ms.h,v 1.13 2004/11/15 22:13:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAPMS_INCLUDE +#define CHAPMS_INCLUDE + +extern const struct chap_digest_type chapms_digest; +extern const struct chap_digest_type chapms2_digest; + +#endif /* CHAPMS_INCLUDE */ + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/eap.h b/Sming/third-party/lwip2/include/netif/ppp/eap.h new file mode 100644 index 0000000000..3ee9aaf81a --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/eap.h @@ -0,0 +1,169 @@ +/* + * eap.h - Extensible Authentication Protocol for PPP (RFC 2284) + * + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Non-exclusive rights to redistribute, modify, translate, and use + * this software in source and binary forms, in whole or in part, is + * hereby granted, provided that the above copyright notice is + * duplicated in any source form, and that neither the name of the + * copyright holder nor the author is used to endorse or promote + * products derived from this software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Original version by James Carlson + * + * $Id: eap.h,v 1.2 2003/06/11 23:56:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_EAP_H +#define PPP_EAP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Packet header = Code, id, length. + */ +#define EAP_HEADERLEN 4 + + +/* EAP message codes. */ +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +/* EAP types */ +#define EAPT_IDENTITY 1 +#define EAPT_NOTIFICATION 2 +#define EAPT_NAK 3 /* (response only) */ +#define EAPT_MD5CHAP 4 +#define EAPT_OTP 5 /* One-Time Password; RFC 1938 */ +#define EAPT_TOKEN 6 /* Generic Token Card */ +/* 7 and 8 are unassigned. */ +#define EAPT_RSA 9 /* RSA Public Key Authentication */ +#define EAPT_DSS 10 /* DSS Unilateral */ +#define EAPT_KEA 11 /* KEA */ +#define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */ +#define EAPT_TLS 13 /* EAP-TLS */ +#define EAPT_DEFENDER 14 /* Defender Token (AXENT) */ +#define EAPT_W2K 15 /* Windows 2000 EAP */ +#define EAPT_ARCOT 16 /* Arcot Systems */ +#define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */ +#define EAPT_NOKIACARD 18 /* Nokia IP smart card */ +#define EAPT_SRP 19 /* Secure Remote Password */ +/* 20 is deprecated */ + +/* EAP SRP-SHA1 Subtypes */ +#define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */ +#define EAPSRP_CKEY 1 /* Response 1 - Client Key */ +#define EAPSRP_SKEY 2 /* Request 2 - Server Key */ +#define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */ +#define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */ +#define EAPSRP_ACK 3 /* Response 3 - final ack */ +#define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */ + +#define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */ + +#define SRP_PSEUDO_ID "pseudo_" +#define SRP_PSEUDO_LEN 7 + +#define MD5_SIGNATURE_SIZE 16 +#define EAP_MIN_CHALLENGE_LENGTH 17 +#define EAP_MAX_CHALLENGE_LENGTH 24 +#define EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH 3 /* 2^3-1 = 7, 17+7 = 24 */ + +#define EAP_STATES \ + "Initial", "Pending", "Closed", "Listen", "Identify", \ + "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" + +#define eap_client_active(pcb) ((pcb)->eap.es_client.ea_state == eapListen) +#if PPP_SERVER +#define eap_server_active(pcb) \ + ((pcb)->eap.es_server.ea_state >= eapIdentify && \ + (pcb)->eap.es_server.ea_state <= eapMD5Chall) +#endif /* PPP_SERVER */ + +/* + * Complete EAP state for one PPP session. + */ +enum eap_state_code { + eapInitial = 0, /* No EAP authentication yet requested */ + eapPending, /* Waiting for LCP (no timer) */ + eapClosed, /* Authentication not in use */ + eapListen, /* Client ready (and timer running) */ + eapIdentify, /* EAP Identify sent */ + eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ + eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ + eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ + eapMD5Chall, /* Sent MD5-Challenge */ + eapOpen, /* Completed authentication */ + eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ + eapBadAuth /* Failed authentication */ +}; + +struct eap_auth { + const char *ea_name; /* Our name */ + char ea_peer[MAXNAMELEN +1]; /* Peer's name */ + void *ea_session; /* Authentication library linkage */ + u_char *ea_skey; /* Shared encryption key */ + u_short ea_namelen; /* Length of our name */ + u_short ea_peerlen; /* Length of peer's name */ + enum eap_state_code ea_state; + u_char ea_id; /* Current id */ + u_char ea_requests; /* Number of Requests sent/received */ + u_char ea_responses; /* Number of Responses */ + u_char ea_type; /* One of EAPT_* */ + u32_t ea_keyflags; /* SRP shared key usage flags */ +}; + +#ifndef EAP_MAX_CHALLENGE_LENGTH +#define EAP_MAX_CHALLENGE_LENGTH 24 +#endif +typedef struct eap_state { + struct eap_auth es_client; /* Client (authenticatee) data */ +#if PPP_SERVER + struct eap_auth es_server; /* Server (authenticator) data */ +#endif /* PPP_SERVER */ + int es_savedtime; /* Saved timeout */ + int es_rechallenge; /* EAP rechallenge interval */ + int es_lwrechallenge; /* SRP lightweight rechallenge inter */ + u8_t es_usepseudo; /* Use SRP Pseudonym if offered one */ + int es_usedpseudo; /* Set if we already sent PN */ + int es_challen; /* Length of challenge string */ + u_char es_challenge[EAP_MAX_CHALLENGE_LENGTH]; +} eap_state; + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +#define EAP_DEFTRANSMITS 10 /* max # times to transmit */ +#define EAP_DEFREQTIME 20 /* Time to wait for peer request */ +#define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ +#endif /* moved to ppp_opts.h */ + +void eap_authwithpeer(ppp_pcb *pcb, const char *localname); +void eap_authpeer(ppp_pcb *pcb, const char *localname); + +extern const struct protent eap_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_EAP_H */ + +#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ecp.h b/Sming/third-party/lwip2/include/netif/ppp/ecp.h new file mode 100644 index 0000000000..5cdce29d5b --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ecp.h @@ -0,0 +1,50 @@ +/* + * ecp.h - Definitions for PPP Encryption Control Protocol. + * + * Copyright (c) 2002 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ecp.h,v 1.2 2003/01/10 07:12:36 fcusack Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +typedef struct ecp_options { + bool required; /* Is ECP required? */ + unsigned enctype; /* Encryption type */ +} ecp_options; + +extern fsm ecp_fsm[]; +extern ecp_options ecp_wantoptions[]; +extern ecp_options ecp_gotoptions[]; +extern ecp_options ecp_allowoptions[]; +extern ecp_options ecp_hisoptions[]; + +extern const struct protent ecp_protent; + +#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/eui64.h b/Sming/third-party/lwip2/include/netif/ppp/eui64.h new file mode 100644 index 0000000000..20ac22eede --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/eui64.h @@ -0,0 +1,94 @@ +/* + * eui64.h - EUI64 routines for IPv6CP. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: eui64.h,v 1.6 2002/12/04 23:03:32 paulus Exp $ +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef EUI64_H +#define EUI64_H + +/* + * @todo: + * + * Maybe this should be done by processing struct in6_addr directly... + */ +typedef union +{ + u8_t e8[8]; + u16_t e16[4]; + u32_t e32[2]; +} eui64_t; + +#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0) +#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \ + ((e).e32[1] == (o).e32[1])) +#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0; + +#define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t)) + +#define eui64_magic(e) do { \ + (e).e32[0] = magic(); \ + (e).e32[1] = magic(); \ + (e).e8[0] &= ~2; \ + } while (0) +#define eui64_magic_nz(x) do { \ + eui64_magic(x); \ + } while (eui64_iszero(x)) +#define eui64_magic_ne(x, y) do { \ + eui64_magic(x); \ + } while (eui64_equals(x, y)) + +#define eui64_get(ll, cp) do { \ + eui64_copy((*cp), (ll)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_put(ll, cp) do { \ + eui64_copy((ll), (*cp)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_set32(e, l) do { \ + (e).e32[0] = 0; \ + (e).e32[1] = lwip_htonl(l); \ + } while (0) +#define eui64_setlo32(e, l) eui64_set32(e, l) + +char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ + +#endif /* EUI64_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/fsm.h b/Sming/third-party/lwip2/include/netif/ppp/fsm.h new file mode 100644 index 0000000000..b6915d3b80 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/fsm.h @@ -0,0 +1,175 @@ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: fsm.h,v 1.10 2004/11/13 02:28:15 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef FSM_H +#define FSM_H + +#include "ppp.h" + +/* + * Packet header = Code, id, length. + */ +#define HEADERLEN 4 + + +/* + * CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ 1 /* Configuration Request */ +#define CONFACK 2 /* Configuration Ack */ +#define CONFNAK 3 /* Configuration Nak */ +#define CONFREJ 4 /* Configuration Reject */ +#define TERMREQ 5 /* Termination Request */ +#define TERMACK 6 /* Termination Ack */ +#define CODEREJ 7 /* Code Reject */ + + +/* + * Each FSM is described by an fsm structure and fsm callbacks. + */ +typedef struct fsm { + ppp_pcb *pcb; /* PPP Interface */ + const struct fsm_callbacks *callbacks; /* Callback routines */ + const char *term_reason; /* Reason for closing protocol */ + u8_t seen_ack; /* Have received valid Ack/Nak/Rej to Req */ + /* -- This is our only flag, we might use u_int :1 if we have more flags */ + u16_t protocol; /* Data Link Layer Protocol field value */ + u8_t state; /* State */ + u8_t flags; /* Contains option bits */ + u8_t id; /* Current id */ + u8_t reqid; /* Current request id */ + u8_t retransmits; /* Number of retransmissions left */ + u8_t nakloops; /* Number of nak loops since last ack */ + u8_t rnakloops; /* Number of naks received */ + u8_t maxnakloops; /* Maximum number of nak loops tolerated + (necessary because IPCP require a custom large max nak loops value) */ + u8_t term_reason_len; /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { + void (*resetci) /* Reset our Configuration Information */ + (fsm *); + int (*cilen) /* Length of our Configuration Information */ + (fsm *); + void (*addci) /* Add our Configuration Information */ + (fsm *, u_char *, int *); + int (*ackci) /* ACK our Configuration Information */ + (fsm *, u_char *, int); + int (*nakci) /* NAK our Configuration Information */ + (fsm *, u_char *, int, int); + int (*rejci) /* Reject our Configuration Information */ + (fsm *, u_char *, int); + int (*reqci) /* Request peer's Configuration Information */ + (fsm *, u_char *, int *, int); + void (*up) /* Called when fsm reaches PPP_FSM_OPENED state */ + (fsm *); + void (*down) /* Called when fsm leaves PPP_FSM_OPENED state */ + (fsm *); + void (*starting) /* Called when we want the lower layer */ + (fsm *); + void (*finished) /* Called when we don't want the lower layer */ + (fsm *); + void (*protreject) /* Called when Protocol-Reject received */ + (int); + void (*retransmit) /* Retransmission is necessary */ + (fsm *); + int (*extcode) /* Called when unknown code received */ + (fsm *, int, int, u_char *, int); + const char *proto_name; /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/* + * Link states. + */ +#define PPP_FSM_INITIAL 0 /* Down, hasn't been opened */ +#define PPP_FSM_STARTING 1 /* Down, been opened */ +#define PPP_FSM_CLOSED 2 /* Up, hasn't been opened */ +#define PPP_FSM_STOPPED 3 /* Open, waiting for down event */ +#define PPP_FSM_CLOSING 4 /* Terminating the connection, not open */ +#define PPP_FSM_STOPPING 5 /* Terminating, but open */ +#define PPP_FSM_REQSENT 6 /* We've sent a Config Request */ +#define PPP_FSM_ACKRCVD 7 /* We've received a Config Ack */ +#define PPP_FSM_ACKSENT 8 /* We've sent a Config Ack */ +#define PPP_FSM_OPENED 9 /* Connection available */ + + +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT 4 /* Wait for peer to speak first */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define DEFTIMEOUT 3 /* Timeout time in seconds */ +#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif /* moved to ppp_opts.h */ + + +/* + * Prototypes + */ +void fsm_init(fsm *f); +void fsm_lowerup(fsm *f); +void fsm_lowerdown(fsm *f); +void fsm_open(fsm *f); +void fsm_close(fsm *f, const char *reason); +void fsm_input(fsm *f, u_char *inpacket, int l); +void fsm_protreject(fsm *f); +void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen); + + +#endif /* FSM_H */ +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ipcp.h b/Sming/third-party/lwip2/include/netif/ppp/ipcp.h new file mode 100644 index 0000000000..45f46b31ff --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ipcp.h @@ -0,0 +1,126 @@ +/* + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipcp.h,v 1.14 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPCP_H +#define IPCP_H + +/* + * Options. + */ +#define CI_ADDRS 1 /* IP Addresses */ +#if VJ_SUPPORT +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* VJ_SUPPORT */ +#define CI_ADDR 3 + +#if LWIP_DNS +#define CI_MS_DNS1 129 /* Primary DNS value */ +#define CI_MS_DNS2 131 /* Secondary DNS value */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ +#define CI_MS_WINS1 130 /* Primary WINS value */ +#define CI_MS_WINS2 132 /* Secondary WINS value */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT +#define MAX_STATES 16 /* from slcompress.h */ + +#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ +#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ +#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ + /* maxslot and slot number compression) */ + +#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ +#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ + /* compression option*/ +#endif /* VJ_SUPPORT */ + +typedef struct ipcp_options { + unsigned int neg_addr :1; /* Negotiate IP Address? */ + unsigned int old_addrs :1; /* Use old (IP-Addresses) option? */ + unsigned int req_addr :1; /* Ask peer to send IP address? */ +#if 0 /* UNUSED */ + unsigned int default_route :1; /* Assign default route through interface? */ + unsigned int replace_default_route :1; /* Replace default route through interface? */ +#endif /* UNUSED */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp :1; /* Make proxy ARP entry for peer? */ +#endif /* UNUSED - PROXY ARP */ +#if VJ_SUPPORT + unsigned int neg_vj :1; /* Van Jacobson Compression? */ + unsigned int old_vj :1; /* use old (short) form of VJ option? */ + unsigned int cflag :1; +#endif /* VJ_SUPPORT */ + unsigned int accept_local :1; /* accept peer's value for ouraddr */ + unsigned int accept_remote :1; /* accept peer's value for hisaddr */ +#if LWIP_DNS + unsigned int req_dns1 :1; /* Ask peer to send primary DNS address? */ + unsigned int req_dns2 :1; /* Ask peer to send secondary DNS address? */ +#endif /* LWIP_DNS */ + + u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ +#if LWIP_DNS + u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT + u16_t vj_protocol; /* protocol value to use in VJ option */ + u8_t maxslotindex; /* values for RFC1332 VJ compression neg. */ +#endif /* VJ_SUPPORT */ +} ipcp_options; + +#if 0 /* UNUSED, already defined by lwIP */ +char *ip_ntoa (u32_t); +#endif /* UNUSED, already defined by lwIP */ + +extern const struct protent ipcp_protent; + +#endif /* IPCP_H */ +#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ipv6cp.h b/Sming/third-party/lwip2/include/netif/ppp/ipv6cp.h new file mode 100644 index 0000000000..07d1ae3186 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ipv6cp.h @@ -0,0 +1,183 @@ +/* + * ipv6cp.h - PPP IPV6 Control Protocol. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Original version, based on RFC2023 : + + Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt + Économique ayant pour membres BULL S.A. et l'INRIA). + + Ce logiciel informatique est disponible aux conditions + usuelles dans la recherche, c'est-à-dire qu'il peut + être utilisé, copié, modifié, distribué à l'unique + condition que ce texte soit conservé afin que + l'origine de ce logiciel soit reconnue. + + Le nom de l'Institut National de Recherche en Informatique + et en Automatique (INRIA), de l'IMAG, ou d'une personne morale + ou physique ayant participé à l'élaboration de ce logiciel ne peut + être utilisé sans son accord préalable explicite. + + Ce logiciel est fourni tel quel sans aucune garantie, + support ou responsabilité d'aucune sorte. + Ce logiciel est dérivé de sources d'origine + "University of California at Berkeley" et + "Digital Equipment Corporation" couvertes par des copyrights. + + L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) + est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National + Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant + sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + + This work has been done in the context of GIE DYADE (joint R & D venture + between BULL S.A. and INRIA). + + This software is available with usual "research" terms + with the aim of retain credits of the software. + Permission to use, copy, modify and distribute this software for any + purpose and without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies, + and the name of INRIA, IMAG, or any contributor not be used in advertising + or publicity pertaining to this material without the prior explicit + permission. The software is provided "as is" without any + warranties, support or liabilities of any kind. + This software is derived from source code from + "University of California at Berkeley" and + "Digital Equipment Corporation" protected by copyrights. + + Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) + is a federation of seven research units funded by the CNRS, National + Polytechnic Institute of Grenoble and University Joseph Fourier. + The research unit in Software, Systems, Networks (LSR) is member of IMAG. +*/ + +/* + * Derived from : + * + * + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipv6cp.h,v 1.7 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPV6CP_H +#define IPV6CP_H + +#include "eui64.h" + +/* + * Options. + */ +#define CI_IFACEID 1 /* Interface Identifier */ +#ifdef IPV6CP_COMP +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* IPV6CP_COMP */ + +/* No compression types yet defined. + *#define IPV6CP_COMP 0x004f + */ +typedef struct ipv6cp_options { + unsigned int neg_ifaceid :1; /* Negotiate interface identifier? */ + unsigned int req_ifaceid :1; /* Ask peer to send interface identifier? */ + unsigned int accept_local :1; /* accept peer's value for iface id? */ + unsigned int opt_local :1; /* ourtoken set by option */ + unsigned int opt_remote :1; /* histoken set by option */ + unsigned int use_ip :1; /* use IP as interface identifier */ +#if 0 + unsigned int use_persistent :1; /* use uniquely persistent value for address */ +#endif +#ifdef IPV6CP_COMP + unsigned int neg_vj :1; /* Van Jacobson Compression? */ +#endif /* IPV6CP_COMP */ + +#ifdef IPV6CP_COMP + u_short vj_protocol; /* protocol value to use in VJ option */ +#endif /* IPV6CP_COMP */ + eui64_t ourid, hisid; /* Interface identifiers */ +} ipv6cp_options; + +extern const struct protent ipv6cp_protent; + +#endif /* IPV6CP_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/lcp.h b/Sming/third-party/lwip2/include/netif/ppp/lcp.h new file mode 100644 index 0000000000..12e2a05fc9 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/lcp.h @@ -0,0 +1,171 @@ +/* + * lcp.h - Link Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: lcp.h,v 1.20 2004/11/14 22:53:42 carlsonj Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef LCP_H +#define LCP_H + +#include "ppp.h" + +/* + * Options. + */ +#define CI_VENDOR 0 /* Vendor Specific */ +#define CI_MRU 1 /* Maximum Receive Unit */ +#define CI_ASYNCMAP 2 /* Async Control Character Map */ +#define CI_AUTHTYPE 3 /* Authentication Type */ +#define CI_QUALITY 4 /* Quality Protocol */ +#define CI_MAGICNUMBER 5 /* Magic Number */ +#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ +#define CI_FCSALTERN 9 /* FCS-Alternatives */ +#define CI_SDP 10 /* Self-Describing-Pad */ +#define CI_NUMBERED 11 /* Numbered-Mode */ +#define CI_CALLBACK 13 /* callback */ +#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF 18 /* short sequence numbers for multilink */ +#define CI_EPDISC 19 /* endpoint discriminator */ +#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ +#define CI_LDISC 23 /* Link-Discriminator */ +#define CI_LCPAUTH 24 /* LCP Authentication */ +#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ +#define CI_PREFELIS 26 /* Prefix Elision */ +#define CI_MPHDRFMT 27 /* MP Header Format */ +#define CI_I18N 28 /* Internationalization */ +#define CI_SDL 29 /* Simple Data Link */ + +/* + * LCP-specific packet types (code numbers). + */ +#define PROTREJ 8 /* Protocol Reject */ +#define ECHOREQ 9 /* Echo Request */ +#define ECHOREP 10 /* Echo Reply */ +#define DISCREQ 11 /* Discard Request */ +#define IDENTIF 12 /* Identification */ +#define TIMEREM 13 /* Time Remaining */ + +/* Value used as data for CI_CALLBACK option */ +#define CBCP_OPT 6 /* Use callback control protocol */ + +#if 0 /* moved to ppp_opts.h */ +#define DEFMRU 1500 /* Try for this */ +#define MINMRU 128 /* No MRUs below this */ +#define MAXMRU 16384 /* Normally limit MRU to this */ +#endif /* moved to ppp_opts.h */ + +/* An endpoint discriminator, used with multilink. */ +#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ +struct epdisc { + unsigned char class_; /* -- The word "class" is reserved in C++. */ + unsigned char length; + unsigned char value[MAX_ENDP_LEN]; +}; + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { + unsigned int passive :1; /* Don't die if we don't get a response */ + unsigned int silent :1; /* Wait for the other end to start first */ +#if 0 /* UNUSED */ + unsigned int restart :1; /* Restart vs. exit after close */ +#endif /* UNUSED */ + unsigned int neg_mru :1; /* Negotiate the MRU? */ + unsigned int neg_asyncmap :1; /* Negotiate the async map? */ +#if PAP_SUPPORT + unsigned int neg_upap :1; /* Ask for UPAP authentication? */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int neg_chap :1; /* Ask for CHAP authentication? */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int neg_eap :1; /* Ask for EAP authentication? */ +#endif /* EAP_SUPPORT */ + unsigned int neg_magicnumber :1; /* Ask for magic number? */ + unsigned int neg_pcompression :1; /* HDLC Protocol Field Compression? */ + unsigned int neg_accompression :1; /* HDLC Address/Control Field Compression? */ +#if LQR_SUPPORT + unsigned int neg_lqr :1; /* Negotiate use of Link Quality Reports */ +#endif /* LQR_SUPPORT */ + unsigned int neg_cbcp :1; /* Negotiate use of CBCP */ +#ifdef HAVE_MULTILINK + unsigned int neg_mrru :1; /* negotiate multilink MRRU */ +#endif /* HAVE_MULTILINK */ + unsigned int neg_ssnhf :1; /* negotiate short sequence numbers */ + unsigned int neg_endpoint :1; /* negotiate endpoint discriminator */ + + u16_t mru; /* Value of MRU */ +#ifdef HAVE_MULTILINK + u16_t mrru; /* Value of MRRU, and multilink enable */ +#endif /* MULTILINK */ +#if CHAP_SUPPORT + u8_t chap_mdtype; /* which MD types (hashing algorithm) */ +#endif /* CHAP_SUPPORT */ + u32_t asyncmap; /* Value of async map */ + u32_t magicnumber; + u8_t numloops; /* Number of loops during magic number neg. */ +#if LQR_SUPPORT + u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ +#endif /* LQR_SUPPORT */ + struct epdisc endpoint; /* endpoint discriminator */ +} lcp_options; + +void lcp_open(ppp_pcb *pcb); +void lcp_close(ppp_pcb *pcb, const char *reason); +void lcp_lowerup(ppp_pcb *pcb); +void lcp_lowerdown(ppp_pcb *pcb); +void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len); /* send protocol reject */ + +extern const struct protent lcp_protent; + +#if 0 /* moved to ppp_opts.h */ +/* Default number of times we receive our magic number from the peer + before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 +#endif /* moved to ppp_opts.h */ + +#endif /* LCP_H */ +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/magic.h b/Sming/third-party/lwip2/include/netif/ppp/magic.h new file mode 100644 index 0000000000..a2a9b530e5 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/magic.h @@ -0,0 +1,122 @@ +/* + * magic.h - PPP Magic Number definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $ + */ +/***************************************************************************** +* randm.h - Random number generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-05-29 Guy Lancaster , Global Election Systems Inc. +* Extracted from avos. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MAGIC_H +#define MAGIC_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* + * Initialize the random number generator. + */ +void magic_init(void); + +/* + * Randomize our random seed value. To be called for truely random events + * such as user operations and network traffic. + */ +void magic_randomize(void); + +/* + * Return a new random number. + */ +u32_t magic(void); /* Returns the next magic number */ + +/* + * Fill buffer with random bytes + * + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using magic_churnrand(). + * Thus it's important to make sure that the results of this are not + * published directly because one could predict the next result to at + * least some degree. Also, it's important to get a good seed before + * the first use. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len); + +/* + * Return a new random number between 0 and (2^pow)-1 included. + */ +u32_t magic_pow(u8_t pow); + +#endif /* MAGIC_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/mppe.h b/Sming/third-party/lwip2/include/netif/ppp/mppe.h new file mode 100644 index 0000000000..1ae8a5d924 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/mppe.h @@ -0,0 +1,173 @@ +/* + * mppe.h - Definitions for MPPE + * + * Copyright (c) 2008 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MPPE_H +#define MPPE_H + +#include "netif/ppp/pppcrypt.h" + +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a lwip_htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + const u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) + +/* Shared MPPE padding between MSCHAP and MPPE */ +#define SHA1_PAD_SIZE 40 + +static const u8_t mppe_sha1_pad1[SHA1_PAD_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const u8_t mppe_sha1_pad2[SHA1_PAD_SIZE] = { + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 +}; + +/* + * State for an MPPE (de)compressor. + */ +typedef struct ppp_mppe_state { + lwip_arc4_context arc4; + u8_t master_key[MPPE_MAX_KEY_LEN]; + u8_t session_key[MPPE_MAX_KEY_LEN]; + u8_t keylen; /* key length in bytes */ + /* NB: 128-bit == 16, 40-bit == 8! + * If we want to support 56-bit, the unit has to change to bits + */ + u8_t bits; /* MPPE control bits */ + u16_t ccount; /* 12-bit coherency count (seqno) */ + u16_t sanity_errors; /* take down LCP if too many */ + unsigned int stateful :1; /* stateful mode flag */ + unsigned int discard :1; /* stateful mode packet loss flag */ +} ppp_mppe_state; + +void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key); +void mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options); +void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol); +void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb); + +#endif /* MPPE_H */ +#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/polarssl/arc4.h b/Sming/third-party/lwip2/include/netif/ppp/polarssl/arc4.h new file mode 100644 index 0000000000..4af724cd90 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/polarssl/arc4.h @@ -0,0 +1,81 @@ +/** + * \file arc4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_ARC4 + +#ifndef LWIP_INCLUDED_POLARSSL_ARC4_H +#define LWIP_INCLUDED_POLARSSL_ARC4_H + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +arc4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be initialized + * \param key the secret key + * \param keylen length of the key + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param buf buffer to be processed + * \param buflen amount of data in buf + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/polarssl/des.h b/Sming/third-party/lwip2/include/netif/ppp/polarssl/des.h new file mode 100644 index 0000000000..e893890ed7 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/polarssl/des.h @@ -0,0 +1,92 @@ +/** + * \file des.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_DES + +#ifndef LWIP_INCLUDED_POLARSSL_DES_H +#define LWIP_INCLUDED_POLARSSL_DES_H + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< DES subkeys */ +} +des_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + */ +void des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_DES_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/polarssl/md4.h b/Sming/third-party/lwip2/include/netif/ppp/polarssl/md4.h new file mode 100644 index 0000000000..570445687e --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/polarssl/md4.h @@ -0,0 +1,97 @@ +/** + * \file md4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD4 + +#ifndef LWIP_INCLUDED_POLARSSL_MD4_H +#define LWIP_INCLUDED_POLARSSL_MD4_H + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/polarssl/md5.h b/Sming/third-party/lwip2/include/netif/ppp/polarssl/md5.h new file mode 100644 index 0000000000..1244011890 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/polarssl/md5.h @@ -0,0 +1,96 @@ +/** + * \file md5.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD5 + +#ifndef LWIP_INCLUDED_POLARSSL_MD5_H +#define LWIP_INCLUDED_POLARSSL_MD5_H + +/** + * \brief MD5 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD5_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/polarssl/sha1.h b/Sming/third-party/lwip2/include/netif/ppp/polarssl/sha1.h new file mode 100644 index 0000000000..a4c53e07c5 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/polarssl/sha1.h @@ -0,0 +1,96 @@ +/** + * \file sha1.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_SHA1 + +#ifndef LWIP_INCLUDED_POLARSSL_SHA1_H +#define LWIP_INCLUDED_POLARSSL_SHA1_H + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ppp.h b/Sming/third-party/lwip2/include/netif/ppp/ppp.h new file mode 100644 index 0000000000..d9ea097efd --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ppp.h @@ -0,0 +1,690 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_H +#define PPP_H + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#if PPP_IPV6_SUPPORT +#include "lwip/ip6_addr.h" +#endif /* PPP_IPV6_SUPPORT */ + +/* Disable non-working or rarely used PPP feature, so rarely that we don't want to bloat ppp_opts.h with them */ +#ifndef PPP_OPTIONS +#define PPP_OPTIONS 0 +#endif + +#ifndef PPP_NOTIFY +#define PPP_NOTIFY 0 +#endif + +#ifndef PPP_REMOTENAME +#define PPP_REMOTENAME 0 +#endif + +#ifndef PPP_IDLETIMELIMIT +#define PPP_IDLETIMELIMIT 0 +#endif + +#ifndef PPP_LCP_ADAPTIVE +#define PPP_LCP_ADAPTIVE 0 +#endif + +#ifndef PPP_MAXCONNECT +#define PPP_MAXCONNECT 0 +#endif + +#ifndef PPP_ALLOWED_ADDRS +#define PPP_ALLOWED_ADDRS 0 +#endif + +#ifndef PPP_PROTOCOLNAME +#define PPP_PROTOCOLNAME 0 +#endif + +#ifndef PPP_STATS_SUPPORT +#define PPP_STATS_SUPPORT 0 +#endif + +#ifndef DEFLATE_SUPPORT +#define DEFLATE_SUPPORT 0 +#endif + +#ifndef BSDCOMPRESS_SUPPORT +#define BSDCOMPRESS_SUPPORT 0 +#endif + +#ifndef PREDICTOR_SUPPORT +#define PREDICTOR_SUPPORT 0 +#endif + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ + +/* + * Values for phase. + */ +#define PPP_PHASE_DEAD 0 +#define PPP_PHASE_MASTER 1 +#define PPP_PHASE_HOLDOFF 2 +#define PPP_PHASE_INITIALIZE 3 +#define PPP_PHASE_SERIALCONN 4 +#define PPP_PHASE_DORMANT 5 +#define PPP_PHASE_ESTABLISH 6 +#define PPP_PHASE_AUTHENTICATE 7 +#define PPP_PHASE_CALLBACK 8 +#define PPP_PHASE_NETWORK 9 +#define PPP_PHASE_RUNNING 10 +#define PPP_PHASE_TERMINATE 11 +#define PPP_PHASE_DISCONNECT 12 + +/* Error codes. */ +#define PPPERR_NONE 0 /* No error. */ +#define PPPERR_PARAM 1 /* Invalid parameter. */ +#define PPPERR_OPEN 2 /* Unable to open PPP session. */ +#define PPPERR_DEVICE 3 /* Invalid I/O device for PPP. */ +#define PPPERR_ALLOC 4 /* Unable to allocate resources. */ +#define PPPERR_USER 5 /* User interrupt. */ +#define PPPERR_CONNECT 6 /* Connection lost. */ +#define PPPERR_AUTHFAIL 7 /* Failed authentication challenge. */ +#define PPPERR_PROTOCOL 8 /* Failed to meet protocol. */ +#define PPPERR_PEERDEAD 9 /* Connection timeout */ +#define PPPERR_IDLETIMEOUT 10 /* Idle Timeout */ +#define PPPERR_CONNECTTIME 11 /* Max connect time reached */ +#define PPPERR_LOOPBACK 12 /* Loopback detected */ + +/* Whether auth support is enabled at all */ +#define PPP_AUTH_SUPPORT (PAP_SUPPORT || CHAP_SUPPORT || EAP_SUPPORT) + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Other headers require ppp_pcb definition for prototypes, but ppp_pcb + * require some structure definition from other headers as well, we are + * fixing the dependency loop here by declaring the ppp_pcb type then + * by including headers containing necessary struct definition for ppp_pcb + */ +typedef struct ppp_pcb_s ppp_pcb; + +/* Type definitions for BSD code. */ +#ifndef __u_char_defined +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; +#endif + +#include "fsm.h" +#include "lcp.h" +#if CCP_SUPPORT +#include "ccp.h" +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT +#include "mppe.h" +#endif /* MPPE_SUPPORT */ +#if PPP_IPV4_SUPPORT +#include "ipcp.h" +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +#include "ipv6cp.h" +#endif /* PPP_IPV6_SUPPORT */ +#if PAP_SUPPORT +#include "upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "eap.h" +#endif /* EAP_SUPPORT */ +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ + +/* Link status callback function prototype */ +typedef void (*ppp_link_status_cb_fn)(ppp_pcb *pcb, int err_code, void *ctx); + +/* + * PPP configuration. + */ +typedef struct ppp_settings_s { + +#if PPP_SERVER && PPP_AUTH_SUPPORT + unsigned int auth_required :1; /* Peer is required to authenticate */ + unsigned int null_login :1; /* Username of "" and a password of "" are acceptable */ +#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ +#if PPP_REMOTENAME + unsigned int explicit_remote :1; /* remote_name specified with remotename opt */ +#endif /* PPP_REMOTENAME */ +#if PAP_SUPPORT + unsigned int refuse_pap :1; /* Don't proceed auth. with PAP */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int refuse_chap :1; /* Don't proceed auth. with CHAP */ +#endif /* CHAP_SUPPORT */ +#if MSCHAP_SUPPORT + unsigned int refuse_mschap :1; /* Don't proceed auth. with MS-CHAP */ + unsigned int refuse_mschap_v2 :1; /* Don't proceed auth. with MS-CHAPv2 */ +#endif /* MSCHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int refuse_eap :1; /* Don't proceed auth. with EAP */ +#endif /* EAP_SUPPORT */ +#if LWIP_DNS + unsigned int usepeerdns :1; /* Ask peer for DNS adds */ +#endif /* LWIP_DNS */ + unsigned int persist :1; /* Persist mode, always try to open the connection */ +#if PRINTPKT_SUPPORT + unsigned int hide_password :1; /* Hide password in dumped packets */ +#endif /* PRINTPKT_SUPPORT */ + unsigned int noremoteip :1; /* Let him have no IP address */ + unsigned int lax_recv :1; /* accept control chars in asyncmap */ + unsigned int noendpoint :1; /* don't send/accept endpoint discriminator */ +#if PPP_LCP_ADAPTIVE + unsigned int lcp_echo_adaptive :1; /* request echo only if the link was idle */ +#endif /* PPP_LCP_ADAPTIVE */ +#if MPPE_SUPPORT + unsigned int require_mppe :1; /* Require MPPE (Microsoft Point to Point Encryption) */ + unsigned int refuse_mppe_40 :1; /* Allow MPPE 40-bit mode? */ + unsigned int refuse_mppe_128 :1; /* Allow MPPE 128-bit mode? */ + unsigned int refuse_mppe_stateful :1; /* Allow MPPE stateful mode? */ +#endif /* MPPE_SUPPORT */ + + u16_t listen_time; /* time to listen first (ms), waiting for peer to send LCP packet */ + +#if PPP_IDLETIMELIMIT + u16_t idle_time_limit; /* Disconnect if idle for this many seconds */ +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT + u32_t maxconnect; /* Maximum connect time (seconds) */ +#endif /* PPP_MAXCONNECT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ + const char *user; /* Username for PAP */ + const char *passwd; /* Password for PAP, secret for CHAP */ +#if PPP_REMOTENAME + char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ +#endif /* PPP_REMOTENAME */ + +#if PAP_SUPPORT + u8_t pap_timeout_time; /* Timeout (seconds) for auth-req retrans. */ + u8_t pap_max_transmits; /* Number of auth-reqs sent */ +#if PPP_SERVER + u8_t pap_req_timeout; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* PAP_SUPPPORT */ + +#if CHAP_SUPPORT + u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ + u8_t chap_max_transmits; /* max # times to send challenge */ +#if PPP_SERVER + u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPPORT */ + +#if EAP_SUPPORT + u8_t eap_req_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_allow_req; /* Max Requests allowed */ +#if PPP_SERVER + u8_t eap_timeout_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_max_transmits; /* Max Requests allowed */ +#endif /* PPP_SERVER */ +#endif /* EAP_SUPPORT */ + +#endif /* PPP_AUTH_SUPPORT */ + + u8_t fsm_timeout_time; /* Timeout time in seconds */ + u8_t fsm_max_conf_req_transmits; /* Maximum Configure-Request transmissions */ + u8_t fsm_max_term_transmits; /* Maximum Terminate-Request transmissions */ + u8_t fsm_max_nak_loops; /* Maximum number of nak loops tolerated */ + + u8_t lcp_loopbackfail; /* Number of times we receive our magic number from the peer + before deciding the link is looped-back. */ + u8_t lcp_echo_interval; /* Interval between LCP echo-requests */ + u8_t lcp_echo_fails; /* Tolerance to unanswered echo-requests */ + +} ppp_settings; + +#if PPP_SERVER +struct ppp_addrs { +#if PPP_IPV4_SUPPORT + ip4_addr_t our_ipaddr, his_ipaddr, netmask; +#if LWIP_DNS + ip4_addr_t dns1, dns2; +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + ip6_addr_t our6_ipaddr, his6_ipaddr; +#endif /* PPP_IPV6_SUPPORT */ +}; +#endif /* PPP_SERVER */ + +/* + * PPP interface control block. + */ +struct ppp_pcb_s { + ppp_settings settings; + const struct link_callbacks *link_cb; + void *link_ctx_cb; + void (*link_status_cb)(ppp_pcb *pcb, int err_code, void *ctx); /* Status change callback */ +#if PPP_NOTIFY_PHASE + void (*notify_phase_cb)(ppp_pcb *pcb, u8_t phase, void *ctx); /* Notify phase callback */ +#endif /* PPP_NOTIFY_PHASE */ + void *ctx_cb; /* Callbacks optional pointer */ + struct netif *netif; /* PPP interface */ + u8_t phase; /* where the link is at */ + u8_t err_code; /* Code indicating why interface is down. */ + + /* flags */ +#if PPP_IPV4_SUPPORT + unsigned int ask_for_local :1; /* request our address from peer */ + unsigned int ipcp_is_open :1; /* haven't called np_finished() */ + unsigned int ipcp_is_up :1; /* have called ipcp_up() */ + unsigned int if4_up :1; /* True when the IPv4 interface is up. */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp_set :1; /* Have created proxy arp entry */ +#endif /* UNUSED - PROXY ARP */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + unsigned int ipv6cp_is_up :1; /* have called ip6cp_up() */ + unsigned int if6_up :1; /* True when the IPv6 interface is up. */ +#endif /* PPP_IPV6_SUPPORT */ + unsigned int lcp_echo_timer_running :1; /* set if a timer is running */ +#if VJ_SUPPORT + unsigned int vj_enabled :1; /* Flag indicating VJ compression enabled. */ +#endif /* VJ_SUPPORT */ +#if CCP_SUPPORT + unsigned int ccp_all_rejected :1; /* we rejected all peer's options */ +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT + unsigned int mppe_keys_set :1; /* Have the MPPE keys been set? */ +#endif /* MPPE_SUPPORT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ +#if PPP_SERVER && defined(HAVE_MULTILINK) + char peer_authname[MAXNAMELEN + 1]; /* The name by which the peer authenticated itself to us. */ +#endif /* PPP_SERVER && defined(HAVE_MULTILINK) */ + u16_t auth_pending; /* Records which authentication operations haven't completed yet. */ + u16_t auth_done; /* Records which authentication operations have been completed. */ + +#if PAP_SUPPORT + upap_state upap; /* PAP data */ +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + chap_client_state chap_client; /* CHAP client data */ +#if PPP_SERVER + chap_server_state chap_server; /* CHAP server data */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if EAP_SUPPORT + eap_state eap; /* EAP data */ +#endif /* EAP_SUPPORT */ +#endif /* PPP_AUTH_SUPPORT */ + + fsm lcp_fsm; /* LCP fsm structure */ + lcp_options lcp_wantoptions; /* Options that we want to request */ + lcp_options lcp_gotoptions; /* Options that peer ack'd */ + lcp_options lcp_allowoptions; /* Options we allow peer to request */ + lcp_options lcp_hisoptions; /* Options that we ack'd */ + u16_t peer_mru; /* currently negotiated peer MRU */ + u8_t lcp_echos_pending; /* Number of outstanding echo msgs */ + u8_t lcp_echo_number; /* ID number of next echo frame */ + + u8_t num_np_open; /* Number of network protocols which we have opened. */ + u8_t num_np_up; /* Number of network protocols which have come up. */ + +#if VJ_SUPPORT + struct vjcompress vj_comp; /* Van Jacobson compression header. */ +#endif /* VJ_SUPPORT */ + +#if CCP_SUPPORT + fsm ccp_fsm; /* CCP fsm structure */ + ccp_options ccp_wantoptions; /* what to request the peer to use */ + ccp_options ccp_gotoptions; /* what the peer agreed to do */ + ccp_options ccp_allowoptions; /* what we'll agree to do */ + ccp_options ccp_hisoptions; /* what we agreed to do */ + u8_t ccp_localstate; /* Local state (mainly for handling reset-reqs and reset-acks). */ + u8_t ccp_receive_method; /* Method chosen on receive path */ + u8_t ccp_transmit_method; /* Method chosen on transmit path */ +#if MPPE_SUPPORT + ppp_mppe_state mppe_comp; /* MPPE "compressor" structure */ + ppp_mppe_state mppe_decomp; /* MPPE "decompressor" structure */ +#endif /* MPPE_SUPPORT */ +#endif /* CCP_SUPPORT */ + +#if PPP_IPV4_SUPPORT + fsm ipcp_fsm; /* IPCP fsm structure */ + ipcp_options ipcp_wantoptions; /* Options that we want to request */ + ipcp_options ipcp_gotoptions; /* Options that peer ack'd */ + ipcp_options ipcp_allowoptions; /* Options we allow peer to request */ + ipcp_options ipcp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT + fsm ipv6cp_fsm; /* IPV6CP fsm structure */ + ipv6cp_options ipv6cp_wantoptions; /* Options that we want to request */ + ipv6cp_options ipv6cp_gotoptions; /* Options that peer ack'd */ + ipv6cp_options ipv6cp_allowoptions; /* Options we allow peer to request */ + ipv6cp_options ipv6cp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV6_SUPPORT */ +}; + +/************************ + *** PUBLIC FUNCTIONS *** + ************************/ + +/* + * WARNING: For multi-threads environment, all ppp_set_* functions most + * only be called while the PPP is in the dead phase (i.e. disconnected). + */ + +#if PPP_AUTH_SUPPORT +/* + * Set PPP authentication. + * + * Warning: Using PPPAUTHTYPE_ANY might have security consequences. + * RFC 1994 says: + * + * In practice, within or associated with each PPP server, there is a + * database which associates "user" names with authentication + * information ("secrets"). It is not anticipated that a particular + * named user would be authenticated by multiple methods. This would + * make the user vulnerable to attacks which negotiate the least secure + * method from among a set (such as PAP rather than CHAP). If the same + * secret was used, PAP would reveal the secret to be used later with + * CHAP. + * + * Instead, for each user name there should be an indication of exactly + * one method used to authenticate that user name. If a user needs to + * make use of different authentication methods under different + * circumstances, then distinct user names SHOULD be employed, each of + * which identifies exactly one authentication method. + * + * Default is none auth type, unset (NULL) user and passwd. + */ +#define PPPAUTHTYPE_NONE 0x00 +#define PPPAUTHTYPE_PAP 0x01 +#define PPPAUTHTYPE_CHAP 0x02 +#define PPPAUTHTYPE_MSCHAP 0x04 +#define PPPAUTHTYPE_MSCHAP_V2 0x08 +#define PPPAUTHTYPE_EAP 0x10 +#define PPPAUTHTYPE_ANY 0xff +void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd); + +/* + * If set, peer is required to authenticate. This is mostly necessary for PPP server support. + * + * Default is false. + */ +#define ppp_set_auth_required(ppp, boolval) (ppp->settings.auth_required = boolval) +#endif /* PPP_AUTH_SUPPORT */ + +#if PPP_IPV4_SUPPORT +/* + * Set PPP interface "our" and "his" IPv4 addresses. This is mostly necessary for PPP server + * support but it can also be used on a PPP link where each side choose its own IP address. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_ouraddr(ppp, addr) do { ppp->ipcp_wantoptions.ouraddr = ip4_addr_get_u32(addr); \ + ppp->ask_for_local = ppp->ipcp_wantoptions.ouraddr != 0; } while(0) +#define ppp_set_ipcp_hisaddr(ppp, addr) (ppp->ipcp_wantoptions.hisaddr = ip4_addr_get_u32(addr)) +#if LWIP_DNS +/* + * Set DNS server addresses that are sent if the peer asks for them. This is mostly necessary + * for PPP server support. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_dnsaddr(ppp, index, addr) (ppp->ipcp_allowoptions.dnsaddr[index] = ip4_addr_get_u32(addr)) + +/* + * If set, we ask the peer for up to 2 DNS server addresses. Received DNS server addresses are + * registered using the dns_setserver() function. + * + * Default is false. + */ +#define ppp_set_usepeerdns(ppp, boolval) (ppp->settings.usepeerdns = boolval) +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ + +#if MPPE_SUPPORT +/* Disable MPPE (Microsoft Point to Point Encryption). This parameter is exclusive. */ +#define PPP_MPPE_DISABLE 0x00 +/* Require the use of MPPE (Microsoft Point to Point Encryption). */ +#define PPP_MPPE_ENABLE 0x01 +/* Allow MPPE to use stateful mode. Stateless mode is still attempted first. */ +#define PPP_MPPE_ALLOW_STATEFUL 0x02 +/* Refuse the use of MPPE with 40-bit encryption. Conflict with PPP_MPPE_REFUSE_128. */ +#define PPP_MPPE_REFUSE_40 0x04 +/* Refuse the use of MPPE with 128-bit encryption. Conflict with PPP_MPPE_REFUSE_40. */ +#define PPP_MPPE_REFUSE_128 0x08 +/* + * Set MPPE configuration + * + * Default is disabled. + */ +void ppp_set_mppe(ppp_pcb *pcb, u8_t flags); +#endif /* MPPE_SUPPORT */ + +/* + * Wait for up to intval milliseconds for a valid PPP packet from the peer. + * At the end of this time, or when a valid PPP packet is received from the + * peer, we commence negotiation by sending our first LCP packet. + * + * Default is 0. + */ +#define ppp_set_listen_time(ppp, intval) (ppp->settings.listen_time = intval) + +/* + * If set, we will attempt to initiate a connection but if no reply is received from + * the peer, we will then just wait passively for a valid LCP packet from the peer. + * + * Default is false. + */ +#define ppp_set_passive(ppp, boolval) (ppp->lcp_wantoptions.passive = boolval) + +/* + * If set, we will not transmit LCP packets to initiate a connection until a valid + * LCP packet is received from the peer. This is what we usually call the server mode. + * + * Default is false. + */ +#define ppp_set_silent(ppp, boolval) (ppp->lcp_wantoptions.silent = boolval) + +/* + * If set, enable protocol field compression negotiation in both the receive and + * the transmit direction. + * + * Default is true. + */ +#define ppp_set_neg_pcomp(ppp, boolval) (ppp->lcp_wantoptions.neg_pcompression = \ + ppp->lcp_allowoptions.neg_pcompression = boolval) + +/* + * If set, enable Address/Control compression in both the receive and the transmit + * direction. + * + * Default is true. + */ +#define ppp_set_neg_accomp(ppp, boolval) (ppp->lcp_wantoptions.neg_accompression = \ + ppp->lcp_allowoptions.neg_accompression = boolval) + +/* + * If set, enable asyncmap negotiation. Otherwise forcing all control characters to + * be escaped for both the transmit and the receive direction. + * + * Default is true. + */ +#define ppp_set_neg_asyncmap(ppp, boolval) (ppp->lcp_wantoptions.neg_asyncmap = \ + ppp->lcp_allowoptions.neg_asyncmap = boolval) + +/* + * This option sets the Async-Control-Character-Map (ACCM) for this end of the link. + * The ACCM is a set of 32 bits, one for each of the ASCII control characters with + * values from 0 to 31, where a 1 bit indicates that the corresponding control + * character should not be used in PPP packets sent to this system. The map is + * an unsigned 32 bits integer where the least significant bit (00000001) represents + * character 0 and the most significant bit (80000000) represents character 31. + * We will then ask the peer to send these characters as a 2-byte escape sequence. + * + * Default is 0. + */ +#define ppp_set_asyncmap(ppp, intval) (ppp->lcp_wantoptions.asyncmap = intval) + +/* + * Set a PPP interface as the default network interface + * (used to output all packets for which no specific route is found). + */ +#define ppp_set_default(ppp) netif_set_default(ppp->netif) + +#if PPP_NOTIFY_PHASE +/* + * Set a PPP notify phase callback. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +typedef void (*ppp_notify_phase_cb_fn)(ppp_pcb *pcb, u8_t phase, void *ctx); +void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ + +/* + * Initiate a PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * Holdoff is the time to wait (in seconds) before initiating + * the connection. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff); + +#if PPP_SERVER +/* + * Listen for an incoming PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +/* + * Initiate the end of a PPP connection. + * Any outstanding packets in the queues are dropped. + * + * Setting nocarrier to 1 close the PPP connection without initiating the + * shutdown procedure. Always using nocarrier = 0 is still recommended, + * this is going to take a little longer time if your link is down, but + * is a safer choice for the PPP state machine. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_close(ppp_pcb *pcb, u8_t nocarrier); + +/* + * Release the control block. + * + * This can only be called if PPP is in the dead phase. + * + * You must use ppp_close() before if you wish to terminate + * an established PPP session. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_free(ppp_pcb *pcb); + +/* + * PPP IOCTL commands. + * + * Get the up status - 0 for down, non-zero for up. The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 0 + +/* + * Get the PPP error code. The argument must point to an int. + * Returns a PPPERR_* value. + */ +#define PPPCTLG_ERRCODE 1 + +/* + * Get the fd associated with a PPP over serial + */ +#define PPPCTLG_FD 2 + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. + */ +err_t ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +/* Get the PPP netif interface */ +#define ppp_netif(ppp) (ppp->netif) + +/* Set an lwIP-style status-callback for the selected PPP device */ +#define ppp_set_netif_statuscallback(ppp, status_cb) \ + netif_set_status_callback(ppp->netif, status_cb); + +/* Set an lwIP-style link-callback for the selected PPP device */ +#define ppp_set_netif_linkcallback(ppp, link_cb) \ + netif_set_link_callback(ppp->netif, link_cb); + +#endif /* PPP_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ppp_impl.h b/Sming/third-party/lwip2/include/netif/ppp/ppp_impl.h new file mode 100644 index 0000000000..1d4c7742f3 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ppp_impl.h @@ -0,0 +1,629 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +#ifndef LWIP_HDR_PPP_IMPL_H +#define LWIP_HDR_PPP_IMPL_H + +#include "netif/ppp/ppp_opts.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifdef PPP_INCLUDE_SETTINGS_HEADER +#include "ppp_settings.h" +#endif + +#include /* formats */ +#include +#include +#include /* strtol() */ + +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/timeouts.h" + +#include "ppp.h" +#include "pppdebug.h" + +/* + * Memory used for control packets. + * + * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we + * cannot figure out how much we are going to use before filling the buffer. + */ +#if PPP_USE_PBUF_RAM +#define PPP_CTRL_PBUF_TYPE PBUF_RAM +#define PPP_CTRL_PBUF_MAX_SIZE 512 +#else /* PPP_USE_PBUF_RAM */ +#define PPP_CTRL_PBUF_TYPE PBUF_POOL +#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE +#endif /* PPP_USE_PBUF_RAM */ + +/* + * The basic PPP frame. + */ +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#if 0 /* UNUSED */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#endif /* UNUSED */ +#if VJ_SUPPORT +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#endif /* VJ_SUPPORT */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_COMP 0xfd /* compressed packet */ +#endif /* CCP_SUPPORT */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#if 0 /* UNUSED */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#endif /* UNUSED */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#endif /* ECP_SUPPORT */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#if PAP_SUPPORT +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#endif /* LQR_SUPPORT */ +#if CHAP_SUPPORT +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#endif /* CBCP_SUPPORT */ +#if EAP_SUPPORT +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ +#endif /* EAP_SUPPORT */ + +/* + * The following struct gives the addresses of procedures to call + * for a particular lower link level protocol. + */ +struct link_callbacks { + /* Start a connection (e.g. Initiate discovery phase) */ + void (*connect) (ppp_pcb *pcb, void *ctx); +#if PPP_SERVER + /* Listen for an incoming connection (Passive mode) */ + void (*listen) (ppp_pcb *pcb, void *ctx); +#endif /* PPP_SERVER */ + /* End a connection (i.e. initiate disconnect phase) */ + void (*disconnect) (ppp_pcb *pcb, void *ctx); + /* Free lower protocol control block */ + err_t (*free) (ppp_pcb *pcb, void *ctx); + /* Write a pbuf to a ppp link, only used from PPP functions to send PPP packets. */ + err_t (*write)(ppp_pcb *pcb, void *ctx, struct pbuf *p); + /* Send a packet from lwIP core (IPv4 or IPv6) */ + err_t (*netif_output)(ppp_pcb *pcb, void *ctx, struct pbuf *p, u_short protocol); + /* configure the transmit-side characteristics of the PPP interface */ + void (*send_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); + /* confire the receive-side characteristics of the PPP interface */ + void (*recv_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); +}; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics. + */ +#if PPP_STATS_SUPPORT +struct pppstat { + unsigned int ppp_ibytes; /* bytes received */ + unsigned int ppp_ipackets; /* packets received */ + unsigned int ppp_ierrors; /* receive errors */ + unsigned int ppp_obytes; /* bytes sent */ + unsigned int ppp_opackets; /* packets sent */ + unsigned int ppp_oerrors; /* transmit errors */ +}; + +#if VJ_SUPPORT +struct vjstat { + unsigned int vjs_packets; /* outbound packets */ + unsigned int vjs_compressed; /* outbound compressed packets */ + unsigned int vjs_searches; /* searches for connection state */ + unsigned int vjs_misses; /* times couldn't find conn. state */ + unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ + unsigned int vjs_compressedin; /* inbound compressed packets */ + unsigned int vjs_errorin; /* inbound unknown type packets */ + unsigned int vjs_tossed; /* inbound packets tossed because of error */ +}; +#endif /* VJ_SUPPORT */ + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ +#if VJ_SUPPORT + struct vjstat vj; /* VJ header compression statistics */ +#endif /* VJ_SUPPORT */ +}; + +#if CCP_SUPPORT +struct compstat { + unsigned int unc_bytes; /* total uncompressed bytes */ + unsigned int unc_packets; /* total uncompressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned int comp_packets; /* compressed packets */ + unsigned int inc_bytes; /* incompressible bytes */ + unsigned int inc_packets; /* incompressible packets */ + unsigned int ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; +#endif /* CCP_SUPPORT */ + +#endif /* PPP_STATS_SUPPORT */ + +#if PPP_IDLETIMELIMIT +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; +#endif /* PPP_IDLETIMELIMIT */ + +/* values for epdisc.class */ +#define EPD_NULL 0 /* null discriminator, no data */ +#define EPD_LOCAL 1 +#define EPD_IP 2 +#define EPD_MAC 3 +#define EPD_MAGIC 4 +#define EPD_PHONENUM 5 + +/* + * Global variables. + */ +#ifdef HAVE_MULTILINK +extern u8_t multilink; /* enable multilink operation */ +extern u8_t doing_multilink; +extern u8_t multilink_master; +extern u8_t bundle_eof; +extern u8_t bundle_terminating; +#endif + +#ifdef MAXOCTETS +extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ +extern int maxoctets_dir; /* Direction : + 0 - in+out (default) + 1 - in + 2 - out + 3 - max(in,out) */ +extern int maxoctets_timeout; /* Timeout for check of octets limit */ +#define PPP_OCTETS_DIRECTION_SUM 0 +#define PPP_OCTETS_DIRECTION_IN 1 +#define PPP_OCTETS_DIRECTION_OUT 2 +#define PPP_OCTETS_DIRECTION_MAXOVERAL 3 +/* same as previos, but little different on RADIUS side */ +#define PPP_OCTETS_DIRECTION_MAXSESSION 4 +#endif + +/* Data input may be used by CCP and ECP, remove this entry + * from struct protent to save some flash + */ +#define PPP_DATAINPUT 0 + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { + u_short protocol; /* PPP protocol number */ + /* Initialization procedure */ + void (*init) (ppp_pcb *pcb); + /* Process a received packet */ + void (*input) (ppp_pcb *pcb, u_char *pkt, int len); + /* Process a received protocol-reject */ + void (*protrej) (ppp_pcb *pcb); + /* Lower layer has come up */ + void (*lowerup) (ppp_pcb *pcb); + /* Lower layer has gone down */ + void (*lowerdown) (ppp_pcb *pcb); + /* Open the protocol */ + void (*open) (ppp_pcb *pcb); + /* Close the protocol */ + void (*close) (ppp_pcb *pcb, const char *reason); +#if PRINTPKT_SUPPORT + /* Print a packet in readable form */ + int (*printpkt) (const u_char *pkt, int len, + void (*printer) (void *, const char *, ...), + void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + /* Process a received data packet */ + void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len); +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + const char *name; /* Text name of protocol */ + const char *data_name; /* Text name of corresponding data protocol */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + option_t *options; /* List of command-line options */ + /* Check requested options, assign defaults */ + void (*check_options) (void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + /* Configure interface for demand-dial */ + int (*demand_conf) (int unit); + /* Say whether to bring up link for this pkt */ + int (*active_pkt) (u_char *pkt, int len); +#endif /* DEMAND_SUPPORT */ +}; + +/* Table of pointers to supported protocols */ +extern const struct protent* const protocols[]; + + +/* Values for auth_pending, auth_done */ +#if PAP_SUPPORT +#define PAP_WITHPEER 0x1 +#define PAP_PEER 0x2 +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#define CHAP_WITHPEER 0x4 +#define CHAP_PEER 0x8 +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#define EAP_WITHPEER 0x10 +#define EAP_PEER 0x20 +#endif /* EAP_SUPPORT */ + +/* Values for auth_done only */ +#if CHAP_SUPPORT +#define CHAP_MD5_WITHPEER 0x40 +#define CHAP_MD5_PEER 0x80 +#if MSCHAP_SUPPORT +#define CHAP_MS_SHIFT 8 /* LSB position for MS auths */ +#define CHAP_MS_WITHPEER 0x100 +#define CHAP_MS_PEER 0x200 +#define CHAP_MS2_WITHPEER 0x400 +#define CHAP_MS2_PEER 0x800 +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ + +/* Supported CHAP protocols */ +#if CHAP_SUPPORT + +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) +#else /* MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MD5) +#endif /* MSCHAP_SUPPORT */ + +#else /* CHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_NONE) +#endif /* CHAP_SUPPORT */ + +#if PPP_STATS_SUPPORT +/* + * PPP statistics structure + */ +struct pppd_stats { + unsigned int bytes_in; + unsigned int bytes_out; + unsigned int pkts_in; + unsigned int pkts_out; +}; +#endif /* PPP_STATS_SUPPORT */ + + +/* + * PPP private functions + */ + + +/* + * Functions called from lwIP core. + */ + +/* initialize the PPP subsystem */ +int ppp_init(void); + +/* + * Functions called from PPP link protocols. + */ + +/* Create a new PPP control block */ +ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* Initiate LCP open request */ +void ppp_start(ppp_pcb *pcb); + +/* Called when link failed to setup */ +void ppp_link_failed(ppp_pcb *pcb); + +/* Called when link is normally down (i.e. it was asked to end) */ +void ppp_link_end(ppp_pcb *pcb); + +/* function called to process input packet */ +void ppp_input(ppp_pcb *pcb, struct pbuf *pb); + +/* helper function, merge a pbuf chain into one pbuf */ +struct pbuf *ppp_singlebuf(struct pbuf *p); + + +/* + * Functions called by PPP protocols. + */ + +/* function called by all PPP subsystems to send packets */ +err_t ppp_write(ppp_pcb *pcb, struct pbuf *p); + +/* functions called by auth.c link_terminated() */ +void ppp_link_terminated(ppp_pcb *pcb); + +void new_phase(ppp_pcb *pcb, int p); + +int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp); +int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp); + +#if PPP_IPV4_SUPPORT +int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask); +int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr); +#if 0 /* UNUSED - PROXY ARP */ +int sifproxyarp(ppp_pcb *pcb, u32_t his_adr); +int cifproxyarp(ppp_pcb *pcb, u32_t his_adr); +#endif /* UNUSED - PROXY ARP */ +#if LWIP_DNS +int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +#endif /* LWIP_DNS */ +#if VJ_SUPPORT +int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid); +#endif /* VJ_SUPPORT */ +int sifup(ppp_pcb *pcb); +int sifdown (ppp_pcb *pcb); +u32_t get_mask(u32_t addr); +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int sif6up(ppp_pcb *pcb); +int sif6down (ppp_pcb *pcb); +#endif /* PPP_IPV6_SUPPORT */ + +#if DEMAND_SUPPORT +int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); +#endif /* DEMAND_SUPPORt */ + +void netif_set_mtu(ppp_pcb *pcb, int mtu); +int netif_get_mtu(ppp_pcb *pcb); + +#if CCP_SUPPORT +#if 0 /* unused */ +int ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit); +#endif /* unused */ +void ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method); +void ccp_reset_comp(ppp_pcb *pcb); +void ccp_reset_decomp(ppp_pcb *pcb); +#if 0 /* unused */ +int ccp_fatal_error(ppp_pcb *pcb); +#endif /* unused */ +#endif /* CCP_SUPPORT */ + +#if PPP_IDLETIMELIMIT +int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip); +#endif /* PPP_IDLETIMELIMIT */ + +#if DEMAND_SUPPORT +int get_loop_output(void); +#endif /* DEMAND_SUPPORT */ + +/* Optional protocol names list, to make our messages a little more informative. */ +#if PPP_PROTOCOLNAME +const char * protocol_name(int proto); +#endif /* PPP_PROTOCOLNAME */ + +/* Optional stats support, to get some statistics on the PPP interface */ +#if PPP_STATS_SUPPORT +void print_link_stats(void); /* Print stats, if available */ +void reset_link_stats(int u); /* Reset (init) stats when link goes up */ +void update_link_stats(int u); /* Get stats at link termination */ +#endif /* PPP_STATS_SUPPORT */ + + + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ + (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ + *(cp)++ = (u_char) (c); \ +} +#define GETSHORT(s, cp) { \ + (s) = *(cp)++ << 8; \ + (s) |= *(cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s); \ +} +#define GETLONG(l, cp) { \ + (l) = *(cp)++ << 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; \ +} +#define PUTLONG(l, cp) { \ + *(cp)++ = (u_char) ((l) >> 24); \ + *(cp)++ = (u_char) ((l) >> 16); \ + *(cp)++ = (u_char) ((l) >> 8); \ + *(cp)++ = (u_char) (l); \ +} + +#define INCPTR(n, cp) ((cp) += (n)) +#define DECPTR(n, cp) ((cp) -= (n)) + +/* + * System dependent definitions for user-level 4.3BSD UNIX implementation. + */ +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) +#define TIMEOUTMS(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t), (f), (a)); } while(0) +#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) + +#define BZERO(s, n) memset(s, 0, n) +#define BCMP(s1, s2, l) memcmp(s1, s2, l) + +#define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } + +/* + * MAKEHEADER - Add Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/* Procedures exported from auth.c */ +void link_required(ppp_pcb *pcb); /* we are starting to use the link */ +void link_terminated(ppp_pcb *pcb); /* we are finished with the link */ +void link_down(ppp_pcb *pcb); /* the LCP layer has left the Opened state */ +void upper_layers_down(ppp_pcb *pcb); /* take all NCPs down */ +void link_established(ppp_pcb *pcb); /* the link is up; authenticate now */ +void start_networks(ppp_pcb *pcb); /* start all the network control protos */ +void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen); + /* check the user name and passwd against configuration */ +void auth_peer_fail(ppp_pcb *pcb, int protocol); + /* peer failed to authenticate itself */ +void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen); + /* peer successfully authenticated itself */ +#endif /* PPP_SERVER */ +void auth_withpeer_fail(ppp_pcb *pcb, int protocol); + /* we failed to authenticate ourselves */ +void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor); + /* we successfully authenticated ourselves */ +#endif /* PPP_AUTH_SUPPORT */ +void np_up(ppp_pcb *pcb, int proto); /* a network protocol has come up */ +void np_down(ppp_pcb *pcb, int proto); /* a network protocol has gone down */ +void np_finished(ppp_pcb *pcb, int proto); /* a network protocol no longer needs link */ +#if PPP_AUTH_SUPPORT +int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server); + /* get "secret" for chap */ +#endif /* PPP_AUTH_SUPPORT */ + +/* Procedures exported from ipcp.c */ +/* int parse_dotted_ip (char *, u32_t *); */ + +/* Procedures exported from demand.c */ +#if DEMAND_SUPPORT +void demand_conf (void); /* config interface(s) for demand-dial */ +void demand_block (void); /* set all NPs to queue up packets */ +void demand_unblock (void); /* set all NPs to pass packets */ +void demand_discard (void); /* set all NPs to discard packets */ +void demand_rexmit (int, u32_t); /* retransmit saved frames for an NP*/ +int loop_chars (unsigned char *, int); /* process chars from loopback */ +int loop_frame (unsigned char *, int); /* should we bring link up? */ +#endif /* DEMAND_SUPPORT */ + +/* Procedures exported from multilink.c */ +#ifdef HAVE_MULTILINK +void mp_check_options (void); /* Check multilink-related options */ +int mp_join_bundle (void); /* join our link to an appropriate bundle */ +void mp_exit_bundle (void); /* have disconnected our link from bundle */ +void mp_bundle_terminated (void); +char *epdisc_to_str (struct epdisc *); /* string from endpoint discrim. */ +int str_to_epdisc (struct epdisc *, char *); /* endpt disc. from str */ +#else +#define mp_bundle_terminated() /* nothing */ +#define mp_exit_bundle() /* nothing */ +#define doing_multilink 0 +#define multilink_master 0 +#endif + +/* Procedures exported from utils.c. */ +void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg); /* Format a string for output */ +int ppp_slprintf(char *buf, int buflen, const char *fmt, ...); /* sprintf++ */ +int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args); /* vsprintf++ */ +size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ +size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ +void ppp_dbglog(const char *fmt, ...); /* log a debug message */ +void ppp_info(const char *fmt, ...); /* log an informational message */ +void ppp_notice(const char *fmt, ...); /* log a notice-level message */ +void ppp_warn(const char *fmt, ...); /* log a warning message */ +void ppp_error(const char *fmt, ...); /* log an error message */ +void ppp_fatal(const char *fmt, ...); /* log an error message and die(1) */ +#if PRINTPKT_SUPPORT +void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); + /* dump packet to debug log if interesting */ +#endif /* PRINTPKT_SUPPORT */ + + +#endif /* PPP_SUPPORT */ +#endif /* LWIP_HDR_PPP_IMPL_H */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/ppp_opts.h b/Sming/third-party/lwip2/include/netif/ppp/ppp_opts.h new file mode 100644 index 0000000000..fa79c090f2 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/ppp_opts.h @@ -0,0 +1,593 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPP_OPTS_H +#define LWIP_PPP_OPTS_H + +#include "lwip/opt.h" + +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOL2TP_SUPPORT==1: Enable PPP Over L2TP + */ +#ifndef PPPOL2TP_SUPPORT +#define PPPOL2TP_SUPPORT 0 +#endif + +/** + * PPPOL2TP_AUTH_SUPPORT==1: Enable PPP Over L2TP Auth (enable MD5 support) + */ +#ifndef PPPOL2TP_AUTH_SUPPORT +#define PPPOL2TP_AUTH_SUPPORT PPPOL2TP_SUPPORT +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +/** + * LWIP_PPP_API==1: Enable PPP API (in pppapi.c) + */ +#ifndef LWIP_PPP_API +#define LWIP_PPP_API (PPP_SUPPORT && (NO_SYS == 0)) +#endif + +/** + * MEMP_NUM_PPP_PCB: the number of simultaneously active PPP + * connections (requires the PPP_SUPPORT option) + */ +#ifndef MEMP_NUM_PPP_PCB +#define MEMP_NUM_PPP_PCB 1 +#endif + +#if PPP_SUPPORT + +/** + * MEMP_NUM_PPPOS_INTERFACES: the number of concurrently active PPPoS + * interfaces (only used with PPPOS_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOS_INTERFACES +#define MEMP_NUM_PPPOS_INTERFACES MEMP_NUM_PPP_PCB +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPPOL2TP_INTERFACES: the number of concurrently active PPPoL2TP + * interfaces (only used with PPPOL2TP_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOL2TP_INTERFACES +#define MEMP_NUM_PPPOL2TP_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPP_API_MSG: Number of concurrent PPP API messages (in pppapi.c) + */ +#ifndef MEMP_NUM_PPP_API_MSG +#define MEMP_NUM_PPP_API_MSG 5 +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_INPROC_IRQ_SAFE==1 call pppos_input() using tcpip_callback(). + * + * Please read the "PPPoS input path" chapter in the PPP documentation about this option. + */ +#ifndef PPP_INPROC_IRQ_SAFE +#define PPP_INPROC_IRQ_SAFE 0 +#endif + +/** + * PRINTPKT_SUPPORT==1: Enable PPP print packet support + * + * Mandatory for debugging, it displays exchanged packet content in debug trace. + */ +#ifndef PRINTPKT_SUPPORT +#define PRINTPKT_SUPPORT 0 +#endif + +/** + * PPP_IPV4_SUPPORT==1: Enable PPP IPv4 support + */ +#ifndef PPP_IPV4_SUPPORT +#define PPP_IPV4_SUPPORT (LWIP_IPV4) +#endif + +/** + * PPP_IPV6_SUPPORT==1: Enable PPP IPv6 support + */ +#ifndef PPP_IPV6_SUPPORT +#define PPP_IPV6_SUPPORT (LWIP_IPV6) +#endif + +/** + * PPP_NOTIFY_PHASE==1: Support PPP notify phase support + * + * PPP notify phase support allows you to set a callback which is + * called on change of the internal PPP state machine. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +#ifndef PPP_NOTIFY_PHASE +#define PPP_NOTIFY_PHASE 0 +#endif + +/** + * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets. + * + * Memory allocated must be single buffered for PPP to works, it requires pbuf + * that are not going to be chained when allocated. This requires setting + * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. + * + * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous + * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. + */ +#ifndef PPP_USE_PBUF_RAM +#define PPP_USE_PBUF_RAM 0 +#endif + +/** + * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS + */ +#ifndef PPP_FCS_TABLE +#define PPP_FCS_TABLE 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif +#if MSCHAP_SUPPORT +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MSCHAP_SUPPORT */ + +/** + * EAP_SUPPORT==1: Support EAP. + */ +#ifndef EAP_SUPPORT +#define EAP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * MPPE_SUPPORT==1: Support MPPE. + */ +#ifndef MPPE_SUPPORT +#define MPPE_SUPPORT 0 +#endif +#if MPPE_SUPPORT +/* MPPE requires CCP support */ +#undef CCP_SUPPORT +#define CCP_SUPPORT 1 +/* MPPE requires MSCHAP support */ +#undef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 1 +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MPPE_SUPPORT */ + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * ECP_SUPPORT==1: Support ECP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef ECP_SUPPORT +#define ECP_SUPPORT 0 +#endif + +/** + * DEMAND_SUPPORT==1: Support dial on demand. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef DEMAND_SUPPORT +#define DEMAND_SUPPORT 0 +#endif + +/** + * LQR_SUPPORT==1: Support Link Quality Report. Do nothing except exchanging some LCP packets. + */ +#ifndef LQR_SUPPORT +#define LQR_SUPPORT 0 +#endif + +/** + * PPP_SERVER==1: Enable PPP server support (waiting for incoming PPP session). + * + * Currently only supported for PPPoS. + */ +#ifndef PPP_SERVER +#define PPP_SERVER 0 +#endif + +#if PPP_SERVER +/* + * PPP_OUR_NAME: Our name for authentication purposes + */ +#ifndef PPP_OUR_NAME +#define PPP_OUR_NAME "lwIP" +#endif +#endif /* PPP_SERVER */ + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 1 +#endif +/* VJ compression is only supported for TCP over IPv4 over PPPoS. */ +#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP +#undef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif /* !PPPOS_SUPPORT */ + +/** + * PPP_MD5_RANDM==1: Use MD5 for better randomness. + * Enabled by default if CHAP, EAP, or L2TP AUTH support is enabled. + */ +#ifndef PPP_MD5_RANDM +#define PPP_MD5_RANDM (CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT) +#endif + +/** + * PolarSSL embedded library + * + * + * lwIP contains some files fetched from the latest BSD release of + * the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption + * methods we need for lwIP PPP support. + * + * The PolarSSL files were cleaned to contain only the necessary struct + * fields and functions needed for lwIP. + * + * The PolarSSL API was not changed at all, so if you are already using + * PolarSSL you can choose to skip the compilation of the included PolarSSL + * library into lwIP. + * + * If you are not using the embedded copy you must include external + * libraries into your arch/cc.h port file. + * + * Beware of the stack requirements which can be a lot larger if you are not + * using our cleaned PolarSSL library. + */ + +/** + * LWIP_USE_EXTERNAL_POLARSSL: Use external PolarSSL library + */ +#ifndef LWIP_USE_EXTERNAL_POLARSSL +#define LWIP_USE_EXTERNAL_POLARSSL 0 +#endif + +/** + * LWIP_USE_EXTERNAL_MBEDTLS: Use external mbed TLS library + */ +#ifndef LWIP_USE_EXTERNAL_MBEDTLS +#define LWIP_USE_EXTERNAL_MBEDTLS 0 +#endif + +/* + * PPP Timeouts + */ + +/** + * FSM_DEFTIMEOUT: Timeout time in seconds + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 +#endif + +/** + * FSM_DEFMAXTERMREQS: Maximum Terminate-Request transmissions + */ +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 +#endif + +/** + * FSM_DEFMAXCONFREQS: Maximum Configure-Request transmissions + */ +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 +#endif + +/** + * FSM_DEFMAXNAKLOOPS: Maximum number of nak loops + */ +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 +#endif + +/** + * UPAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 +#endif + +/** + * UPAP_DEFTRANSMITS: Maximum number of auth-reqs to send + */ +#ifndef UPAP_DEFTRANSMITS +#define UPAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * UPAP_DEFREQTIME: Time to wait for auth-req from peer + */ +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 +#endif +#endif /* PPP_SERVER */ + +/** + * CHAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 +#endif + +/** + * CHAP_DEFTRANSMITS: max # times to send challenge + */ +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * CHAP_DEFRECHALLENGETIME: If this option is > 0, rechallenge the peer every n seconds + */ +#ifndef CHAP_DEFRECHALLENGETIME +#define CHAP_DEFRECHALLENGETIME 0 +#endif +#endif /* PPP_SERVER */ + +/** + * EAP_DEFREQTIME: Time to wait for peer request + */ +#ifndef EAP_DEFREQTIME +#define EAP_DEFREQTIME 6 +#endif + +/** + * EAP_DEFALLOWREQ: max # times to accept requests + */ +#ifndef EAP_DEFALLOWREQ +#define EAP_DEFALLOWREQ 10 +#endif + +#if PPP_SERVER +/** + * EAP_DEFTIMEOUT: Timeout (seconds) for rexmit + */ +#ifndef EAP_DEFTIMEOUT +#define EAP_DEFTIMEOUT 6 +#endif + +/** + * EAP_DEFTRANSMITS: max # times to transmit + */ +#ifndef EAP_DEFTRANSMITS +#define EAP_DEFTRANSMITS 10 +#endif +#endif /* PPP_SERVER */ + +/** + * LCP_DEFLOOPBACKFAIL: Default number of times we receive our magic number from the peer + * before deciding the link is looped-back. + */ +#ifndef LCP_DEFLOOPBACKFAIL +#define LCP_DEFLOOPBACKFAIL 10 +#endif + +/** + * LCP_ECHOINTERVAL: Interval in seconds between keepalive echo requests, 0 to disable. + */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/** + * LCP_MAXECHOFAILS: Number of unanswered echo requests before failure. + */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/** + * PPP_MAXIDLEFLAG: Max Xmit idle time (in ms) before resend flag char. + */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/** + * PPP Packet sizes + */ + +/** + * PPP_MRU: Default MRU + */ +#ifndef PPP_MRU +#define PPP_MRU 1500 +#endif + +/** + * PPP_DEFMRU: Default MRU to try + */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 1500 +#endif + +/** + * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384) + */ +#ifndef PPP_MAXMRU +#define PPP_MAXMRU 1500 +#endif + +/** + * PPP_MINMRU: No MRUs below this + */ +#ifndef PPP_MINMRU +#define PPP_MINMRU 128 +#endif + +/** + * PPPOL2TP_DEFMRU: Default MTU and MRU for L2TP + * Default = 1500 - PPPoE(6) - PPP Protocol(2) - IPv4 header(20) - UDP Header(8) + * - L2TP Header(6) - HDLC Header(2) - PPP Protocol(2) - MPPE Header(2) - PPP Protocol(2) + */ +#if PPPOL2TP_SUPPORT +#ifndef PPPOL2TP_DEFMRU +#define PPPOL2TP_DEFMRU 1450 +#endif +#endif /* PPPOL2TP_SUPPORT */ + +/** + * MAXNAMELEN: max length of hostname or name for auth + */ +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 +#endif + +/** + * MAXSECRETLEN: max length of password or secret + */ +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Build triggers for embedded PolarSSL + */ +#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS + +/* CHAP, EAP, L2TP AUTH and MD5 Random require MD5 support */ +#if CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#endif /* CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM */ + +#if MSCHAP_SUPPORT + +/* MSCHAP require MD4 support */ +#define LWIP_INCLUDED_POLARSSL_MD4 1 +/* MSCHAP require SHA1 support */ +#define LWIP_INCLUDED_POLARSSL_SHA1 1 +/* MSCHAP require DES support */ +#define LWIP_INCLUDED_POLARSSL_DES 1 + +/* MS-CHAP support is required for MPPE */ +#if MPPE_SUPPORT +/* MPPE require ARC4 support */ +#define LWIP_INCLUDED_POLARSSL_ARC4 1 +#endif /* MPPE_SUPPORT */ + +#endif /* MSCHAP_SUPPORT */ + +#endif /* !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* Default value if unset */ +#ifndef LWIP_INCLUDED_POLARSSL_MD4 +#define LWIP_INCLUDED_POLARSSL_MD4 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ +#ifndef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ +#ifndef LWIP_INCLUDED_POLARSSL_SHA1 +#define LWIP_INCLUDED_POLARSSL_SHA1 0 +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ +#ifndef LWIP_INCLUDED_POLARSSL_DES +#define LWIP_INCLUDED_POLARSSL_DES 0 +#endif /* LWIP_INCLUDED_POLARSSL_DES */ +#ifndef LWIP_INCLUDED_POLARSSL_ARC4 +#define LWIP_INCLUDED_POLARSSL_ARC4 0 +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ + +#endif /* PPP_SUPPORT */ + +#endif /* LWIP_PPP_OPTS_H */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppapi.h b/Sming/third-party/lwip2/include/netif/ppp/pppapi.h new file mode 100644 index 0000000000..913d93f749 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppapi.h @@ -0,0 +1,137 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPPAPI_H +#define LWIP_PPPAPI_H + +#include "netif/ppp/ppp_opts.h" + +#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/priv/tcpip_priv.h" +#include "netif/ppp/ppp.h" +#if PPPOS_SUPPORT +#include "netif/ppp/pppos.h" +#endif /* PPPOS_SUPPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct pppapi_msg_msg { + ppp_pcb *ppp; + union { +#if PPP_NOTIFY_PHASE + struct { + ppp_notify_phase_cb_fn notify_phase_cb; + } setnotifyphasecb; +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT + struct { + struct netif *pppif; + pppos_output_cb_fn output_cb; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } serialcreate; +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT + struct { + struct netif *pppif; + struct netif *ethif; + const char *service_name; + const char *concentrator_name; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } ethernetcreate; +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT + struct { + struct netif *pppif; + struct netif *netif; + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; + u8_t secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } l2tpcreate; +#endif /* PPPOL2TP_SUPPORT */ + struct { + u16_t holdoff; + } connect; + struct { + u8_t nocarrier; + } close; + struct { + u8_t cmd; + void *arg; + } ioctl; + } msg; +}; + +struct pppapi_msg { + struct tcpip_api_call_data call; + struct pppapi_msg_msg msg; +}; + +/* API for application */ +err_t pppapi_set_default(ppp_pcb *pcb); +#if PPP_NOTIFY_PHASE +err_t pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT +ppp_pcb *pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT +ppp_pcb *pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, + const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, + void *ctx_cb); +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT +ppp_pcb *pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOL2TP_SUPPORT */ +err_t pppapi_connect(ppp_pcb *pcb, u16_t holdoff); +#if PPP_SERVER +err_t pppapi_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ +err_t pppapi_close(ppp_pcb *pcb, u8_t nocarrier); +err_t pppapi_free(ppp_pcb *pcb); +err_t pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PPP_API */ + +#endif /* LWIP_PPPAPI_H */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppcrypt.h b/Sming/third-party/lwip2/include/netif/ppp/pppcrypt.h new file mode 100644 index 0000000000..a7b2099f25 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppcrypt.h @@ -0,0 +1,136 @@ +/* + * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 + * + * Extracted from chap_ms.c by James Carlson. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* This header file is included in all PPP modules needing hashes and/or ciphers */ + +#ifndef PPPCRYPT_H +#define PPPCRYPT_H + +/* + * If included PolarSSL copy is not used, user is expected to include + * external libraries in arch/cc.h (which is included by lwip/arch.h). + */ +#include "lwip/arch.h" + +/* + * Map hashes and ciphers functions to PolarSSL + */ +#if !LWIP_USE_EXTERNAL_MBEDTLS + +#include "netif/ppp/polarssl/md4.h" +#define lwip_md4_context md4_context +#define lwip_md4_init(context) +#define lwip_md4_starts md4_starts +#define lwip_md4_update md4_update +#define lwip_md4_finish md4_finish +#define lwip_md4_free(context) + +#include "netif/ppp/polarssl/md5.h" +#define lwip_md5_context md5_context +#define lwip_md5_init(context) +#define lwip_md5_starts md5_starts +#define lwip_md5_update md5_update +#define lwip_md5_finish md5_finish +#define lwip_md5_free(context) + +#include "netif/ppp/polarssl/sha1.h" +#define lwip_sha1_context sha1_context +#define lwip_sha1_init(context) +#define lwip_sha1_starts sha1_starts +#define lwip_sha1_update sha1_update +#define lwip_sha1_finish sha1_finish +#define lwip_sha1_free(context) + +#include "netif/ppp/polarssl/des.h" +#define lwip_des_context des_context +#define lwip_des_init(context) +#define lwip_des_setkey_enc des_setkey_enc +#define lwip_des_crypt_ecb des_crypt_ecb +#define lwip_des_free(context) + +#include "netif/ppp/polarssl/arc4.h" +#define lwip_arc4_context arc4_context +#define lwip_arc4_init(context) +#define lwip_arc4_setup arc4_setup +#define lwip_arc4_crypt arc4_crypt +#define lwip_arc4_free(context) + +#endif /* !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* + * Map hashes and ciphers functions to mbed TLS + */ +#if LWIP_USE_EXTERNAL_MBEDTLS + +#define lwip_md4_context mbedtls_md4_context +#define lwip_md4_init mbedtls_md4_init +#define lwip_md4_starts mbedtls_md4_starts +#define lwip_md4_update mbedtls_md4_update +#define lwip_md4_finish mbedtls_md4_finish +#define lwip_md4_free mbedtls_md4_free + +#define lwip_md5_context mbedtls_md5_context +#define lwip_md5_init mbedtls_md5_init +#define lwip_md5_starts mbedtls_md5_starts +#define lwip_md5_update mbedtls_md5_update +#define lwip_md5_finish mbedtls_md5_finish +#define lwip_md5_free mbedtls_md5_free + +#define lwip_sha1_context mbedtls_sha1_context +#define lwip_sha1_init mbedtls_sha1_init +#define lwip_sha1_starts mbedtls_sha1_starts +#define lwip_sha1_update mbedtls_sha1_update +#define lwip_sha1_finish mbedtls_sha1_finish +#define lwip_sha1_free mbedtls_sha1_free + +#define lwip_des_context mbedtls_des_context +#define lwip_des_init mbedtls_des_init +#define lwip_des_setkey_enc mbedtls_des_setkey_enc +#define lwip_des_crypt_ecb mbedtls_des_crypt_ecb +#define lwip_des_free mbedtls_des_free + +#define lwip_arc4_context mbedtls_arc4_context +#define lwip_arc4_init mbedtls_arc4_init +#define lwip_arc4_setup mbedtls_arc4_setup +#define lwip_arc4_crypt(context, buffer, length) mbedtls_arc4_crypt(context, length, buffer, buffer) +#define lwip_arc4_free mbedtls_arc4_free + +#endif /* LWIP_USE_EXTERNAL_MBEDTLS */ + +void pppcrypt_56_to_64_bit_key(u_char *key, u_char *des_key); + +#endif /* PPPCRYPT_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppdebug.h b/Sming/third-party/lwip2/include/netif/ppp/pppdebug.h new file mode 100644 index 0000000000..7ead045910 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppdebug.h @@ -0,0 +1,80 @@ +/***************************************************************************** +* pppdebug.h - System debugging utilities. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* portions Copyright (c) 2001 by Cognizant Pty Ltd. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY (please don't use tabs!) +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-07-29 Guy Lancaster , Global Election Systems Inc. +* Original. +* +***************************************************************************** +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPDEBUG_H +#define PPPDEBUG_H + +/* Trace levels. */ +#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_INFO (PPP_DEBUG) +#define LOG_DETAIL (PPP_DEBUG) +#define LOG_DEBUG (PPP_DEBUG) + +#if PPP_DEBUG + +#define MAINDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define SYSDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define FSMDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define LCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPV6CPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define UPAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define CHAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) + +#else /* PPP_DEBUG */ + +#define MAINDEBUG(a) +#define SYSDEBUG(a) +#define FSMDEBUG(a) +#define LCPDEBUG(a) +#define IPCPDEBUG(a) +#define IPV6CPDEBUG(a) +#define UPAPDEBUG(a) +#define CHAPDEBUG(a) +#define PPPDEBUG(a, b) + +#endif /* PPP_DEBUG */ + +#endif /* PPPDEBUG_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppoe.h b/Sming/third-party/lwip2/include/netif/ppp/pppoe.h new file mode 100644 index 0000000000..9f8f2892b4 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppoe.h @@ -0,0 +1,179 @@ +/***************************************************************************** +* pppoe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "ppp.h" +#include "lwip/etharp.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { + PACK_STRUCT_FLD_8(u8_t vertype); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +/* passive */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif + +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + ppp_pcb *pcb; /* PPP PCB */ + + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + u8_t sc_state; /* discovery phase or session connected */ + +#ifdef PPPOE_TODO + u8_t *sc_service_name; /* if != NULL: requested name of service */ + u8_t *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_TODO */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + u8_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + u8_t sc_hunique_len; /* length of host unique */ +#endif + u8_t sc_padi_retried; /* number of PADI retries already done */ + u8_t sc_padr_retried; /* number of PADR retries already done */ +}; + + +#define pppoe_init() /* compatibility define, no initialization needed */ + +ppp_pcb *pppoe_create(struct netif *pppif, + struct netif *ethif, + const char *service_name, const char *concentrator_name, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +#endif /* PPP_OE_H */ + +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppol2tp.h b/Sming/third-party/lwip2/include/netif/ppp/pppol2tp.h new file mode 100644 index 0000000000..f03950e65d --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppol2tp.h @@ -0,0 +1,201 @@ +/** + * @file + * Network Point to Point Protocol over Layer 2 Tunneling Protocol header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOL2TP_H +#define PPPOL2TP_H + +#include "ppp.h" + +/* Timeout */ +#define PPPOL2TP_CONTROL_TIMEOUT (5*1000) /* base for quick timeout calculation */ +#define PPPOL2TP_SLOW_RETRY (60*1000) /* persistent retry interval */ + +#define PPPOL2TP_MAXSCCRQ 4 /* retry SCCRQ four times (quickly) */ +#define PPPOL2TP_MAXICRQ 4 /* retry IRCQ four times */ +#define PPPOL2TP_MAXICCN 4 /* retry ICCN four times */ + +/* L2TP header flags */ +#define PPPOL2TP_HEADERFLAG_CONTROL 0x8000 +#define PPPOL2TP_HEADERFLAG_LENGTH 0x4000 +#define PPPOL2TP_HEADERFLAG_SEQUENCE 0x0800 +#define PPPOL2TP_HEADERFLAG_OFFSET 0x0200 +#define PPPOL2TP_HEADERFLAG_PRIORITY 0x0100 +#define PPPOL2TP_HEADERFLAG_VERSION 0x0002 + +/* Mandatory bits for control: Control, Length, Sequence, Version 2 */ +#define PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY (PPPOL2TP_HEADERFLAG_CONTROL|PPPOL2TP_HEADERFLAG_LENGTH|PPPOL2TP_HEADERFLAG_SEQUENCE|PPPOL2TP_HEADERFLAG_VERSION) +/* Forbidden bits for control: Offset, Priority */ +#define PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN (PPPOL2TP_HEADERFLAG_OFFSET|PPPOL2TP_HEADERFLAG_PRIORITY) + +/* Mandatory bits for data: Version 2 */ +#define PPPOL2TP_HEADERFLAG_DATA_MANDATORY (PPPOL2TP_HEADERFLAG_VERSION) + +/* AVP (Attribute Value Pair) header */ +#define PPPOL2TP_AVPHEADERFLAG_MANDATORY 0x8000 +#define PPPOL2TP_AVPHEADERFLAG_HIDDEN 0x4000 +#define PPPOL2TP_AVPHEADERFLAG_LENGTHMASK 0x03ff + +/* -- AVP - Message type */ +#define PPPOL2TP_AVPTYPE_MESSAGE 0 /* Message type */ + +/* Control Connection Management */ +#define PPPOL2TP_MESSAGETYPE_SCCRQ 1 /* Start Control Connection Request */ +#define PPPOL2TP_MESSAGETYPE_SCCRP 2 /* Start Control Connection Reply */ +#define PPPOL2TP_MESSAGETYPE_SCCCN 3 /* Start Control Connection Connected */ +#define PPPOL2TP_MESSAGETYPE_STOPCCN 4 /* Stop Control Connection Notification */ +#define PPPOL2TP_MESSAGETYPE_HELLO 6 /* Hello */ +/* Call Management */ +#define PPPOL2TP_MESSAGETYPE_OCRQ 7 /* Outgoing Call Request */ +#define PPPOL2TP_MESSAGETYPE_OCRP 8 /* Outgoing Call Reply */ +#define PPPOL2TP_MESSAGETYPE_OCCN 9 /* Outgoing Call Connected */ +#define PPPOL2TP_MESSAGETYPE_ICRQ 10 /* Incoming Call Request */ +#define PPPOL2TP_MESSAGETYPE_ICRP 11 /* Incoming Call Reply */ +#define PPPOL2TP_MESSAGETYPE_ICCN 12 /* Incoming Call Connected */ +#define PPPOL2TP_MESSAGETYPE_CDN 14 /* Call Disconnect Notify */ +/* Error reporting */ +#define PPPOL2TP_MESSAGETYPE_WEN 15 /* WAN Error Notify */ +/* PPP Session Control */ +#define PPPOL2TP_MESSAGETYPE_SLI 16 /* Set Link Info */ + +/* -- AVP - Result code */ +#define PPPOL2TP_AVPTYPE_RESULTCODE 1 /* Result code */ +#define PPPOL2TP_RESULTCODE 1 /* General request to clear control connection */ + +/* -- AVP - Protocol version (!= L2TP Header version) */ +#define PPPOL2TP_AVPTYPE_VERSION 2 +#define PPPOL2TP_VERSION 0x0100 /* L2TP Protocol version 1, revision 0 */ + +/* -- AVP - Framing capabilities */ +#define PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES 3 /* Bearer capabilities */ +#define PPPOL2TP_FRAMINGCAPABILITIES 0x00000003 /* Async + Sync framing */ + +/* -- AVP - Bearer capabilities */ +#define PPPOL2TP_AVPTYPE_BEARERCAPABILITIES 4 /* Bearer capabilities */ +#define PPPOL2TP_BEARERCAPABILITIES 0x00000003 /* Analog + Digital Access */ + +/* -- AVP - Tie breaker */ +#define PPPOL2TP_AVPTYPE_TIEBREAKER 5 + +/* -- AVP - Host name */ +#define PPPOL2TP_AVPTYPE_HOSTNAME 7 /* Host name */ +#define PPPOL2TP_HOSTNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Vendor name */ +#define PPPOL2TP_AVPTYPE_VENDORNAME 8 /* Vendor name */ +#define PPPOL2TP_VENDORNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Assign tunnel ID */ +#define PPPOL2TP_AVPTYPE_TUNNELID 9 /* Assign Tunnel ID */ + +/* -- AVP - Receive window size */ +#define PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE 10 /* Receive window size */ +#define PPPOL2TP_RECEIVEWINDOWSIZE 8 /* FIXME: make it configurable */ + +/* -- AVP - Challenge */ +#define PPPOL2TP_AVPTYPE_CHALLENGE 11 /* Challenge */ + +/* -- AVP - Cause code */ +#define PPPOL2TP_AVPTYPE_CAUSECODE 12 /* Cause code*/ + +/* -- AVP - Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE 13 /* Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE 16 + +/* -- AVP - Assign session ID */ +#define PPPOL2TP_AVPTYPE_SESSIONID 14 /* Assign Session ID */ + +/* -- AVP - Call serial number */ +#define PPPOL2TP_AVPTYPE_CALLSERIALNUMBER 15 /* Call Serial Number */ + +/* -- AVP - Framing type */ +#define PPPOL2TP_AVPTYPE_FRAMINGTYPE 19 /* Framing Type */ +#define PPPOL2TP_FRAMINGTYPE 0x00000001 /* Sync framing */ + +/* -- AVP - TX Connect Speed */ +#define PPPOL2TP_AVPTYPE_TXCONNECTSPEED 24 /* TX Connect Speed */ +#define PPPOL2TP_TXCONNECTSPEED 100000000 /* Connect speed: 100 Mbits/s */ + +/* L2TP Session state */ +#define PPPOL2TP_STATE_INITIAL 0 +#define PPPOL2TP_STATE_SCCRQ_SENT 1 +#define PPPOL2TP_STATE_ICRQ_SENT 2 +#define PPPOL2TP_STATE_ICCN_SENT 3 +#define PPPOL2TP_STATE_DATA 4 + +#define PPPOL2TP_OUTPUT_DATA_HEADER_LEN 6 /* Our data header len */ + +/* + * PPPoL2TP interface control block. + */ +typedef struct pppol2tp_pcb_s pppol2tp_pcb; +struct pppol2tp_pcb_s { + ppp_pcb *ppp; /* PPP PCB */ + u8_t phase; /* L2TP phase */ + struct udp_pcb *udp; /* UDP L2TP Socket */ + struct netif *netif; /* Output interface, used as a default route */ + ip_addr_t remote_ip; /* LNS IP Address */ + u16_t remote_port; /* LNS port */ +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; /* Secret string */ + u8_t secret_len; /* Secret string length */ + u8_t secret_rv[16]; /* Random vector */ + u8_t challenge_hash[16]; /* Challenge response */ + u8_t send_challenge; /* Boolean whether the next sent packet should contains a challenge response */ +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + u16_t tunnel_port; /* Tunnel port */ + u16_t our_ns; /* NS to peer */ + u16_t peer_nr; /* NR from peer */ + u16_t peer_ns; /* NS from peer */ + u16_t source_tunnel_id; /* Tunnel ID assigned by peer */ + u16_t remote_tunnel_id; /* Tunnel ID assigned to peer */ + u16_t source_session_id; /* Session ID assigned by peer */ + u16_t remote_session_id; /* Session ID assigned to peer */ + + u8_t sccrq_retried; /* number of SCCRQ retries already done */ + u8_t icrq_retried; /* number of ICRQ retries already done */ + u8_t iccn_retried; /* number of ICCN retries already done */ +}; + + +/* Create a new L2TP session. */ +ppp_pcb *pppol2tp_create(struct netif *pppif, + struct netif *netif, const ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#endif /* PPPOL2TP_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/pppos.h b/Sming/third-party/lwip2/include/netif/ppp/pppos.h new file mode 100644 index 0000000000..d924a9fc7e --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/pppos.h @@ -0,0 +1,118 @@ +/** + * @file + * Network Point to Point Protocol over Serial header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOS_H +#define PPPOS_H + +#include "lwip/sys.h" + +#include "ppp.h" +#include "vj.h" + +/* PPP packet parser states. Current state indicates operation yet to be + * completed. */ +enum { + PDIDLE = 0, /* Idle state - waiting. */ + PDSTART, /* Process start flag. */ + PDADDRESS, /* Process address field. */ + PDCONTROL, /* Process control field. */ + PDPROTOCOL1, /* Process protocol field 1. */ + PDPROTOCOL2, /* Process protocol field 2. */ + PDDATA /* Process data byte. */ +}; + +/* PPPoS serial output callback function prototype */ +typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx); + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u8_t ext_accm[32]; + +/* + * PPPoS interface control block. + */ +typedef struct pppos_pcb_s pppos_pcb; +struct pppos_pcb_s { + /* -- below are data that will NOT be cleared between two sessions */ + ppp_pcb *ppp; /* PPP PCB */ + pppos_output_cb_fn output_cb; /* PPP serial output callback */ + + /* -- below are data that will be cleared between two sessions + * + * last_xmit must be the first member of cleared members, because it is + * used to know which part must not be cleared. + */ + u32_t last_xmit; /* Time of last transmission. */ + ext_accm out_accm; /* Async-Ctl-Char-Map for output. */ + + /* flags */ + unsigned int open :1; /* Set if PPPoS is open */ + unsigned int pcomp :1; /* Does peer accept protocol compression? */ + unsigned int accomp :1; /* Does peer accept addr/ctl compression? */ + + /* PPPoS rx */ + ext_accm in_accm; /* Async-Ctl-Char-Map for input. */ + struct pbuf *in_head, *in_tail; /* The input packet. */ + u16_t in_protocol; /* The input protocol code. */ + u16_t in_fcs; /* Input Frame Check Sequence value. */ + u8_t in_state; /* The input process state. */ + u8_t in_escaped; /* Escape next character. */ +}; + +/* Create a new PPPoS session. */ +ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +/* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */ +err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +/* PPP over Serial: this is the input function to be called for received data. */ +void pppos_input(ppp_pcb *ppp, u8_t* data, int len); + + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +err_t pppos_input_sys(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +#endif /* PPPOS_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/upap.h b/Sming/third-party/lwip2/include/netif/ppp/upap.h new file mode 100644 index 0000000000..7da792ecc7 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/upap.h @@ -0,0 +1,123 @@ +/* + * upap.h - User/Password Authentication Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: upap.h,v 1.8 2002/12/04 23:03:33 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef UPAP_H +#define UPAP_H + +#include "ppp.h" + +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN 4 + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + + +/* + * Client states. + */ +#define UPAPCS_INITIAL 0 /* Connection down */ +#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ +#define UPAPCS_OPEN 4 /* We've received an Ack */ +#define UPAPCS_BADAUTH 5 /* We've received a Nak */ + +/* + * Server states. + */ +#define UPAPSS_INITIAL 0 /* Connection down */ +#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ +#define UPAPSS_OPEN 4 /* We've sent an Ack */ +#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif /* moved to ppp_opts.h */ + +/* + * Each interface is described by upap structure. + */ +#if PAP_SUPPORT +typedef struct upap_state { + const char *us_user; /* User */ + u8_t us_userlen; /* User length */ + const char *us_passwd; /* Password */ + u8_t us_passwdlen; /* Password length */ + u8_t us_clientstate; /* Client state */ +#if PPP_SERVER + u8_t us_serverstate; /* Server state */ +#endif /* PPP_SERVER */ + u8_t us_id; /* Current id */ + u8_t us_transmits; /* Number of auth-reqs sent */ +} upap_state; +#endif /* PAP_SUPPORT */ + + +void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password); +#if PPP_SERVER +void upap_authpeer(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +extern const struct protent pap_protent; + +#endif /* UPAP_H */ +#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/ppp/vj.h b/Sming/third-party/lwip2/include/netif/ppp/vj.h new file mode 100644 index 0000000000..7f389c846f --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/ppp/vj.h @@ -0,0 +1,161 @@ +/* + * Definitions for tcp compression routines. + * + * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef VJ_H +#define VJ_H + +#include "lwip/ip.h" +#include "lwip/priv/tcp_priv.h" + +#define MAX_SLOTS 16 /* must be > 2 and < 256 */ +#define MAX_HDR 128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP 0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP 0x80 +#define TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + struct cstate *cs_next; /* next most recently used state (xmit only) */ + u16_t cs_hlen; /* size of hdr (receive only) */ + u8_t cs_id; /* connection # associated with this state */ + u8_t cs_filler; + union { + char csu_hdr[MAX_HDR]; + struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ + } vjcs_u; +}; +#define cs_ip vjcs_u.csu_ip +#define cs_hdr vjcs_u.csu_hdr + + +struct vjstat { + u32_t vjs_packets; /* outbound packets */ + u32_t vjs_compressed; /* outbound compressed packets */ + u32_t vjs_searches; /* searches for connection state */ + u32_t vjs_misses; /* times couldn't find conn. state */ + u32_t vjs_uncompressedin; /* inbound uncompressed packets */ + u32_t vjs_compressedin; /* inbound compressed packets */ + u32_t vjs_errorin; /* inbound unknown type packets */ + u32_t vjs_tossed; /* inbound packets tossed because of error */ +}; + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct vjcompress { + struct cstate *last_cs; /* most recently used tstate */ + u8_t last_recv; /* last rcvd conn. id */ + u8_t last_xmit; /* last sent conn. id */ + u16_t flags; + u8_t maxSlotIndex; + u8_t compressSlot; /* Flag indicating OK to compress slot ID. */ +#if LINK_STATS + struct vjstat stats; +#endif + struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ + struct cstate rstate[MAX_SLOTS]; /* receive connection states */ +}; + +/* flag values */ +#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ + +extern void vj_compress_init (struct vjcompress *comp); +extern u8_t vj_compress_tcp (struct vjcompress *comp, struct pbuf **pb); +extern void vj_uncompress_err (struct vjcompress *comp); +extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); +extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp); + +#endif /* VJ_H */ + +#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/Sming/third-party/lwip2/include/netif/slipif.h b/Sming/third-party/lwip2/include/netif/slipif.h new file mode 100644 index 0000000000..65ba31f835 --- /dev/null +++ b/Sming/third-party/lwip2/include/netif/slipif.h @@ -0,0 +1,87 @@ +/** + * @file + * + * SLIP netif API + */ + +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_SLIPIF_H +#define LWIP_HDR_NETIF_SLIPIF_H + +#include "lwip/opt.h" +#include "lwip/netif.h" + +/** Set this to 1 to start a thread that blocks reading on the serial line + * (using sio_read()). + */ +#ifndef SLIP_USE_RX_THREAD +#define SLIP_USE_RX_THREAD !NO_SYS +#endif + +/** Set this to 1 to enable functions to pass in RX bytes from ISR context. + * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled + * packets on a queue, which is fed into lwIP from slipif_poll(). + * If disabled, slipif_poll() polls the serial line (using sio_tryread()). + */ +#ifndef SLIP_RX_FROM_ISR +#define SLIP_RX_FROM_ISR 0 +#endif + +/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets + * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. + * If disabled, packets will be dropped if more than one packet is received. + */ +#ifndef SLIP_RX_QUEUE +#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +err_t slipif_init(struct netif * netif); +void slipif_poll(struct netif *netif); +#if SLIP_RX_FROM_ISR +void slipif_process_rxqueue(struct netif *netif); +void slipif_received_byte(struct netif *netif, u8_t data); +void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); +#endif /* SLIP_RX_FROM_ISR */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_SLIPIF_H */ + diff --git a/Sming/third-party/lwip2/include/posix/errno.h b/Sming/third-party/lwip2/include/posix/errno.h new file mode 100644 index 0000000000..5917c75e24 --- /dev/null +++ b/Sming/third-party/lwip2/include/posix/errno.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/errno.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/errno.h" diff --git a/Sming/third-party/lwip2/include/posix/netdb.h b/Sming/third-party/lwip2/include/posix/netdb.h new file mode 100644 index 0000000000..12d4c7f566 --- /dev/null +++ b/Sming/third-party/lwip2/include/posix/netdb.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/netdb.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/netdb.h" diff --git a/Sming/third-party/lwip2/include/posix/sys/socket.h b/Sming/third-party/lwip2/include/posix/sys/socket.h new file mode 100644 index 0000000000..0ed9baf3d9 --- /dev/null +++ b/Sming/third-party/lwip2/include/posix/sys/socket.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/sockets.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/sockets.h" diff --git a/Sming/third-party/lwip2/liblwip2.a b/Sming/third-party/lwip2/liblwip2.a new file mode 100644 index 0000000000000000000000000000000000000000..35530578804cd074880a5557f6f191de669efdf5 GIT binary patch literal 1066588 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¥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ÞkvQ;u5X)T@ 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/lwip2-src/.gitattributes b/Sming/third-party/lwip2/lwip2-src/.gitattributes new file mode 100644 index 0000000000..f34d43dc57 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/.gitattributes @@ -0,0 +1,4 @@ +# These files are text and should be normalized +*.txt text +*.c text +*.h text diff --git a/Sming/third-party/lwip2/lwip2-src/.gitignore b/Sming/third-party/lwip2/lwip2-src/.gitignore new file mode 100644 index 0000000000..cb0ed5341f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/.gitignore @@ -0,0 +1,18 @@ +*.o +*.a +/doc/doxygen/output/html +/src/apps/snmp/LwipMibCompiler/CCodeGeneration/bin/ +/src/apps/snmp/LwipMibCompiler/CCodeGeneration/obj/ +/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/bin/ +/src/apps/snmp/LwipMibCompiler/LwipMibCompiler/obj/ +/src/apps/snmp/LwipMibCompiler/MibViewer/bin/ +/src/apps/snmp/LwipMibCompiler/MibViewer/obj/ +/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/bin/ +/src/apps/snmp/LwipMibCompiler/LwipSnmpCodeGeneration/obj/ +/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/bin/ +/src/apps/snmp/LwipMibCompiler/SharpSnmpLib/obj/ +/src/apps/snmp/LwipMibCompiler/LwipMibCompiler.userprefs +/src/apps/snmp/LwipMibCompiler/*.suo +/test/fuzz/output +/test/fuzz/lwip_fuzz +/test/fuzz/.depend diff --git a/Sming/third-party/lwip2/lwip2-src/CHANGELOG b/Sming/third-party/lwip2/lwip2-src/CHANGELOG new file mode 100644 index 0000000000..3a277195ce --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/CHANGELOG @@ -0,0 +1,4276 @@ +HISTORY + +(git master) + + * [Enter new changes just after this line - do not remove this line] + +(STABLE-2.0.2) + + ++ New features: + + 2017-02-10: Dirk Ziegelmeier + * Implement task #14367: Hooks need a better place to be defined: + We now have a #define for a header file name that is #included in every .c + file that provides hooks. + + ++ Bugfixes: + + 2017-03-08 + * tcp: do not keep sending SYNs when getting ACKs + + 2017-03-08: Joel Cunningham + * tcp: Initialize ssthresh to TCP_SND_BUF (bug #50476) + + 2017-03-01: Simon Goldschmidt + * httpd: LWIP_HTTPD_POST_MANUAL_WND: fixed double-free when httpd_post_data_recved + is called nested from httpd_post_receive_data() (bug #50424) + + 2017-02-28: David van Moolenbroek/Simon Goldschmidt + * tcp: fixed bug #50418: LWIP_EVENT_API: fix invalid calbacks for SYN_RCVD pcb + + 2017-02-17: Simon Goldschmidt + * dns: Improved DNS_LOCAL_HOSTLIST interface (bug #50325) + + 2017-02-16: Simon Goldschmidt + * LWIP_NETCONN_FULLDUPLEX: fixed shutdown during write (bug #50274) + + 2017-02-13: Simon Goldschmidt/Dirk Ziegelmeier + * For tiny targtes, LWIP_RAND is optional (fix compile time checks) + + 2017-02-10: Simon Goldschmidt + * tcp: Fixed bug #47485 (tcp_close() should not fail on memory error) by retrying + to send FIN from tcp_fasttmr + + 2017-02-09: Simon Goldschmidt + * sockets: Fixed bug #44032 (LWIP_NETCONN_FULLDUPLEX: select might work on + invalid/reused socket) by not allowing to reallocate a socket that has + "select_waiting != 0" + + 2017-02-09: Simon Goldschmidt + * httpd: Fixed bug #50059 (httpd LWIP_HTTPD_SUPPORT_11_KEEPALIVE vs. + LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED) + + 2017-02-08: Dirk Ziegelmeier + * Rename "IPv6 mapped IPv4 addresses" to their correct name from RFC4191: + "IPv4-mapped IPv6 address" + + 2017-02-08: Luc Revardel + * mld6.c: Fix bug #50220 (mld6_leavegroup does not send ICMP6_TYPE_MLD, even + if last reporter) + + 2017-02-08: David van Moolenbroek + * ip6.c: Patch #9250: fix source substitution in ip6_output_if() + + 2017-02-08: Simon Goldschmidt + * tcp_out.c: Fixed bug #50090 (last_unsent->oversize_left can become wrong value + in tcp_write error path) + + 2017-02-02: Dirk Ziegelmeier + * Fix bug #50206: UDP Netconn bind to IP6_ADDR_ANY fails + + 2017-01-18: Dirk Ziegelmeier + * Fix zero-copy RX, see bug bug #50064. PBUF_REFs were not supported as ARP requests. + + 2017-01-15: Axel Lin, Dirk Ziegelmeier + * minor bug fixes in mqtt + + 2017-01-11: Knut Andre Tidemann + * sockets/netconn: fix broken default ICMPv6 handling of checksums + +(STABLE-2.0.1) + + ++ New features: + + 2016-12-31: Simon Goldschmidt + * tcp.h/.c: added function tcp_listen_with_backlog_and_err() to get the error + reason when listening fails (bug #49861) + + 2016-12-20: Erik Andersen + * Add MQTT client + + 2016-12-14: Jan Breuer: + * opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106) + + 2016-12-14: David van Moolenbroek + * opt.h, nd6.c: Added LWIP_HOOK_ND6_GET_GW() + + 2016-12-09: Dirk Ziegelmeier + * ip6_frag.c: Implemented support for LWIP_NETIF_TX_SINGLE_PBUF + + 2016-12-09: Simon Goldschmidt + * dns.c: added one-shot multicast DNS queries + + 2016-11-24: Ambroz Bizjak, David van Moolenbroek + * tcp_out.c: Optimize passing contiguous nocopy buffers to tcp_write (bug #46290) + + 2016-11-16: Dirk Ziegelmeier + * sockets.c: added support for IPv6 mapped IPv4 addresses + + ++ Bugfixes: + + 2016-12-16: Thomas Mueller + * api_lib.c: fixed race condition in return value of netconn_gethostbyname() + (and thus also lwip_gethostbyname/_r() and lwip_getaddrinfo()) + + 2016-12-15: David van Moolenbroek + * opt.h, tcp: added LWIP_HOOK_TCP_ISN() to implement less predictable initial + sequence numbers (see contrib/addons/tcp_isn for an example implementation) + + 2016-12-05: Dirk Ziegelmeier + * fixed compiling with IPv4 disabled (IPv6 only case) + + 2016-11-28: Simon Goldschmidt + * api_lib.c: fixed bug #49725 (send-timeout: netconn_write() can return + ERR_OK without all bytes being written) + + 2016-11-28: Ambroz Bizjak + * tcpi_in.c: fixed bug #49717 (window size in received SYN and SYN-ACK + assumed scaled) + + 2016-11-25: Simon Goldschmidt + * dhcp.c: fixed bug #49676 (Possible endless loop when parsing dhcp options) + + 2016-11-23: Dirk Ziegelmeier + * udp.c: fixed bug #49662: multicast traffic is now only received on a UDP PCB + (and therefore on a UDP socket/netconn) when the PCB is bound to IP_ADDR_ANY + + 2016-11-16: Dirk Ziegelmeier + * *: Fixed dual-stack behaviour, IPv6 mapped IPv4 support in socket API + + 2016-11-14: Joel Cunningham + * tcp_out.c: fixed bug #49533 (start persist timer when unsent seg can't fit + in window) + + 2016-11-16: Roberto Barbieri Carrera + * autoip.c: fixed bug #49610 (sometimes AutoIP fails to reuse the same address) + + 2016-11-11: Dirk Ziegelmeier + * sockets.c: fixed bug #49578 (dropping multicast membership does not work + with LWIP_SOCKET_OFFSET) + +(STABLE-2.0.0) + + ++ New features: + + 2016-07-27: Simon Goldschmidt + * opt.h, timeouts.h/.c: added LWIP_TIMERS_CUSTOM to override the default + implementation of timeouts + + 2016-07-xx: Dirk Ziegelmeier + * Large overhaul of doxygen documentation + + 2016-04-05: Simon Goldschmidt + * timers.h/.c: prepare for overriding current timeout implementation: all + stack-internal caclic timers are avaliable in the lwip_cyclic_timers array + + 2016-03-23: Simon Goldschmidt + * tcp: call accept-callback with ERR_MEM when allocating a pcb fails on + passive open to inform the application about this error + ATTENTION: applications have to handle NULL pcb in accept callback! + + 2016-02-22: Ivan Delamer + * Initial 6LoWPAN support + + 2016-02-XX to 2016-03-XX: Dirk Ziegelmeier + * Cleanup TCPIP thread sync methods in a way that it is possibe to use them + in arbitrary code that needs things to be done in TCPIP thread. Used to + decouple netconn, netif, ppp and 6LoWPAN from LWIP core. + + 2016-02-XX: Dirk Ziegelmeier + * Implement dual-stack support in RAW, UDP and TCP. Add new IP address + type IPADDR_ANY_TYPE for this. Netconn/Socket API: Dual-stack is + automatically supported when an IPv6 netconn/socket is created. + + 2015-12-26: Martin Hentschel and Dirk Ziegelmeier + * Rewrite SNMP agent. SNMPv2c + MIB compiler. + + 2015-11-12: Dirk Ziegelmeier + * Decouple SNMP stack from lwIP core and move stack to apps/ directory. + Breaking change: Users have to call snmp_init() now! + + 2015-11-12: Dirk Ziegelmeier + * Implement possibility to declare private memory pools. This is useful to + decouple some apps from the core (SNMP stack) or make contrib app usage + simpler (httpserver_raw) + + 2015-10-09: Simon Goldschmidt + * started to move "private" header files containing implementation details to + "lwip/priv/" include directory to seperate the API from the implementation. + + 2015-10-07: Simon Goldschmidt + * added sntp client as first "supported" application layer protocol implementation + added 'apps' folder + + 2015-09-30: Dirk Ziegelmeier + * snmp_structs.h, mib_structs.c, mib2.c: snmp: fixed ugly inheritance + implementation by aggregating the "base class" (struct mib_node) in all + derived node classes to get more type-safe code + + 2015-09-23: Simon Goldschmidt + * netif.h/.c, nd6.c: task #13729: Convert netif addresses (IPv4 & IPv6) to + ip_addr_t (so they can be used without conversion/temporary storage) + + 2015-09-08: Dirk Ziegelmeier + * snmp: Separate mib2 counter/table callbacks from snmp agent. This both cleans + up the code and should allow integration of a 3rd party agent/mib2. Simple + counters are kept in MIB2_STATS, tree/table change function prototypes moved to + snmp_mib2.h. + + 2015-09-03: Simon Goldschmidt + * opt.h, dns.h/.c: DNS/IPv6: added support for AAAA records + + 2015-09-01: Simon Goldschmidt + * task #12178: hardware checksum capabilities can be configured per netif + (use NETIF_SET_CHECKSUM_CTRL() in your netif's init function) + + 2015-08-30: Simon Goldschmidt + * PBUF_REF with "custom" pbufs is now supported for RX pbufs (see pcapif in + contrib for an example, LWIP_SUPPORT_CUSTOM_PBUF is required) + + 2015-08-30: Simon Goldschmidt + * support IPv4 source based routing: define LWIP_HOOK_IP4_ROUTE_SRC to point + to a routing function + + 2015-08-05: Simon Goldschmidt + * many files: allow multicast socket options IP_MULTICAST_TTL, IP_MULTICAST_IF + and IP_MULTICAST_LOOP to be used without IGMP + + 2015-04-24: Simon Goldschmidt + * dhcp.h/c, autoip.h/.c: added functions dhcp/autoip_supplied_address() to + check for the source of address assignment (replacement for NETIF_FLAG_DHCP) + + 2015-04-10: Simon Goldschmidt + * many files: task #13480: added LWIP_IPV4 define - IPv4 can be disabled, + leaving an IPv6-only stack + + 2015-04-09: Simon Goldschmidt + * nearly all files: task #12722 (improve IPv4/v6 address handling): renamed + ip_addr_t to ip4_addr_t, renamed ipX_addr_t to ip_addr_t and added IP + version; ip_addr_t is used for all generic IP addresses for the API, + ip(4/6)_addr_t are only used internally or when initializing netifs or when + calling version-related functions + + 2015-03-24: Simon Goldschmidt + * opt.h, ip4_addr.h, ip4.c, ip6.c: loopif is not required for loopback traffic + any more but passed through any netif (ENABLE_LOOPBACK has to be enabled) + + 2015-03-23: Simon Goldschmidt + * opt.h, etharp.c: with ETHARP_TABLE_MATCH_NETIF== 1, duplicate (Auto)-IP + addresses on multiple netifs should now be working correctly (if correctly + addressed by routing, that is) + + 2015-03-23: Simon Goldschmidt + * etharp.c: Stable etharp entries that are about to expire are now refreshed + using unicast to prevent unnecessary broadcast. Only if no answer is received + after 15 seconds, broadcast is used. + + 2015-03-06: Philip Gladstone + * netif.h/.c: patch #8359 (Provide utility function to add an IPv6 address to + an interface) + + 2015-03-05: Simon Goldschmidt + * netif.c, ip4.c, dhcp.c, autoip.c: fixed bug #37068 (netif up/down handling + is unclear): correclty separated administrative status of a netif (up/down) + from 'valid address' status + ATTENTION: netif_set_up() now always has to be called, even when dhcp/autoip + is used! + + 2015-02-26: patch by TabascoEye + * netif.c, udp.h/.c: fixed bug #40753 (re-bind UDP pcbs on change of IP address) + + 2015-02-22: chrysn, Simon Goldschmidt + * *.*: Changed nearly all functions taking 'ip(X)_addr_t' pointer to take + const pointers (changed user callbacks: raw_recv_fn, udp_recv_fn; changed + port callbacks: netif_output_fn, netif_igmp_mac_filter_fn) + + 2015-02-19: Ivan Delamer + * netif.h, dhcp.c: Removed unused netif flag for DHCP. The preferred way to evaluate + if DHCP is active is through netif->dhcp field. + + 2015-02-19: Ivan Delamer + * netif.h, slipif.c, ppp.c: Removed unused netif flag for point to point connections + + 2015-02-18: Simon Goldschmidt + * api_lib.c: fixed bug #37958 "netconn API doesn't handle correctly + connections half-closed by peer" + + 2015-02-18: Simon Goldschmidt + * tcp.c: tcp_alloc() prefers killing CLOSING/LAST_ACK over active connections + (see bug #39565) + + 2015-02-16: Claudius Zingerli, Sergio Caprile + * opt.h, dhcp.h/.c: patch #8361 "Add support for NTP option in DHCP" + + 2015-02-14: Simon Goldschmidt + * opt.h, snmp*: added support for write-access community and dedicated + community for sending traps + + 2015-02-13: Simon Goldschmidt + * opt.h, memp.c: added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when + a memp pool was empty and an item is now available + + 2015-02-13: Simon Goldschmidt + * opt.h, pbuf.h/.c, etharp.c: Added the option PBUF_LINK_ENCAPSULATION_HLEN to + allocate additional header space for TX on netifs requiring additional headers + + 2015-02-12: chrysn + * timers.h/.c: introduce sys_timeouts_sleeptime (returns the time left before + the next timeout is due, for NO_SYS==1) + + 2015-02-11: Nick van Ijzendoorn + * opt.h, sockets.h/c: patch #7702 "Include ability to increase the socket number + with defined offset" + + 2015-02-11: Frederick Baksik + * opt.h, def.h, others: patch #8423 "arch/perf.h" should be made an optional item + + 2015-02-11: Simon Goldschmidt + * api_msg.c, opt.h: started to implement fullduplex sockets/netconns + (note that this is highly unstable yet!) + + 2015-01-17: Simon Goldschmidt + * api: allow enabling socket API without (public) netconn API - netconn API is + still used by sockets, but keeping it private (static) should allow better + compiler optimizations + + 2015-01-16: Simon Goldschmidt + * tcp_in.c: fixed bug #20506 "Initial congestion window is very small" again + by implementing the calculation formula from RFC3390 + + 2014-12-10: Simon Goldschmidt + * api: added option LWIP_NETCONN_SEM_PER_THREAD to use a semaphore per thread + instead of using one per netconn and per select call + + 2014-12-08: Simon Goldschmidt + * ip6.h: fixed bug #43778: IPv6 header version not set on 16-bit platform + (macro IP6H_VTCFL_SET()) + + 2014-12-08: Simon Goldschmidt + * icmp.c, ip4.c, pbuf.c, udp.c, pbuf.h: task #11472 Support PBUF_REF for RX + (IPv6 and IPv4/v6 reassembly might not work yet) + + 2014-11-06: Simon Goldschmidt + * sockets.c/.h, init.c: lwip_socket_init() is not needed any more + -> compatibility define + + 2014-09-16: Simon Goldschmidt + * dns.c, opt.h: reduced ram usage by parsing DNS responses in place + + 2014-09-16: Simon Goldschmidt + * pbuf.h/.c: added pbuf_take_at() and pbuf_put_at() + + 2014-09-15: Simon Goldschmidt + * dns.c: added source port randomization to make the DNS client more robust + (see bug #43144) + + 2013-09-02: Simon Goldschmidt + * arch.h and many other files: added optional macros PACK_STRUCT_FLD_8() and + PACK_STRUCT_FLD_S() to prevent gcc 4 from warning about struct members that + do not need packing + + 2013-08-19: Simon Goldschmidt + * netif.h: bug #42998: made NETIF_MAX_HWADDR_LEN overridable for some special + networks + + 2013-03-17: Simon Goldschmidt (patch by Ghobad Emadi) + * opt.h, etharp.c: Added LWIP_HOOK_ETHARP_GET_GW to implement IPv4 routing with + multiple gateways + + 2013-04-20: Fatih Asici + * opt.h, etharp.h/.c: patch #7993: Added support for transmitting packets + with VLAN headers via hook function LWIP_HOOK_VLAN_SET and to check them + via hook function LWIP_HOOK_VLAN_CHECK + + 2014-02-20: Simon Goldschmidt (based on patch by Artem Pisarenko) + * patch #7885: modification of api modules to support FreeRTOS-MPU + (don't pass stack-pointers to other threads) + + 2014-02-05: Simon Goldschmidt (patch by "xtian" and "alex_ab") + * patch #6537/#7858: TCP window scaling support + + 2014-01-17: Jiri Engelthaler + * icmp, icmp6, opt.h: patch #8027: Completed HW checksuming for IPv4 and + IPv6 ICMP's + + 2012-08-22: Sylvain Rochet + * New PPP stack for lwIP, developed in ppp-new branch. + Based from pppd 2.4.5, released 2009-11-17, with huge changes to match + code size and memory requirements for embedded devices, including: + - Gluing together the previous low-level PPP code in lwIP to pppd 2.4.5, which + is more or less what pppd sys-* files are, so that we get something working + using the unix port. + - Merged some patchs from lwIP Git repository which add interesting features + or fix bugs. + - Merged some patchs from Debian pppd package which add interesting features + or fix bugs. + - Ported PPP timeout handling to the lwIP timers system + - Disabled all the PPP code using filesystem access, replaced in necessary cases + to configuration variables. + - Disabled all the PPP code forking processes. + - Removed IPX support, lwIP does not support IPX. + - Ported and improved random module from the previous PPP port. + - Removed samba TDB (file-driven database) usage, because it needs a filesystem. + - MS-CHAP required a DES implementation, we added the latest PolarSSL DES + implementation which is under a BSD-ish license. + - Also switched to PolarSSL MD4,MD5,SHA1 implementations, which are meant to be + used in embedded devices with reduced memory footprint. + - Removed PPP configuration file parsing support. + - Added macro definition EAP_SUPPORT to make EAP support optional. + - Added macro definition CHAP_SUPPORT to make CHAP support optional. + - Added macro definition MSCHAP_SUPPORT to make MSCHAP support optional. + - Added macro definition PAP_SUPPORT to make PAP support optional. + - Cleared all Linux syscall calls. + - Disabled demand support using a macro, so that it can be ported later. + - Disabled ECP support using a macro, so that it can be ported later. + - Disabled CCP support using a macro, so that it can be ported later. + - Disabled CBCP support using a macro, so that it can be ported later. + - Disabled LQR support using a macro, so that it can be ported later. + - Print packet debug feature optional, through PRINTPKT_SUPPORT + - Removed POSIX signal usage. + - Fully ported PPPoS code from the previous port. + - Fully ported PPPoE code from the previous port. + - Fully ported VJ compression protocol code from the previous port. + - Removed all malloc()/free() use from PPP, replaced by stack usage or PBUF. + - Disabled PPP server support using a macro, so that it can be ported later. + - Switched all PPP debug to lwIP debug system. + - Created PPP Control Block (PPP PCB), removed PPP unit integer everywhere, + removed all global variables everywhere, did everything necessary for + the PPP stack to support more than one PPP session (pppd only support + one session per process). + - Removed the statically allocated output buffer, now using PBUF. + - Improved structure size of all PPP modules, deep analyze of code to reduce + variables size to the bare minimum. Switched all boolean type (char type in + most architecture) to compiler generated bitfields. + - Added PPP IPv6 support, glued lwIP IPv6 support to PPP. + - Now using a persistent netif interface which can then be used in lwIP + functions requiring a netif. + - Now initializing PPP in lwip_init() function. + - Reworked completely the PPP state machine, so that we don't end up in + anymore in inconsistent state, especially with PPPoE. + - Improved the way we handle PPP reconnection after disconnect, cleaning + everything required so that we start the PPP connection again from a + clean state. + - Added PPP holdoff support, allow the lwIP user to wait a little bit before + reconnecting, prevents connection flood, especially when using PPPoL2TP. + - Added PPPoL2TP LAC support (a.k.a. UDP tunnels), adding a VPN client + feature to lwIP, L2TP being a widely used tunnel protocol. + - Switched all used PPP types to lwIP types (u8t, u16t, u32t, ...) + - Added PPP API "sequential" thread-safe API, based from NETIFAPI. + + 2011-07-21: Simon Goldschmidt + * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes + ioctl/FIONREAD return the size of the next pending datagram. + + 2011-05-25: Simon Goldschmidt + * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, + combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 + and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP + code so that the code is more readable. + + 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) + * nearly the whole stack: Finally, we got decent IPv6 support, big thanks to + Ivan! (this is work in progress: we're just post release anyway :-) + + + ++ Bugfixes: + + 2016-08-23: Simon Goldschmidt + * etharp: removed ETHARP_TRUST_IP_MAC since it is insecure and we don't need + it any more after implementing unicast ARP renewal towards arp entry timeout + + 2016-07-20: Simon Goldschmidt + * memp.h/.c: fixed bug #48442 (memp stats don't work for MEMP_MEM_MALLOC) + + 2016-07-21: Simon Goldschmidt (patch by Ambroz Bizjak) + * tcp_in.c, tcp_out.c: fixed bug #48543 (TCP sent callback may prematurely + report sent data when only part of a segment is acked) and don't include + SYN/FIN in snd_buf counter + + 2016-07-19: Simon Goldschmidt + * etharp.c: fixed bug #48477 (ARP input packet might update static entry) + + 2016-07-11: Simon Goldschmidt + * tcp_in.c: fixed bug #48476 (TCP sent callback called wrongly due to picking + up old pcb->acked + + 2016-06-30: Simon Goldschmidt (original patch by Fabian Koch) + * tcp_in.c: fixed bug #48170 (Vulnerable to TCP RST spoofing) + + 2016-05-20: Dirk Ziegelmeier + * sntp.h/.c: Fix return value of sntp_getserver() call to return a pointer + + 2016-04-05: Simon Goldschmidt (patch by Philip Gladstone) + * udp.c: patch #8358: allow more combinations of listening PCB for IPv6 + + 2016-04-05: Simon Goldschmidt + * netconn/socket API: fixed bug# 43739 (Accept not reporting errors about + aborted connections): netconn_accept() returns ERR_ABRT (sockets: ECONNABORTED) + for aborted connections, ERR_CLSD (sockets: EINVAL) if the listening netconn + is closed, which better seems to follow the standard. + + 2016-03-23: Florent Matignon + * dhcp.c: fixed bug #38203: DHCP options are not recorded in all DHCP ack messages + + 2016-03-22: Simon Goldschmidt + * tcp: changed accept handling to be done internally: the application does not + have to call tcp_accepted() any more. Instead, when delaying accept (e.g. sockets + do), call tcp_backlog_delayed()/tcp_backlog_accepted() (fixes bug #46696) + + 2016-03-22: Simon Goldschmidt + * dns.c: ignore dns response parsing errors, only abort resolving for correct + responses or error responses from correct server (bug #47459) + + 2016-03-17: Simon Goldschmidt + * api_msg.c: fixed bug #47448 (netconn/socket leak if RST is received during close) + + 2016-03-17: Joel Cunningham + * api_msg.c: don't fail closing a socket/netconn when failing to allocate the + FIN segment; blocking the calling thread for a while is better than risking + leaking a netconn/socket (see bug #46701) + + 2016-03-16: Joel Cunningham + * tcp_out.c: reset rto timer on fast retransmission + + 2016-03-16: Deomid Ryabkov + * tcp_out.c: fixed bug #46384 Segment size calculation bug with MSS != TCP_MSS + + 2016-03-05: Simon Goldschmidt + * err.h/.c, sockets.c: ERR_IF is not necessarily a fatal error + + 2015-11-19: fix by Kerem Hadimli + * sockets.c: fixed bug #46471: lwip_accept() leaks socket descriptors if new + netconn was already closed because of peer behavior + + 2015-11-12: fix by Valery Ushakov + * tcp_in.c: fixed bug #46365 tcp_accept_null() should call tcp_abort() + + 2015-10-02: Dirk Ziegelmeier/Simon Goldschmidt + * snmp: cleaned up snmp structs API (fixed race conditions from bug #46089, + reduce ram/rom usage of tables): incompatible change for private MIBs + + 2015-09-30: Simon Goldschmidt + * ip4_addr.c: fixed bug #46072: ip4addr_aton() does not check the number range + of all address parts + + 2015-08-28: Simon Goldschmidt + * tcp.c, tcp_in.c: fixed bug #44023: TCP ssthresh value is unclear: ssthresh + is set to the full send window for active open, too, and is updated once + after SYN to ensure the correct send window is used + + 2015-08-28: Simon Goldschmidt + * tcp: fixed bug #45559: Window scaling casts u32_t to u16_t without checks + + 2015-08-26: Simon Goldschmidt + * ip6_frag.h/.c: fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms: + define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header + instead of referencing it, which gives more room for struct ip6_reass_helper + + 2015-08-25: Simon Goldschmidt + * sockets.c: fixed bug #45827: recvfrom: TCP window is updated with MSG_PEEK + + 2015-08-20: Manoj Kumar + * snmp_msg.h, msg_in.c: fixed bug #43790: Sending octet string of Length >255 + from SNMP agent + + 2015-08-19: Jens Nielsen + * icmp.c, ip4.c, tcp_in.c, udp.c, raw.c: fixed bug #45120: Broadcast & multiple + interfaces handling + + 2015-08-19: Simon Goldschmidt (patch by "Sandra") + * dns.c: fixed bug #45004: dns response without answer might be discarded + + 2015-08-18: Chrysn + * timers.c: patch #8704 fix sys_timeouts_sleeptime function + + 2015-07-01: Erik Ekman + * puf.c: fixed bug #45454 (pbuf_take_at() skips write and returns OK if offset + is at start of pbuf in chain) + + 2015-05-19: Simon Goldschmidt + * dhcp.h/.c: fixed bugs #45140 and #45141 (dhcp was not stopped correctly after + fixing bug #38204) + + 2015-03-21: Simon Goldschmidt (patch by Homyak) + * tcp_in.c: fixed bug #44766 (LWIP_WND_SCALE: tcphdr->wnd was not scaled in + two places) + + 2015-03-21: Simon Goldschmidt + * tcp_impl.h, tcp.c, tcp_in.c: fixed bug #41318 (Bad memory ref in tcp_input() + after tcp_close()) + + 2015-03-21: Simon Goldschmidt + * tcp_in.c: fixed bug #38468 (tcp_sent() not called on half-open connection for + data ACKed with the same ack as FIN) + + 2015-03-21: Simon Goldschmidt (patch by Christoffer Lind) + * dhcp.h/.c: fixed bug #38204 (DHCP lease time not handled correctly) + + 2015-03-20: Simon Goldschmidt + * dhcp.c: fixed bug #38714 (Missing option and client address in DHCPRELEASE message) + + 2015-03-19: Simon Goldschmidt + * api.h, tcpip.h, api_lib.c, api_msg.c: fixed race conditions in assigning + netconn->last_err (fixed bugs #38121 and #37676) + + 2015-03-09: Simon Goldschmidt + * ip4.c: fixed the IPv4 part of bug #43904 (ip_route() must detect linkup status) + + 2015-03-04: Simon Goldschmidt + * nd6.c: fixed bug #43784 (a host should send at least one Router Solicitation) + + 2015-03-04: Valery Ushakov + * ip6.c: fixed bug #41094 (Byte-order bug in IPv6 fragmentation header test) + + 2015-03-04: Zach Smith + * nd6.c: fixed bug #38153 (nd6_input() byte order issues) + + 2015-02-26: Simon Goldschmidt + * netif.c, tcp.h/.c: fixed bug #44378 (TCP connections are not aborted on netif + remove) + + 2015-02-25: Simon Goldschmidt + * ip4.c, etharp.c: fixed bug #40177 (System hangs when dealing with corrupted + packets), implemented task #12357 (Ensure that malicious packets don't + assert-fail): improved some pbuf_header calls to not assert-fail. + + 2015-02-25: patch by Joel Cunningham + * udp.h/.c, sockets.c: fixed bug #43028 (IP_MULTICAST_TTL affects unicast + datagrams) + + 2015-02-25: patch by Greg Renda + * ip4_frag.c: fixed bug #38210 (ip reassembly while remove oldest datagram) + + 2015-02-25: Simon Goldschmidt + * sockets.c: fixed bug #38165 (socket with mulicast): ensure igmp membership + are dropped when socket (not netconn!) is closed. + + 2015-02-25: Simon Goldschmidt + * ip4.h/.c, udp.c: fixed bug #38061 (wrong multicast routing in IPv4) by + adding an optional default netif for multicast routing + + 2015-02-25: Simon Goldschmidt + * netconn API: fixed that netconn_connect still used message passing for + LWIP_TCPIP_CORE_LOCKING==1 + + 2015-02-22: patch by Jens Nielsen + * icmp.c: fixed bug #38803 (Source address in broadcast ping reply) + + 2015-02-22: Simon Goldschmidt + * udp.h, sockets.c: added proper accessor functions for pcb->multicast_ip + (previously used by get/setsockopt only) + + 2015-02-18: Simon Goldschmidt + * sockets.c: Fixed select not reporting received FIN as 'readable' in certain + rare cases (bug #43779: select(), close(), and TCP retransmission error) + + 2015-02-17: Simon Goldschmidt + * err.h, sockets.c, api_msg.c: fixed bug #38853 "connect() use a wrong errno": + return ERR_ALREADY/EALRADY during connect, ERR_ISCONN/EISCONN when already + connected + + 2015-02-17: Simon Goldschmidt + * tcp_impl.h, tcp_out.c, tcp.c, api_msg.c: fixed bug #37614 "Errors from + ipX_output are not processed". Now tcp_output(_segment) checks for the return + value of ipX_output and does not try to send more on error. A netif driver + can call tcp_txnow() (from tcpip_thread!) to try to send again if TX buffers + are available again. + + 2015-02-14: patches by Freddie Chopin + * snmp*: made community writable, fixed some const pointers + + 2015-02-13: Simon Goldschmidt + * msg_in.c: fixed bug #22070 "MIB_OBJECT_WRITE_ONLY not implemented in SNMP" + + 2015-02-12: Simon Goldschmidt + * ip.h, ip4.c, ip6.c: fixed bug #36403 "ip4_input() and ip6_input() always pass + inp to higher layers": now the accepting netif is passed up, but the input + netif is available through ip_current_input_netif() if required. + + 2015-02-11: patch by hichard + * tcpip.c: fixed bug #43094 "The function tcpip_input() forget to handle IPv6" + + 2015-02-10: Simon Goldschmidt + * netconn API: fixed that netconn_close/netconn_delete still used message passing + for LWIP_TCPIP_CORE_LOCKING==1 + + 2015-02-10: Simon Goldschmidt + * netconn/socket api: fixed bug #44225 "closing TCP socket should time out + eventually", implemented task #6930 "Implement SO_LINGER": closing TCP sockets + times out after 20 seconds or after the configured SND_TIMEOUT or depending + on the linger settings. + + 2015-01-27: Simon Goldschmidt + * api_msg.c: fixed that SHUT_RD followed by SHUT_WR was different to SHUT_RDWR, + fixed return value of lwip_netconn_do_close on unconnected netconns + + 2015-01-17: Simon Goldschmidt + * sockets.c: fixed bug #43361 select() crashes with stale FDs + + 2015-01-17: Simon Goldschmidt + * sockets.c/.h, memp_std.h: fixed bug #40788 "lwip_setsockopt_internal() crashes" + by rewriting set/getsockopt functions to combine checks with the actual code + and add more NULL checks; this also fixes that CORE_LOCKING used message + passing for set/getsockopt. + + 2014-12-19: Simon Goldschmidt + * opt.h, dhcp.h/.c: prevent dhcp from starting when netif link is down (only + when LWIP_DHCP_CHECK_LINK_UP==1, which is disabled by default for + compatibility reasons) + + 2014-12-17: Simon Goldschmidt + * tcp_out.c: fixed bug #43840 Checksum error for TCP_CHECKSUM_ON_COPY==1 for + no-copy data with odd length + + 2014-12-10: Simon Goldschmidt + * sockets.c, tcp.c, others: fixed bug #43797 set/getsockopt: SO_SNDTIMEO/SO_RCVTIMEO + take int as option but should take timeval (LWIP_SO_SNDRCVTIMEO_STANDARD==0 can + be used to revert to the old 'winsock' style behaviour) + Fixed implementation of SO_ACCEPTCONN to just look at the pcb state + + 2014-12-09: Simon Goldschmidt + * ip4.c: fixed bug #43596 IGMP queries from 0.0.0.0 are discarded + + 2014-10-21: Simon Goldschmidt (patch by Joel Cunningham and Albert Huitsing) + * sockts.c: fixed bugs #41495 Possible threading issue in select() and #43278 + event_callback() handle context switch when calling sys_sem_signal() + + 2014-10-21: Simon Goldschmidt + * api_msg.c: fixed bug #38219 Assert on TCP netconn_write with sndtimeout set + + 2014-09-16: Kevin Cernekee + * dns.c: patch #8480 Fix handling of dns_seqno wraparound + + 2014-09-16: Simon Goldschmidt + * tcp_out.c: fixed bug #43192 tcp_enqueue_flags() should not check TCP_SND_QUEUELEN + when sending FIN + + 2014-09-03: Simon Goldschmidt + * msg_in.c: fixed bug #39355 SNMP Memory Leak in case of error + + 2014-09-02: Simon Goldschmidt + * err.h/.c, sockets.c, api_msg.c: fixed bug #43110 call getpeername() before + listen() will cause a error + + 2014-09-02: Simon Goldschmidt + * sockets.c: fixed bug #42117 lwip_fcntl does not set errno + + 2014-09-02: Simon Goldschmidt + * tcp.c: fixed bug #42299 tcp_abort() leaves freed pcb on tcp_bound_pcbs list + + 2014-08-20: Simon Goldschmidt + * dns.c: fixed bug #42987 lwIP is vulnerable to DNS cache poisoning due to + non-randomized TXIDs + + 2014-06-03: Simon Goldschmidt + * tcp_impl.h, tcp_in.c: fixed bug #37969 SYN packet dropped as short packet in + tcp_input function + + 2014-05-20: Simon Goldschmidt + * tcp_out.c: fixed bug #37184 tcp_write problem for pcbs in the SYN_SENT state + + 2014-05-19: Simon Goldschmidt + * *.h: Fixed bug #35874 reserved identifier violation (removed leading underscores + from header include guards) + + 2014-04-08: Simon Goldschmidt + * tcp.c: Fixed bug #36167 tcp server crash when client closes (maximum window) + + 2014-04-06: Simon Goldschmidt + * tcp_in.c: Fixed bug #36210 lwIP does not elicit an empty ACK when received + unacceptable ACK + + 2014-04-06: Simon Goldschmidt + * dhcp.c, ip4.c/.h, ip6.c/.h, udp.c/.h, ip.h: Fixed bug #41787 DHCP Discovery + is invalid when an IP is set to thet netif. + + 2014-03-14: Simon Goldschmidt + * tcp_out.c: Fixed bug #36153 TCP Cheksum error if LWIP_CHECKSUM_ON_COPY=1 + + 2014-03-11: Simon Goldschmidt (patch by Mason) + * opt.h, sockets.c: fixed bug #35928 BSD sockets functions must set errno for + POSIX-compliance + + 2014-02-27: Simon Goldschmidt + * dhcp.c: fixed bug #40303 DHCP xid renewed when sending a DHCPREQUEST + + 2014-02-27: Simon Goldschmidt + * raw.c: fixed bug #41680 raw socket can not receive IPv6 packet when + IP_SOF_BROADCAST_RECV==1 + + 2014-02-27: Simon Goldschmidt + * api_msg.c, sockets.c: fixed bug #38404 getpeeraddr returns success on + unconnected/listening TCP sockets + + 2014-02-27: Simon Goldschmidt + * sockets.c: fixed bug #41729 Some socket functions return Exyz instead of -1 + + 2014-02-25: Simon Goldschmidt + * ip4.c: fixed bug #39514 ip_route() may return an IPv6-only interface + + 2014-02-25: Simon Goldschmidt, patch by Fatih Asici + * pbuf.c: fixed bug #39356 Wrong increment in pbuf_memfind() + + 2014-02-25: Simon Goldschmidt + * netif.c/.h, udp.c: fixed bug #39225 udp.c uses netif_matches_ip6_addr() incorrectly; + renamed function netif_matches_ip6_addr() to netif_get_ip6_addr_match() + + 2014-02-25: Simon Goldschmidt + * igmp.c: fixed bug #39145 IGMP membership report for 224.0.0.1 + + 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) + * etharp.c, opt.h: fixed bug #34681 Limit ARP queue length by ARP_QUEUE_LEN (=3) + + 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) + * etharp.h/.c: fixed bug #34682 Limit ARP request flood for unresolved entry + + 2014-02-20: Simon Goldschmidt + * tcp_out.c: fixed bug #39683 Assertion "seg->tcphdr not aligned" failed with + MEM_ALIGNMENT = 8 + + 2014-02-20: Simon Goldschmidt + * sockets.c: fixed bug #39882 No function shall set errno to 0 + + 2014-02-20: Simon Goldschmidt + * mib_structs.c: fixed bug #40050 SNMP problem with MIB arrays > 255 + + 2014-02-20: Simon Goldschmidt + * api.h, sockets.c: fixed bug #41499 netconn::recv_avail can overflow + + 2014-01-08: Stathis Voukelatos + * memp_std.h: patch #7928 Fixed size calculation in MALLOC memory pool + creation macro + + 2014-01-18: Brian Fahs + * tcp_out.c: patch #8237: tcp_rexmit_rto fails to update pcb->unsent_oversize + when necessary + + 2014-01-17: Grant Erickson, Jay Logue, Simon Goldschmidt + * ipv6.c, netif.c: patch #7913 Enable Support for IPv6 Loopback + + 2014-01-16: Stathis Voukelatos + * netif.c: patch #7902 Fixed netif_poll() operation when LWIP_LOOPBACK_MAX_PBUFS > 0 + + 2014-01-14: "Freddie Chopin" + * snmp.h, mib2.c: fixed constness and spelling of sysdescr + + 2014-01-14: Simon Goldschmidt (patch by Thomas Faber) + * tcpip.c: patch #8241: Fix implicit declaration of ip_input with + LWIP_TCPIP_CORE_LOCKING_INPUT disabled + + 2014-01-14: chrysn + * timers.c: patch #8244 make timeouts usable reliably from outside of the + timeout routine + + 2014-01-10: Simon Goldschmidt + * ip_frag.c, ip6_frag.c: fixed bug #41041 Potential use-after-free in IPv6 reassembly + + 2014-01-10: Simon Goldschmidt + * memp.c: fixed bug #41188 Alignment error in memp_init() when MEMP_SEPARATE_POOLS==1 + + 2014-01-10: Simon Goldschmidt + * tcp.c: fixed bug #39898 tcp_fasttmr() possible lock due to infinte queue process loop + + 2013-06-29: Simon Goldschmidt + * inet.h, sockets.h: partially fixed bug #37585: IPv6 compatibility (in socket structs) + + 2013-06-29: Simon Goldschmidt + * inet6.h: bug #37585/task #12600: fixed struct in6_addr.s6_addr to conform to spec + + 2013-04-24: patch by Liam + * api_msg.c: patch #8008 Fix a potential null pointer dereference in assert + + 2013-04-24: Simon Goldschmidt + * igmp.c: fixed possible division by zero + + 2013-04-24: Simon Goldschmidt + * ip6.h, some ipv6 C files: fixed bug #38526 Coverity: Recursive Header Inclusion in ip6.h + + 2013-04-24: Simon Goldschmidt (patch by Emil Ljungdahl): + * netif.c: fixed bug #38586 netif_loop_output() "deadlocks" + + 2013-01-15: Simon Goldschmidt + * ip4.c: fixed bug #37665 ip_canforward operates on address in wrong byte order + + 2013-01-15: Simon Goldschmidt + * pbuf.h: fixed bug #38097 pbuf_free_ooseq() warning + + 2013-01-14: Simon Goldschmidt + * dns.c: fixed bug #37705 Possible memory corruption in DNS query + + 2013-01-11: Simon Goldschmidt + * raw.c: fixed bug #38066 Raw pcbs can alter packet without eating it + + 2012-08-22: Simon Goldschmidt + * memp.c: fixed bug #37166: memp_sanity check loops itself + + 2012-08-13: Simon Goldschmidt + * dhcp.c: fixed bug #36645: Calling dhcp_release before dhcp_start + dereferences NULL + + 2012-08-13: Simon Goldschmidt + * msg_out.c: fixed bug #36840 snmp_send_trap() NULL de-reference if traps + configured but no interfaces available + + 2012-08-13: Simon Goldschmidt + * dns.c: fixed bug #36899 DNS TTL 0 is cached for a long time + + 2012-05-11: Simon Goldschmidt (patch by Marty) + * memp.c: fixed bug #36412: memp.c does not compile when + MEMP_OVERFLOW_CHECK > zero and MEMP_SEPARATE_POOLS == 1 + + 2012-05-03: Simon Goldschmidt (patch by Sylvain Rochet) + * ppp.c: fixed bug #36283 (PPP struct used on header size computation and + not packed) + + 2012-05-03: Simon Goldschmidt (patch by David Empson) + * ppp.c: fixed bug #36388 (PPP: checksum-only in last pbuf leads to pbuf with + zero length) + + 2012-03-25: Simon Goldschmidt + * api_msg.c: Fixed bug #35817: do_connect() invalidly signals op_completed + for UDP/RAW with LWIP_TCPIP_CORE_LOCKING==1 + + 2012-03-25: Simon Goldschmidt + * api_msg.h, api_lib.c, api_msg.c, netifapi.c: fixed bug #35931: Name space + pollution in api_msg.c and netifapi.c + + 2011-08-24: Simon Goldschmidt + * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard + + + +(STABLE-1.4.1) + + ++ New features: + + 2012-03-25: Simon Goldschmidt (idea by Mason) + * posix/*: added posix-compatibility include files posix/netdb.h and posix/sys/socket.h + which are a simple wrapper to the correct lwIP include files. + + 2012-01-16: Simon Goldschmidt + * opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP + + 2011-12-17: Simon Goldschmidt + * ip.h: implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW) + (fixes bug #35061) + + 2011-09-27: Simon Goldschmidt + * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989) + (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h) + + 2011-09-21: Simon Goldschmidt + * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on + send (TCP only, bug #33820) + + 2011-09-21: Simon Goldschmidt + * init.c: Converted runtime-sanity-checks into compile-time checks that can + be disabled (since runtime checks can often not be seen on embedded targets) + + 2011-09-11: Simon Goldschmidt + * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file + to get a clear separation of which functions an application or port may use + (task #11281) + + 2011-09-11: Simon Goldschmidt + * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize + initial local TCP/UDP ports (so that different port ranges are used after + a reboot; bug #33818; this one added tcp_init/udp_init functions again) + + 2011-09-03: Simon Goldschmidt + * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) + + 2011-08-24: Simon Goldschmidt + * opt.h, netif.h/.c: added netif remove callback (bug #32397) + + 2011-07-26: Simon Goldschmidt + * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter + function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) + + 2011-07-21: Simon Goldschmidt (patch by hanhui) + * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: + Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. + Also added code to allow ip_forward() to forward non-broadcast packets to + the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). + + 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) + * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that + pcb->state != LISTEN + + 2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage) + * tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static + memory message + + + ++ Bugfixes: + + 2012-09-26: Simon Goldschmidt + * api_msg.c: fixed bug #37405 'err_tcp()' uses already freed 'netconn' object + + 2012-09-26: patch by Henrik Persson + * dhcp.c: patch #7843 Fix corner case with dhcp timeouts + + 2012-09-26: patch by Henrik Persson + * dhcp.c: patch #7840 Segfault in dhcp_parse_reply if no end marker in dhcp packet + + 2012-08-22: Simon Goldschmidt + * memp.c: fixed bug #37166: memp_sanity check loops itself + + 2012-05-08: Simon Goldschmidt + * tcp_out.c: fixed bug: #36380 unsent_oversize mismatch in 1.4.1RC1 (this was + a debug-check issue only) + + 2012-03-27: Simon Goldschmidt + * vj.c: fixed bug #35756 header length calculation problem in ppp/vj.c + + 2012-03-27: Simon Goldschmidt (patch by Mason) + * tcp_out.c: fixed bug #35945: SYN packet should provide the recv MSS not the + send MSS + + 2012-03-22: Simon Goldschmidt + * ip4.c: fixed bug #35927: missing refragmentaion in ip_forward + + 2012-03-20: Simon Goldschmidt (patch by Mason) + * netdb.c: fixed bug #35907: lwip_gethostbyname_r returns an invalid h_addr_list + + 2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic) + * ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, + possible bug on little endian system + + 2012-02-23: Simon Goldschmidt + * etharp.c: fixed bug #35595: Impossible to send broadcast without a gateway + (introduced when fixing bug# 33551) + + 2012-02-16: Simon Goldschmidt + * ppp.c: fixed pbuf leak when PPP session is aborted through pppSigHUP() + (bug #35541: PPP Memory Leak) + + 2012-02-16: Simon Goldschmidt + * etharp.c: fixed bug #35531: Impossible to send multicast without a gateway + (introduced when fixing bug# 33551) + + 2012-02-16: Simon Goldschmidt (patch by Stéphane Lesage) + * msg_in.c, msg_out.c: fixed bug #35536 SNMP: error too big response is malformed + + 2012-02-15: Simon Goldschmidt + * init.c: fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with + MEMP_MEM_MALLOC==1 + + 2012-02-12: Simon Goldschmidt + * tcp.h, tcp_in.c, tcp_out.c: partly fixed bug #25882: TCP hangs on + MSS > pcb->snd_wnd (by not creating segments bigger than half the window) + + 2012-02-11: Simon Goldschmidt + * tcp.c: fixed bug #35435: No pcb state check before adding it to time-wait + queue while closing + + 2012-01-22: Simon Goldschmidt + * tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR) + + 2012-01-21: Simon Goldschmidt + * tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb + + 2012-01-20: Simon Goldschmidt + * dhcp.c: fixed bug #35151: DHCP asserts on incoming option lengths + + 2012-01-20: Simon Goldschmidt + * pbuf.c: fixed bug #35291: NULL pointer in pbuf_copy + + 2011-11-25: Simon Goldschmidt + * tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt + tcp_active_pcbs in some cases + + 2011-11-23: Simon Goldschmidt + * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with + '#ifndef sys_msleep' + + 2011-11-22: Simon Goldschmidt + * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when + netif is brought down + + 2011-10-28: Simon Goldschmidt + * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks + + 2011-10-23: Simon Goldschmidt + * mem.c: fixed bug #34429: possible memory corruption with + LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 + + 2011-10-18: Simon Goldschmidt + * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard + error value + + 2011-10-18: Simon Goldschmidt + * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small + windows (bug #34176 select after non-blocking send times out) + + 2011-10-18: Simon Goldschmidt + * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't + consider netif->mtu, causes slow network + + 2011-10-18: Simon Goldschmidt + * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code + + 2011-10-18: Simon Goldschmidt + * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS + + 2011-10-17: Simon Goldschmidt + * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api + + 2011-10-13: Simon Goldschmidt + * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no + zero window is received) by starting the persist timer when a zero window is + received, not when we have more data queued for sending than fits into the + window + + 2011-10-13: Simon Goldschmidt + * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex + + 2011-10-13: Simon Goldschmidt + * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is + used and not all protocols are enabled + + 2011-10-12: Simon Goldschmidt + * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 + + 2011-10-09: Simon Goldschmidt + * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect + byte value when pcb->unacked != NULL + + 2011-10-09: Simon Goldschmidt + * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong + + 2011-09-27: Simon Goldschmidt + * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... + + 2011-09-27: Simon Goldschmidt + * tcp_in.c: fixed bug #28288: Data after FIN in oos queue + + 2011-09-27: Simon Goldschmidt + * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf + + 2011-09-24: Simon Goldschmidt + * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 + + 2011-09-23: Simon Goldschmidt + * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for + the last packet including FIN can lose data + + 2011-09-22: Simon Goldschmidt + * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into + account + + 2011-09-21: Simon Goldschmidt + * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks + in init.c + + 2011-09-20: Simon Goldschmidt + * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) + + 2011-09-11: Simon Goldschmidt + * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs + (bug #34019) + + 2011-09-09: Simon Goldschmidt + * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if + udp port matches + + 2011-09-03: Simon Goldschmidt + * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet + is aggregated and sent to application + + 2011-09-01: Simon Goldschmidt + * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared + to other options + + 2011-09-01: Simon Goldschmidt + * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno + + 2011-08-24: Simon Goldschmidt + * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling + accept() on UDP connections + + 2011-08-24: Simon Goldschmidt + * sockets.h: fixed bug #34057 socklen_t should be a typedef + + 2011-08-24: Simon Goldschmidt + * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) + + 2011-08-24: Simon Goldschmidt + * dhcp.c: fixed bug #34122 dhcp: hostname can overflow + + 2011-08-24: Simon Goldschmidt + * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr + + 2011-08-22: Simon Goldschmidt + * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This + merely prevents nagle from not transmitting fast after closing.) + + 2011-07-22: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns + always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now + lwip_send() sends as much as possible for non-blocking sockets + + 2011-07-22: Simon Goldschmidt + * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented + for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level. + + 2011-07-21: Simon Goldschmidt + * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by + sending an ARP request when an ARP entry is used in the last minute before + it would time out. + + 2011-07-04: Simon Goldschmidt + * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. + + 2011-06-26: Simon Goldschmidt + * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by + updating its documentation only. + + 2011-06-26: Simon Goldschmidt + * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an + unaligned pointer. + + 2011-06-26: Simon Goldschmidt + * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" + + 2011-05-25: Simon Goldschmidt + * tcp.c: fixed bug #33398 (pointless conversion when checking TCP port range) + + + +(STABLE-1.4.0) + + ++ New features: + + 2011-03-27: Simon Goldschmidt + * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and + calculate it in tcp_zero_window_probe (the only place where it was used). + + 2010-11-21: Simon Goldschmidt + * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif + (fixes bug #31525). + + 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) + * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for + IP_MULTICAST_LOOP at socket- and raw-API level. + + 2010-06-16: Simon Goldschmidt + * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow + link-layer-addressed UDP traffic to be received while a netif is down (just + like DHCP during configuration) + + 2010-05-22: Simon Goldschmidt + * many many files: bug #27352: removed packing from ip_addr_t, the packed + version is now only used in protocol headers. Added global storage for + current src/dest IP address while in input functions. + + 2010-05-16: Simon Goldschmidt + * def.h: task #10391: Add preprocessor-macros for compile-time htonl + calculation (and use them throughout the stack where applicable) + + 2010-05-16: Simon Goldschmidt + * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool + instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h) + + 2010-05-16: Simon Goldschmidt + * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own + MEMP pool instead of the heap + + 2010-05-13: Simon Goldschmidt + * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added + new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast + packets to more than one pcb. + + 2010-05-02: Simon Goldschmidt + * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending + UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 + + 2010-04-30: Simon Goldschmidt + * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that + take a precalculated checksum, added pbuf_fill_chksum() to copy data + into a pbuf and at the same time calculating the checksum for that data + + 2010-04-29: Simon Goldschmidt + * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying + 2-byte-aligned IP addresses and MAC addresses + + 2010-04-28: Patch by Bill Auerbach + * ip.c: Inline generating IP checksum to save a function call + + 2010-04-14: Simon Goldschmidt + * tcpip.h/.c, timers.c: Added an overridable define to get informed when the + tcpip_thread processes messages or timeouts to implement a watchdog. + + 2010-03-28: Simon Goldschmidt + * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing + fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 + + 2010-03-27: Simon Goldschmidt + * etharp.c: Speedup TX by moving code from find_entry to etharp_output/ + etharp_query to prevent unnecessary function calls (inspired by + patch #7135). + + 2010-03-20: Simon Goldschmidt + * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code + since the linker cannot do this automatically to save space. + + 2010-03-20: Simon Goldschmidt + * opt.h, etharp.c/.h: Added support for static ARP table entries + + 2010-03-14: Simon Goldschmidt + * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum + when creating TCP segments, not when (re-)transmitting them. + + 2010-03-07: Simon Goldschmidt + * sockets.c: bug #28775 (select/event_callback: only check select_cb_list + on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code. + This should speed up receiving data on sockets as the select code in + event_callback is only executed when select is waiting. + + 2010-03-06: Simon Goldschmidt + * tcp_out.c: task #7013 (Create option to have all packets delivered to + netif->output in one piece): Always copy to try to create single pbufs + in tcp_write. + + 2010-03-06: Simon Goldschmidt + * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv + by not allocating a netbuf): added function netconn_recv_tcp_pbuf() + for tcp netconns to receive pbufs, not netbufs; use that function + for tcp sockets. + + 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt + * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040: + Work on tcp_enqueue: Don't waste memory when chaining segments, + added option TCP_OVERSIZE to prevent creating many small pbufs when + calling tcp_write with many small blocks of data. Instead, pbufs are + allocated larger than needed and the space is used for later calls to + tcp_write. + + 2010-02-21: Simon Goldschmidt + * stats.c/.h: Added const char* name to mem- and memp-stats for easier + debugging. + + 2010-02-21: Simon Goldschmidt + * tcp.h (and usages), added tcp_impl.h: Splitted API and internal + implementation of tcp to make API usage cleare to application programmers + + 2010-02-14: Simon Goldschmidt/Stephane Lesage + * ip_addr.h: Improved some defines working on ip addresses, added faster + macro to copy addresses that cannot be NULL + + 2010-02-13: Simon Goldschmidt + * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non- + blocking send operation) + + 2010-02-12: Simon Goldschmidt + * sockets.c/.h: Added a minimal version of posix fctl() to have a + standardised way to set O_NONBLOCK for nonblocking sockets. + + 2010-02-12: Simon Goldschmidt + * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated + memory): added autoip_set_struct() and dhcp_set_struct() to let autoip + and dhcp work with user-allocated structs instead of callin mem_malloc + + 2010-02-12: Simon Goldschmidt/Jeff Barber + * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has + SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT + + 2010-02-12: Simon Goldschmidt + * sys layer: task #10139 (Prefer statically allocated memory): converted + mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t; + converted sys_mbox_new/sys_sem_new to take pointers and return err_t; + task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX + to let sys.h use binary semaphores instead of mutexes - as before) + + 2010-02-09: Simon Goldschmidt (Simon Kallweit) + * timers.c/.h: Added function sys_restart_timeouts() from patch #7085 + (Restart system timeout handling) + + 2010-02-09: Simon Goldschmidt + * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into + netif.c) - loopif does not have to be created by the port any more, + just define LWIP_HAVE_LOOPIF to 1. + + 2010-02-08: Simon Goldschmidt + * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa + inet_ntoa_r/ipaddr_ntoa_r + + 2010-02-08: Simon Goldschmidt + * netif.h: Added netif_s/get_igmp_mac_filter() macros + + 2010-02-05: Simon Goldschmidt + * netif.h: Added function-like macros to get/set the hostname on a netif + + 2010-02-04: Simon Goldschmidt + * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to + make changing the actual implementation behind the typedef easier. + + 2010-02-01: Simon Goldschmidt + * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool + for allocating memory when getaddrinfo() is called. + + 2010-01-31: Simon Goldschmidt + * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse + them once instead of parsing for every option. This also removes + the need for mem_malloc from dhcp_recv and makes it possible to + correctly retrieve the BOOTP file. + + 2010-01-30: simon Goldschmidt + * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect + the sockets array. + + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) + * api.h, api_msg.c, sockets.c: Added except set support in select + (patch #6860) + + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) + * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: + Add non-blocking support for connect (partly from patch #6860), + plus many cleanups in socket & netconn API. + + 2010-01-27: Simon Goldschmidt + * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding + to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 + + 2010-01-26: Simon Goldschmidt + * snmp: Use memp pools for snmp instead of the heap; added 4 new pools. + + 2010-01-14: Simon Goldschmidt + * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback + by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() + + 2010-01-13: Simon Goldschmidt + * mem.c: The heap now may be moved to user-defined memory by defining + LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address + (patch #6966 and bug #26133) + + 2010-01-10: Simon Goldschmidt (Bill Auerbach) + * opt.h, memp.c: patch #6822 (Add option to place memory pools in + separate arrays) + + 2010-01-10: Simon Goldschmidt + * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define + LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) + + 2009-12-31: Simon Goldschmidt + * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h + added timers.c/.h: Separated timer implementation from semaphore/mbox + implementation, moved timer implementation to timers.c/.h, timers are + now only called from tcpip_thread or by explicitly checking them. + (TASK#7235) + + 2009-12-27: Simon Goldschmidt + * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option + LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) + + + ++ Bugfixes: + + 2011-04-20: Simon Goldschmidt + * sys_arch.txt: sys_arch_timeouts() is not needed any more. + + 2011-04-13: Simon Goldschmidt + * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by + using ports in the IANA private/dynamic range (49152 through 65535). + + 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl: + * etharp.h/.c: Fixed broken VLAN support. + + 2011-03-27: Simon Goldschmidt + * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp + pcbs) by checking if the pcb was bound (local_port != 0). + + 2011-03-27: Simon Goldschmidt + * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice) + + 2011-03-27: Simon Goldschmidt + * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and + raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. + + 2011-03-27: Simon Goldschmidt + * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route + is present never times out) by starting retransmission timer before checking + route. + + 2011-03-22: Simon Goldschmidt + * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only + calling sio_read_abort() if the file descriptor is valid. + + 2011-03-14: Simon Goldschmidt + * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect + more than once can render a socket useless) since it mainly involves changing + "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal. + + 2011-03-13: Simon Goldschmidt + * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing + err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN: + use EALRADY instead of -1 + + 2011-03-13: Simon Goldschmidt + * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the + connection has been aborted by err_tcp (since this is not a normal closing + procedure). + + 2011-03-13: Simon Goldschmidt + * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind + with pcb->state != CLOSED + + 2011-02-17: Simon Goldschmidt + * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in + documentation + + 2011-02-17: Simon Goldschmidt + * many files: Added missing U/UL modifiers to fix 16-bit-arch portability. + + 2011-01-24: Simon Goldschmidt + * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems + + 2010-12-02: Simon Goldschmidt + * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. + + 2010-11-23: Simon Goldschmidt + * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for + LWIP_SO_RCVBUF and ioctl/FIONREAD. + + 2010-11-23: Simon Goldschmidt + * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at + least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet. + + 2010-11-23: Simon Goldschmidt + * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after + refusing 'refused_data' again. + + 2010-11-22: Simon Goldschmidt + * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS + after a successful nonblocking connection. + + 2010-11-22: Simon Goldschmidt + * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr + must be sent link-local + + 2010-11-22: Simon Goldschmidt + * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for + LWIP_TIMERS==0 + + 2010-11-20: Simon Goldschmidt + * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number + + 2010-11-20: Simon Goldschmidt + * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to + resemble other stacks. + + 2010-11-20: Simon Goldschmidt + * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else + no-copy TCP writes will never succeed. + + 2010-11-20: Simon Goldschmidt + * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does + not match documentation: return ERR_ARG instead of ERR_VAL if not + initialized or wrong argument. + + 2010-10-20: Simon Goldschmidt + * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 + + 2010-10-05: Simon Goldschmidt + * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when + replugging the network cable after an AutoIP address was assigned. + + 2010-08-10: Simon Goldschmidt + * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs + + 2010-08-03: Simon Goldschmidt + * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625) + + 2010-08-01: Simon Goldschmidt (patch by Greg Renda) + * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big + endian architectures) + + 2010-07-28: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP + disabled. + + 2010-07-27: Simon Goldschmidt + * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no + harm but never did anything + + 2010-07-21: Simon Goldschmidt + * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not + add IP options) + + 2010-07-16: Kieran Mansley + * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator + + 2010-07-10: Simon Goldschmidt + * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options + + 2010-06-30: Simon Goldschmidt + * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in + netconn_delete) + + 2010-06-28: Kieran Mansley + * timers.c remove unportable printing of C function pointers + + 2010-06-24: Simon Goldschmidt + * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag + NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading + + 2010-06-24: Simon Goldschmidt + * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly + implemented shutdown at socket level. + + 2010-06-21: Simon Goldschmidt + * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has + problems with zero-copy DMA MACs) by adding custom pbufs and implementing + custom pbufs that reference other (original) pbufs. Additionally set + IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side. + + 2010-06-15: Simon Goldschmidt + * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses + + 2010-06-14: Simon Goldschmidt + * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses + + 2010-06-12: Simon Goldschmidt + * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop + state + + 2010-05-17: Simon Goldschmidt + * netdb.c: Correctly NULL-terminate h_addr_list + + 2010-05-16: Simon Goldschmidt + * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent + "symbol already defined" i.e. when linking to winsock + + 2010-05-05: Simon Goldschmidt + * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may + overflow) + + 2010-04-21: Simon Goldschmidt + * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening + connection) + + 2010-03-28: Luca Ceresoli + * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers + + 2010-03-27: Luca Ceresoli + * mib2.c: patch #7130: remove meaningless const qualifiers + + 2010-03-26: Simon Goldschmidt + * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too + + 2010-03-26: Simon Goldschmidt + * various files: Fixed compiling with different options disabled (TCP/UDP), + triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled + + 2010-03-25: Simon Goldschmidt + * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly + + 2010-03-25: Simon Goldschmidt + * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side + overrunning our rcv_wnd in ooseq case. + + 2010-03-22: Simon Goldschmidt + * tcp.c: tcp_listen() did not copy the pcb's prio. + + 2010-03-19: Simon Goldschmidt + * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set + + 2010-03-14: Simon Goldschmidt + * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports + where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h + and basing PBUF_LINK_HLEN on it. + + 2010-03-08: Simon Goldschmidt + * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections + when assiging routable address): when checking incoming packets and + aborting existing connection on address change, filter out link-local + addresses. + + 2010-03-06: Simon Goldschmidt + * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING + + 2010-03-06: Simon Goldschmidt + * ipv4/ip.c: Don't try to forward link-local addresses + + 2010-03-06: Simon Goldschmidt + * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal- + addresses to gw + + 2010-03-05: Simon Goldschmidt + * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type + and state. + + 2010-03-05: Simon Goldschmidt + * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split + into multiple calls to tcp_write. + + 2010-02-21: Simon Goldschmidt + * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep + the implementation of DNS_USES_STATIC_BUF==1) + + 2010-02-20: Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement + close() vs. shutdown(). Now the application does not get any more + recv callbacks after calling tcp_close(). Added tcp_shutdown(). + + 2010-02-19: Simon Goldschmidt + * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent + confusion with realloc() + + 2010-02-15: Simon Goldschmidt/Stephane Lesage + * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK + (fixes bug #28899) + + 2010-02-14: Simon Goldschmidt + * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with + LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and + admin-status of a netif are up + + 2010-02-14: Simon Goldschmidt + * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet + reception and is not really necessary + + 2010-02-14: Simon Goldschmidt + * etharp.c/.h: Fixed ARP input processing: only add a new entry if a + request was directed as us (RFC 826, Packet Reception), otherwise + only update existing entries; internalized some functions + + 2010-02-14: Simon Goldschmidt + * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be + disabled on netif used for PPPoE) by adding a new netif flag + (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet + device but prevents usage of ARP (so that ethernet_input can be used + for PPPoE). + + 2010-02-12: Simon Goldschmidt + * netif.c: netif_set_link_up/down: only do something if the link state + actually changes + + 2010-02-12: Simon Goldschmidt/Stephane Lesage + * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking + connect) + + 2010-02-12: Simon Goldschmidt + * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h) + + 2010-02-09: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110 + (recv() makes receive window update for data that wasn't received by + application) + + 2010-02-09: Simon Goldschmidt/Stephane Lesage + * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out + or any netconn_recv() error) + + 2010-02-09: Simon Goldschmidt + * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets) + + 2010-02-09: Simon Goldschmidt + * netif.c: For loopback packets, adjust the stats- and snmp-counters + for the loopback netif. + + 2010-02-08: Simon Goldschmidt + * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity + since they are not used anywhere else. + + 2010-02-08: Simon Goldschmidt (Stéphane Lesage) + * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats + (patch from bug #28798) + + 2010-02-08: Simon Goldschmidt (Stéphane Lesage) + * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and + another bug when LWIP_RAND() returns zero. + + 2010-02-04: Simon Goldschmidt + * nearly every file: Use macros defined in ip_addr.h (some of them new) + to work with IP addresses (preparation for bug #27352 - Change ip_addr + from struct to typedef (u32_t) - and better code). + + 2010-01-31: Simon Goldschmidt + * netif.c: Don't call the link-callback from netif_set_up/down() since + this invalidly retriggers DHCP. + + 2010-01-29: Simon Goldschmidt + * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the + portability file inet.h and its contents from the stack: moved htonX- + functions to def.h (and the new def.c - they are not ipv4 dependent), + let inet.h depend on ip_addr.h and not the other way round. + This fixes bug #28732. + + 2010-01-28: Kieran Mansley + * tcp.c: Ensure ssthresh >= 2*MSS + + 2010-01-27: Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv + callback can lead to accessing unallocated memory. As a consequence, + ERR_ABRT means the application has called tcp_abort()! + + 2010-01-25: Simon Goldschmidt + * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY + not implemented in SNMP): write-only or not-accessible are still + returned by getnext (though not by get) + + 2010-01-24: Simon Goldschmidt + * snmp: Renamed the private mib node from 'private' to 'mib_private' to + not use reserved C/C++ keywords + + 2010-01-23: Simon Goldschmidt + * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less + than 1 ms + + 2010-01-21: Simon Goldschmidt + * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called + if tcp_enqueue fails) both in raw- and netconn-API + + 2010-01-19: Simon Goldschmidt + * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp + + 2010-01-18: Iordan Neshev/Simon Goldschmidt + * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some + bugfix backports from 2.4.x. + + 2010-01-18: Simon Goldschmidt + * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong + + 2010-01-17: Simon Goldschmidt + * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): + task #10102: "netconn: clean up conn->err threading issues" by adding + error return value to struct api_msg_msg + + 2010-01-17: Simon Goldschmidt + * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() + to return err_t (bugs #27709 and #28087) + + 2010-01-14: Simon Goldschmidt + * ...: Use typedef for function prototypes throughout the stack. + + 2010-01-13: Simon Goldschmidt + * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive + window = 0) by correctly draining recvmbox/acceptmbox + + 2010-01-11: Simon Goldschmidt + * pap.c: Fixed bug #13315 (PPP PAP authentication can result in + erroneous callbacks) by copying the code from recent pppd + + 2010-01-10: Simon Goldschmidt + * raw.c: Fixed bug #28506 (raw_bind should filter received packets) + + 2010-01-10: Simon Goldschmidt + * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)()) + + 2010-01-08: Simon Goldschmidt + * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535) + + 2010-01-08: Simon Goldschmidt + * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string + passed to dns_local_addhost() might be volatile + + 2010-01-07: Simon Goldschmidt + * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too + + 2010-01-06: Simon Goldschmidt + * netdb.h: Fixed bug #28496: missing include guards in netdb.h + + 2009-12-31: Simon Goldschmidt + * many ppp files: Reorganised PPP source code from ucip structure to pppd + structure to easily compare our code against the pppd code (around v2.3.1) + + 2009-12-27: Simon Goldschmidt + * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted + unit test + + +(STABLE-1.3.2) + + ++ New features: + + 2009-10-27 Simon Goldschmidt/Stephan Lesage + * netifapi.c/.h: Added netifapi_netif_set_addr() + + 2009-10-07 Simon Goldschmidt/Fabian Koch + * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to + support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO) + + 2009-08-26 Simon Goldschmidt/Simon Kallweit + * slipif.c/.h: bug #26397: SLIP polling support + + 2009-08-25 Simon Goldschmidt + * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN), + New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK. + + 2009-08-25 Simon Goldschmidt + * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*) + + 2009-08-24 Jakob Stoklund Olesen + * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond + to netif_set_link_up(). + + 2009-08-23 Simon Goldschmidt + * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state + to a human-readable string. + + ++ Bugfixes: + + 2009-12-24: Kieran Mansley + * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing + (BUG#28241) + + 2009-12-06: Simon Goldschmidt + * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can + be statically allocated (like in ucip) + + 2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev) + * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT + + 2009-12-03: Simon Goldschmidt + * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit + could have non-zero length + + 2009-12-02: Simon Goldschmidt + * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting + tcp_input_pcb until after calling the pcb's callbacks + + 2009-11-29: Simon Goldschmidt + * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of- + sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code + + 2009-11-29: Simon Goldschmidt + * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by + queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty + + 2009-11-26: Simon Goldschmidt + * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending + segment + + 2009-11-26: Simon Goldschmidt + * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle + algorithm at PCB level + + 2009-11-22: Simon Goldschmidt + * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent + + 2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach) + * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when + reusing time-wait pcb + + 2009-11-20: Simon Goldschmidt (patch by Albert Bartel) + * sockets.c: Fixed bug #28062: Data received directly after accepting + does not wake up select + + 2009-11-11: Simon Goldschmidt + * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo) + + 2009-10-30: Simon Goldschmidt + * opt.h: Increased default value for TCP_MSS to 536, updated default + value for TCP_WND to 4*TCP_MSS to keep delayed ACK working. + + 2009-10-28: Kieran Mansley + * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code + to follow algorithm from TCP/IP Illustrated + + 2009-10-27: Kieran Mansley + * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK + + 2009-10-25: Simon Goldschmidt + * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if + pcb->recv is NULL to keep rcv_wnd correct) + + 2009-10-25: Simon Goldschmidt + * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state + + 2009-10-23: Simon Goldschmidt (David Empson) + * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes + + 2009-10-21: Simon Goldschmidt + * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and + trailing 1 byte len (SYN/FIN) + + 2009-10-21: Simon Goldschmidt + * tcp_out.c: Fixed bug #27315: zero window probe and FIN + + 2009-10-19: Simon Goldschmidt + * dhcp.c/.h: Minor code simplification (don't store received pbuf, change + conditional code to assert where applicable), check pbuf length before + testing for valid reply + + 2009-10-19: Simon Goldschmidt + * dhcp.c: Removed most calls to udp_connect since they aren't necessary + when using udp_sendto_if() - always stay connected to IP_ADDR_ANY. + + 2009-10-16: Simon Goldschmidt + * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop + valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is + enabled + + 2009-10-15: Simon Goldschmidt (Oleg Tyshev) + * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit + + 2009-10-15: Simon Goldschmidt + * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv() + timeout + + 2009-10-15: Simon Goldschmidt + * autoip.c: Fixed bug #27704: autoip starts with wrong address + LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead + of network byte order + + 2009-10-11 Simon Goldschmidt (Jörg Kesten) + * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments + which are not consecutive when retransmitting unacked segments + + 2009-10-09 Simon Goldschmidt + * opt.h: Fixed default values of some stats to only be enabled if used + Fixes bug #27338: sys_stats is defined when NO_SYS = 1 + + 2009-08-30 Simon Goldschmidt + * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK + function" by checking for loopback before calling ip_frag + + 2009-08-25 Simon Goldschmidt + * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0 + + 2009-08-23 Simon Goldschmidt + * ppp.c: bug #27078: Possible memory leak in pppInit() + + 2009-08-23 Simon Goldschmidt + * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result + is error. + + 2009-08-23 Simon Goldschmidt + * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF + Fixed wrong parenthesis, added check in init.c + + 2009-08-23 Simon Goldschmidt + * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms + + 2009-08-23 Simon Goldschmidt + * many ppp files: bug #27267: Added include to string.h where needed + + 2009-08-23 Simon Goldschmidt + * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian) + + +(STABLE-1.3.1) + + ++ New features: + + 2009-05-10 Simon Goldschmidt + * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option + LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only + one pbuf to help MACs that don't support scatter-gather DMA. + + 2009-05-09 Simon Goldschmidt + * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming + ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + + 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen + * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive + extended info about the currently received packet. + + 2009-04-27 Simon Goldschmidt + * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 + + 2009-04-25 Simon Goldschmidt + * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next + bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). + + 2009-04-21 Simon Goldschmidt + * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static + hosts table. New configuration options DNS_LOCAL_HOSTLIST and + DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined + as an external function for lookup. + + 2009-04-15 Simon Goldschmidt + * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique + + 2009-03-31 Kieran Mansley + * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for + TCP timestamp options, off by default. Rework tcp_enqueue() to + take option flags rather than specified option data + + 2009-02-18 Simon Goldschmidt + * cc.h: Added printf formatter for size_t: SZT_F + + 2009-02-16 Simon Goldschmidt (patch by Rishi Khan) + * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast + pings + + 2009-02-12 Simon Goldschmidt + * init.h: Added LWIP_VERSION to get the current version of the stack + + 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) + * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead + of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc + is otherwise used) + + 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) + * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() + is only used by UDPLITE at present, so conditionalise it. + + 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) + * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP + "seed" address. This should reduce AUTOIP conflicts if + LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. + + 2008-10-02 Jonathan Larmour and Rishi Khan + * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking + socket. + + 2008-06-30 Simon Goldschmidt + * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from + interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows + mem_free to run between mem_malloc iterations. Added illegal counter for + mem stats. + + 2008-06-27 Simon Goldschmidt + * stats.h/.c, some other files: patch #6483: stats module improvement: + Added defines to display each module's statistic individually, added stats + defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. + + 2008-06-17 Simon Goldschmidt + * err.h: patch #6459: Made err_t overridable to use a more efficient type + (define LWIP_ERR_T in cc.h) + + 2008-06-17 Simon Goldschmidt + * slipif.c: patch #6480: Added a configuration option for slipif for symmetry + to loopif + + 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) + * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly + modified version of patch # 6370: Moved loopif code to netif.c so that + loopback traffic is supported on all netifs (all local IPs). + Added option to limit loopback packets for each netifs. + + + ++ Bugfixes: + 2009-08-12 Kieran Mansley + * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when + out of window or out of order properly + + 2009-08-12 Kieran Mansley + * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 + + 2009-07-28 Simon Goldschmidt + * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s + + 2009-07-27 Kieran Mansley + * api.h api_msg.h netdb.h sockets.h: add missing #include directives + + 2009-07-09 Kieran Mansley + * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for + recv_avail and don't increment counters until message successfully + sent to mbox + + 2009-06-25 Kieran Mansley + * api_msg.c api.h: BUG26722: initialise netconn write variables + in netconn_alloc + + 2009-06-25 Kieran Mansley + * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set + + 2009-06-25 Kieran Mansley + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct + simultaneous close behaviour, and make snd_nxt have the same meaning + as in the RFCs. + + 2009-05-12 Simon Goldschmidt + * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on + arp_table / uses etharp_query" by adding etharp_gratuitous() + + 2009-05-12 Simon Goldschmidt + * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options + to the IP header (used by igmp_ip_output_if) + + 2009-05-06 Simon Goldschmidt + * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if + defined) for SWAP_BYTES_IN_WORD to speed up checksumming. + + 2009-05-05 Simon Goldschmidt + * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() + to crash + + 2009-05-04 Simon Goldschmidt + * init.c: snmp was not initialized in lwip_init() + + 2009-05-04 Frédéric Bernon + * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. + + 2009-05-03 Simon Goldschmidt + * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full + (and unsent->next == NULL) + + 2009-05-02 Simon Goldschmidt + * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after + 1.3.0 in CVS only) - fixes compilation of ppp_oe.c + + 2009-05-02 Simon Goldschmidt + * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields + + 2009-05-01 Simon Goldschmidt + * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets + + 2009-05-01 Simon Goldschmidt + * ppp.c: bug #24228: Memory corruption with PPP and DHCP + + 2009-04-29 Frédéric Bernon + * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the + SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception + of broadcast packets even when this option wasn't set. Port maintainers + which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. + If you want this option also filter broadcast on recv operations, you also + have to set IP_SOF_BROADCAST_RECV=1 in opt.h. + + 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen + * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and + DHCP/AUTOIP cooperation + + 2009-04-25 Simon Goldschmidt, Oleg Tyshev + * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd + Fixed by sorting the unsent and unacked queues (segments are inserted at the + right place in tcp_output and tcp_rexmit). + + 2009-04-25 Simon Goldschmidt + * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation + when debugging": memp_sizes contained the wrong sizes (including sanity + regions); memp pools for MEM_USE_POOLS were too small + + 2009-04-24 Simon Goldschmidt, Frédéric Bernon + * inet.c: patch #6765: Fix a small problem with the last changes (incorrect + behavior, with with ip address string not ended by a '\0', a space or a + end of line) + + 2009-04-19 Simon Goldschmidt + * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, + pcb->err is called, not pcb->connected (with an error code). + + 2009-04-19 Simon Goldschmidt + * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with + no-copy-tcpwrite": deallocate option data, only concat segments with same flags + + 2009-04-19 Simon Goldschmidt + * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated + in the header pbuf, not the data pbuf) + + 2009-04-18 Simon Goldschmidt + * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() + + 2009-04-15 Simon Goldschmidt + * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp + + 2009-04-15 Simon Goldschmidt + * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in + + 2009-04-15 Simon Goldschmidt + * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function + ip_hinted_output() (for smaller code mainly) + + 2009-04-15 Simon Goldschmidt + * inet.c: patch #6765: Supporting new line characters in inet_aton() + + 2009-04-15 Simon Goldschmidt + * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; + Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu + is big enough in dhcp_start + + 2009-04-15 Simon Goldschmidt + * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak + + 2009-04-15 Simon Goldschmidt + * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY + + 2009-04-15 Simon Goldschmidt + * sockets.c: bug #26121: set_errno can be overridden + + 2009-04-09 Kieran Mansley (patch from Luca Ceresoli ) + * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when + LWIP_TCP==0 + + 2009-04-09 Kieran Mansley (patch from Roy Lee ) + * tcp.h: Patch#6802 Add do-while-clauses to those function like + macros in tcp.h + + 2009-03-31 Kieran Mansley + * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window + updates are calculated and sent (BUG20515) + + * tcp_in.c: cope with SYN packets received during established states, + and retransmission of initial SYN. + + * tcp_out.c: set push bit correctly when tcp segments are merged + + 2009-03-27 Kieran Mansley + * tcp_out.c set window correctly on probes (correcting change made + yesterday) + + 2009-03-26 Kieran Mansley + * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping + connections where no reset required (bug #25622) + + * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes + (bug #20779) + + 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) + * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be + too small depending on MEM_ALIGNMENT + + 2009-02-16 Simon Goldschmidt + * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; + converted size argument of netconn_write to 'size_t' + + 2009-02-16 Simon Goldschmidt + * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host + by moving accept callback function pointer to TCP_PCB_COMMON + + 2009-02-12 Simon Goldschmidt + * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" + option) + + 2009-02-11 Simon Goldschmidt + * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) + + 2009-02-11 Simon Goldschmidt + * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: + RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) + + 2009-02-10 Simon Goldschmidt + * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: + Accepts_pending is decrease on a corresponding listen pcb when a connection + in state SYN_RCVD is close. + + 2009-01-28 Jonathan Larmour + * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run + out of pool pbufs. + + 2008-12-19 Simon Goldschmidt + * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 + + 2008-12-10 Tamas Somogyi, Frédéric Bernon + * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and + port uses deleted netbuf. + + 2008-10-18 Simon Goldschmidt + * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length + in tcp_parseopt + + 2008-10-15 Simon Goldschmidt + * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers + by packing the struct ip_reass_helper. + + 2008-10-03 David Woodhouse, Jonathan Larmour + * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. + + 2008-10-02 Jonathan Larmour + * dns.c: Hard-code structure sizes, to avoid issues on some compilers where + padding is included. + + 2008-09-30 Jonathan Larmour + * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an + assertion check that addrlen isn't NULL. + + 2008-09-30 Jonathan Larmour + * tcp.c: Fix bug #24227, wrong error message in tcp_bind. + + 2008-08-26 Simon Goldschmidt + * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and + inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h + + 2008-08-14 Simon Goldschmidt + * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when + tcp_close returns != ERR_OK) + + 2008-07-08 Frédéric Bernon + * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters + in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). + + 2008-06-24 Jonathan Larmour + * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused + if tcp_seg_copy fails. + + 2008-06-17 Simon Goldschmidt + * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) + and created defines for swapping bytes and folding u32 to u16. + + 2008-05-30 Kieran Mansley + * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd + rather than rcv_ann_wnd when deciding if packets are in-window. + Contributed by + + 2008-05-30 Kieran Mansley + * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow + passing as function pointers when MEM_LIBC_MALLOC is defined. + + 2008-05-09 Jonathan Larmour + * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to + stop it being treated as a fatal error. + + 2008-04-15 Simon Goldschmidt + * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP + (flag now cleared) + + 2008-03-27 Simon Goldschmidt + * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free + from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 + in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs + or heap memory from interrupt context + + 2008-03-26 Simon Goldschmidt + * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote + host sent a zero mss as TCP option. + + +(STABLE-1.3.0) + + ++ New features: + + 2008-03-10 Jonathan Larmour + * inet_chksum.c: Allow choice of one of the sample algorithms to be + made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. + + 2008-01-22 Frédéric Bernon + * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in + TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. + + 2008-01-14 Frédéric Bernon + * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable + to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the + tcp_recv callback (see rawapi.txt). + + 2008-01-14 Frédéric Bernon, Marc Chaland + * ip.c: Integrate patch #6369" ip_input : checking before realloc". + + 2008-01-12 Frédéric Bernon + * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field + netconn::sem per netconn::op_completed like suggested for the task #7490 + "Add return value to sys_mbox_post". + + 2008-01-12 Frédéric Bernon + * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, + DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues + sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". + + 2008-01-10 Frédéric Bernon + * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 + "Add return value to sys_mbox_post". tcpip_callback is always defined as + "blocking" ("block" parameter = 1). + + 2008-01-10 Frédéric Bernon + * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field + netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 + "Add return value to sys_mbox_post". + + 2008-01-05 Frédéric Bernon + * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: + Introduce changes for task #7490 "Add return value to sys_mbox_post" with some + modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which + indicate the number of pointers query by the mailbox. There is three defines + in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the + netconn::acceptmbox. Port maintainers, you can decide to just add this new + parameter in your implementation, but to ignore it to keep the previous behavior. + The new sys_mbox_trypost function return a value to know if the mailbox is + full or if the message is posted. Take a look to sys_arch.txt for more details. + This new function is used in tcpip_input (so, can be called in an interrupt + context since the function is not blocking), and in recv_udp and recv_raw. + + 2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour + * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, + tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the + "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add + documentation in the rawapi.txt file. + + 2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer + + 2007-12-31 Frédéric Bernon, Luca Ceresoli + * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets + in autoip". The change in etharp_raw could be removed, since all calls to + etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be + wrong in the future. + + 2007-12-30 Frédéric Bernon, Tom Evans + * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address + Filtering" reported by Tom Evans. + + 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour + * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, + sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API + applications have to call 'tcp_accepted(pcb)' in their accept callback to + keep accepting new connections. + + 2007-12-13 Frédéric Bernon + * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" + by err_t type. Add a new err_t code "ERR_INPROGRESS". + + 2007-12-12 Frédéric Bernon + * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles + are the one which have ram usage. + + 2007-12-05 Frédéric Bernon + * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static + set of variables (=0) or a local one (=1). In this last case, your port should + provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" + which have to do a copy of "h" and return a pointer ont the "per-thread" copy. + + 2007-12-03 Simon Goldschmidt + * ip.c: ip_input: check if a packet is for inp first before checking all other + netifs on netif_list (speeds up packet receiving in most cases) + + 2007-11-30 Simon Goldschmidt + * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access + UDP: move a (connected) pcb selected for input to the front of the list of + pcbs so that it is found faster next time. Same for RAW pcbs that have eaten + a packet. + + 2007-11-28 Simon Goldschmidt + * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS + + 2007-11-25 Simon Goldschmidt + * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy + algorithm. + + 2007-11-24 Simon Goldschmidt + * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c + to the new file netdb.c; included lwip_getaddrinfo. + + 2007-11-21 Simon Goldschmidt + * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss + based on the MTU of the netif used to send. Enabled by default. Disable by + setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. + + 2007-11-19 Frédéric Bernon + * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name + received match the name query), implement DNS_USES_STATIC_BUF (the place where + copy dns payload to parse the response), return an error if there is no place + for a new query, and fix some minor problems. + + 2007-11-16 Simon Goldschmidt + * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c + removed files: core/inet.c, core/inet6.c + Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into + inet and chksum part; changed includes in all lwIP files as appropriate + + 2007-11-16 Simon Goldschmidt + * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential + dns resolver function for netconn api (netconn_gethostbyname) and socket api + (gethostbyname/gethostbyname_r). + + 2007-11-15 Jim Pettinato, Frédéric Bernon + * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name + requests with RAW api interface. Initialization is done in lwip_init() with + build time options. DNS timer is added in tcpip_thread context. DHCP can set + DNS server ip addresses when options are received. You need to set LWIP_DNS=1 + in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get + some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" + list with points to improve. + + 2007-11-06 Simon Goldschmidt + * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly + enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status + for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. + + 2007-11-06 Simon Goldschmidt + * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include + core header files in api.h (ip/tcp/udp/raw.h) to hide the internal + implementation from netconn api applications. + + 2007-11-03 Frédéric Bernon + * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & + RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled + by default). Netconn API users can use the netconn_recv_bufsize macro to access + it. This is a first release which have to be improve for TCP. Note it used the + netconn::recv_avail which need to be more "thread-safe" (note there is already + the problem for FIONREAD with lwip_ioctl/ioctlsocket). + + 2007-11-01 Frédéric Bernon, Marc Chaland + * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: + Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api + layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api + layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. + Note that previous "copy" parameter for "write" APIs is now called "apiflags". + + 2007-10-24 Frédéric Bernon + * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than + TCP_EVENT_xxx macros to get a code more readable. It could also help to remove + some code (like we have talk in "patch #5919 : Create compile switch to remove + select code"), but it could be done later. + + 2007-10-08 Simon Goldschmidt + * many files: Changed initialization: many init functions are not needed any + more since we now rely on the compiler initializing global and static + variables to zero! + + 2007-10-06 Simon Goldschmidt + * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY + to enqueue the received pbufs so that multiple packets can be reassembled + simultaneously and no static reassembly buffer is needed. + + 2007-10-05 Simon Goldschmidt + * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so + all netifs (or ports) can use it. + + 2007-10-05 Frédéric Bernon + * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the + common function to reduce a little bit the footprint (for all functions using + only the "netif" parameter). + + 2007-10-03 Frédéric Bernon + * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, + netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce + a little bit the footprint (for all functions using only the "netif" parameter). + + 2007-09-15 Frédéric Bernon + * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF + option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for + netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for + IP_MULTICAST_TTL and IP_MULTICAST_IF. + + 2007-09-10 Frédéric Bernon + * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles + even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() + each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can + decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but + call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() + or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. + This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside + snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only + when it's queried (any direct call to "sysuptime" is changed by a call to + snmp_get_sysuptime). + + 2007-09-09 Frédéric Bernon, Bill Florac + * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, + and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags + if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). + igmp_report_groups() is now called inside netif_set_link_up() (need to have + LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait + the next query message to receive the matching multicast streams). + + 2007-09-08 Frédéric Bernon + * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains + IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). + Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). + Enable to access to these fields with LWIP_TCP=0. + + 2007-09-05 Frédéric Bernon + * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, + ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option + LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). + Be careful, disabling ICMP make your product non-compliant to RFC1122, but + help to reduce footprint, and to reduce "visibility" on the Internet. + + 2007-09-05 Frédéric Bernon, Bill Florac + * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list + for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new + parameters have to be provided: a task name, and a task stack size. For this + one, since it's platform dependant, you could define the best one for you in + your lwipopts.h. For port maintainers, you can just add these new parameters + in your sys_arch.c file, and but it's not mandatory, use them in your OS + specific functions. + + 2007-09-05 Frédéric Bernon + * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings + inside init.c for task #7142 "Sanity check user-configurable values". + + 2007-09-04 Frédéric Bernon, Bill Florac + * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by + memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the + value). It will avoid potential fragmentation problems, use a counter to know + how many times a group is used on an netif, and free it when all applications + leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity + check if LWIP_IGMP!=0). + + 2007-09-03 Frédéric Bernon + * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". + Initialize igmp_mac_filter to NULL in netif_add (this field should be set in + the netif's "init" function). Use the "imr_interface" field (for socket layer) + and/or the "interface" field (for netconn layer), for join/leave operations. + The igmp_join/leavegroup first parameter change from a netif to an ipaddr. + This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). + + 2007-08-30 Frédéric Bernon + * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions + from api/api_lib". Now netbuf API is independant of netconn, and can be used + with other API (application based on raw API, or future "socket2" API). Ports + maintainers just have to add src/api/netbuf.c in their makefile/projects. + + 2007-08-30 Frédéric Bernon, Jonathan Larmour + * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check + user-configurable values". + + 2007-08-29 Frédéric Bernon + * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. + igmp_start is call inside netif_add. Now, igmp initialization is in the same + spirit than the others modules. Modify some IGMP debug traces. + + 2007-08-29 Frédéric Bernon + * Add init.h, init.c, Change opt.h, tcpip.c: Task #7213 "Add a lwip_init function" + Add lwip_init function to regroup all modules initializations, and to provide + a place to add code for task #7142 "Sanity check user-configurable values". + Ports maintainers should remove direct initializations calls from their code, + and add init.c in their makefiles. Note that lwip_init() function is called + inside tcpip_init, but can also be used by raw api users since all calls are + disabled when matching options are disabled. Also note that their is new options + in opt.h, you should configure in your lwipopts.h (they are enabled per default). + + 2007-08-26 Marc Boucher + * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL + since they can under certain circumstances be called with an invalid conn + pointer after the connection has been closed (and conn has been freed). + + 2007-08-25 Frédéric Bernon (Artem Migaev's Patch) + * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". + Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. + + 2007-08-22 Frédéric Bernon + * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK + to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. + + 2007-08-22 Frédéric Bernon + * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & + ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the + name is tcpip_input (we keep the name of 1.2.0 function). + + 2007-08-17 Jared Grubb + * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool + settings into new memp_std.h and optional user file lwippools.h. This adds + more dynamic mempools, and allows the user to create an arbitrary number of + mempools for mem_malloc. + + 2007-08-16 Marc Boucher + * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; + otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely + close the connection. + + 2007-08-16 Marc Boucher + * sockets.c: lwip_accept(): check netconn_peer() error return. + + 2007-08-16 Marc Boucher + * mem.c, mem.h: Added mem_calloc(). + + 2007-08-16 Marc Boucher + * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) + for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG + and starving other message types. + Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API + + 2007-08-16 Marc Boucher + * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf + type and flgs (later renamed to flags). + Use enum pbuf_flag as pbuf_type. Renumber PBUF_FLAG_*. + Improved lwip_recvfrom(). TCP push now propagated. + + 2007-08-16 Marc Boucher + * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global + provided by etharp. + + 2007-08-16 Marc Boucher + * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, + etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: + Added PPPoE support and various PPP improvements. + + 2007-07-25 Simon Goldschmidt + * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, + making netbuf_copy_partial use this function. + + 2007-07-25 Simon Goldschmidt + * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with + 2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and + other stacks. + + 2007-07-13 Jared Grubb (integrated by Frédéric Bernon) + * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add + a link callback in the netif struct, and functions to handle it. Be carefull + for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) + if you want to be sure to be compatible with future changes... + + 2007-06-30 Frédéric Bernon + * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. + + 2007-06-21 Simon Goldschmidt + * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both + LWIP_AUTOIP =0 and =1 to remove redundant code. + + 2007-06-21 Simon Goldschmidt + * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option + MEM_USE_POOLS to use 4 pools with different sized elements instead of a + heap. This both prevents memory fragmentation and gives a higher speed + at the cost of more memory consumption. Turned off by default. + + 2007-06-21 Simon Goldschmidt + * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of + netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into + int to be able to send a bigger buffer than 64K with one time (mainly + used from lwip_send). + + 2007-06-21 Simon Goldschmidt + * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write + into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. + + 2007-06-21 Simon Goldschmidt + * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in + netconn_write from api_lib.c to api_msg.c to also prevent multiple context- + changes on low memory or empty send-buffer. + + 2007-06-18 Simon Goldschmidt + * etharp.c, etharp.h: Changed etharp to use a defined hardware address length + of 6 to avoid loading netif->hwaddr_len every time (since this file is only + used for ethernet and struct eth_addr already had a defined length of 6). + + 2007-06-17 Simon Goldschmidt + * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets + to disable UDP checksum generation on transmit. + + 2007-06-13 Frédéric Bernon, Simon Goldschmidt + * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid + pointers or parameters, and let the possibility to redefined it in cc.h. Use + this macro to check "conn" parameter in api_msg.c functions. + + 2007-06-11 Simon Goldschmidt + * sockets.c, sockets.h: Added UDP lite support for sockets + + 2007-06-10 Simon Goldschmidt + * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled + by default) to switch off UDP-Lite support if not needed (reduces udp.c code + size) + + 2007-06-09 Dominik Spies (integrated by Frédéric Bernon) + * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: + AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and + LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt + (see TODO mark in the source code). + + 2007-06-09 Simon Goldschmidt + * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for + etharp_output() to match netif->output so etharp_output() can be used + directly as netif->output to save one function call. + + 2007-06-08 Simon Goldschmidt + * netif.h, ethernetif.c, slipif.c, loopif.c: Added define + NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, + added initialization of those to ethernetif, slipif and loopif. + + 2007-05-18 Simon Goldschmidt + * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF + (defaulting to off for now) that can be set to 0 to send fragmented + packets by passing PBUF_REFs down the stack. + + 2007-05-23 Frédéric Bernon + * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP + connections, such present in patch #5959. + + 2007-05-23 Frédéric Bernon + * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx + code in only one part... + + 2007-05-18 Simon Goldschmidt + * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp + elements to overflow. This is achieved by adding some bytes before and after + each pool element (increasing their size, of course), filling them with a + prominent value and checking them on freeing the element. + Set it to 2 to also check every element in every pool each time memp_malloc() + or memp_free() is called (slower but more helpful). + + 2007-05-10 Simon Goldschmidt + * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for + PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce + code size. + + 2007-05-11 Frédéric Bernon + * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: + Include a function pointer instead of a table index in the message to reduce + footprint. Disable some part of lwip_send and lwip_sendto if some options are + not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). + + 2007-05-10 Simon Goldschmidt + * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus + \ extern "C" {' in all header files. Now you can write your application using + the lwIP stack in C++ and simply #include the core files. Note I have left + out the netif/ppp/*h header files for now, since I don't know which files are + included by applications and which are for internal use only. + + 2007-05-09 Simon Goldschmidt + * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library + memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for + situations where some compilers might inline the copy and save a function + call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). + + 2007-05-08 Simon Goldschmidt + * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) + to be overriden in case the C-library malloc implementation is not protected + against concurrent access. + + 2007-05-04 Simon Goldschmidt (Atte Kojo) + * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending + multiple packets to the same host. + + 2007-05-04 Frédéric Bernon, Jonathan Larmour + * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible + to corrupt remote addr/port connection state". Reduce problems "not enought memory" with + netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between + sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. + Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, + these fields are now renamed "addr" & "port". + + 2007-04-11 Jonathan Larmour + * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new + sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return + with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro + by the port in sys_arch.h if desired. + + 2007-04-06 Frédéric Bernon, Simon Goldschmidt + * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API + allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp + clients, using new functions from netifapi.h. Disable as default (no port change to do). + + 2007-04-05 Frédéric Bernon + * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. + + 2007-04-04 Simon Goldschmidt + * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) + use this for and architecture-independent form to tell the compiler you intentionally + are not using this variable. Can be overriden in cc.h. + + 2007-03-28 Frédéric Bernon + * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to + define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded + string, point on one of your's ethernetif field, or alloc a string you will free yourself). + It will be used by DHCP to register a client hostname, but can also be use when you call + snmp_set_sysname. + + 2007-03-28 Frédéric Bernon + * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to + initialize a network interface's flag with. It tell this interface is an ethernet + device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility + Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). + + 2007-03-26 Frédéric Bernon, Jonathan Larmour + * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build + time if you only use PPP or SLIP. The default is enable. Note we don't have to call + etharp_init in your port's initilization sequence if you use tcpip.c, because this call + is done in tcpip_init function. + + 2007-03-22 Frédéric Bernon + * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the + new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in + your lwipopts.h. More, unused counters are not defined in the stats structs, and not + display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined + but never used. Fix msg_in.c with the correct #if test for a stat display. + + 2007-03-21 Kieran Mansley + * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). + Provides callback on netif up/down state change. + + 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds + * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, + ip.c, netif.h, tcpip.c, opt.h: + New configuration option LWIP_IGMP to enable IGMP processing. Based on only one + filter per all network interfaces. Declare a new function in netif to enable to + control the MAC filter (to reduce lwIP traffic processing). + + 2007-03-11 Frédéric Bernon + * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can + be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this + unless you know what you're doing (default are RFC1122 compliant). Note + that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. + + 2007-03-08 Frédéric Bernon + * tcp.h: Keepalive values can be configured at compile time, but don't change + this unless you know what you're doing (default are RFC1122 compliant). + + 2007-03-08 Frédéric Bernon + * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: + Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO + on UDP sockets/netconn. + + 2007-03-08 Simon Goldschmidt + * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. + + 2007-03-06 Frédéric Bernon + * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: + Implement SO_RCVTIMEO on UDP sockets/netconn. + + 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) + * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated + on the stack and remove the API msg type from memp + + 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) + * sockets.h, sockets.c: Move socket initialization to new + lwip_socket_init() function. + NOTE: this changes the API with ports. Ports will have to be + updated to call lwip_socket_init() now. + + 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) + * api_lib.c: Use memcpy in netbuf_copy_partial. + + + ++ Bug fixes: + + 2008-03-17 Frédéric Bernon, Ed Kerekes + * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have + some problems to fill the IP header on some targets, use now the + ip.h macros to do it). + + 2008-03-13 Frédéric Bernon + * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using + (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a + TCP connection caused a crash. Note that using (lwip_)recvfrom + like this is a bit slow and that using (lwip)getpeername is the + good lwip way to do it (so, using recv is faster on tcp sockets). + + 2008-03-12 Frédéric Bernon, Jonathan Larmour + * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's + recv_raw() does not consume data", and the ping sample (with + LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom + returned the IP payload, without the IP header). + + 2008-03-04 Jonathan Larmour + * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors + and/or warnings on some systems where mem_size_t and size_t differ. + * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. + + 2008-03-04 Kieran Mansley (contributions by others) + * Numerous small compiler error/warning fixes from contributions to + mailing list after 1.3.0 release candidate made. + + 2008-01-25 Cui hengbin (integrated by Frédéric Bernon) + * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. + + 2008-01-15 Kieran Mansley + * tcp_out.c: BUG20511. Modify persist timer to start when we are + prevented from sending by a small send window, not just a zero + send window. + + 2008-01-09 Jonathan Larmour + * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid + conflict with Linux system headers. + + 2008-01-06 Jonathan Larmour + * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP + address entirely on receiving a DHCPNAK, and restarting discovery. + + 2007-12-21 Simon Goldschmidt + * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail + is not protected" by using new macros for interlocked access to modify/test + netconn->recv_avail. + + 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) + * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) + + 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling + of silly window avoidance and prevent lwIP from shrinking the window) + + 2007-12-04 Simon Goldschmidt + * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last + data packet was lost): add assert that all segment lists are empty in + tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED + state from LAST_ACK in tcp_process + + 2007-12-02 Simon Goldschmidt + * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET + If including for system-struct timeval, LWIP_TIMEVAL_PRIVATE now + has to be set to 0 in lwipopts.h + + 2007-12-02 Simon Goldschmidt + * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always + allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen + netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. + This is a fix for thread-safety and allocates all items needed for a netconn + when the netconn is created. + + 2007-11-30 Simon Goldschmidt + * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple + netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed + to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same + port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) + + 2007-11-27 Simon Goldschmidt + * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by + letting ip_route only use netifs that are up. + + 2007-11-27 Simon Goldschmidt + * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF + and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and + sockets block most operations once they have seen a fatal error. + + 2007-11-27 Simon Goldschmidt + * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the + netif to send as an argument (to be able to send on netifs that are down). + + 2007-11-26 Simon Goldschmidt + * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs + arrive out-of-order + + 2007-11-21 Simon Goldschmidt + * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early + Fixed the nagle algorithm; nagle now also works for all raw API applications + and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' + + 2007-11-12 Frédéric Bernon + * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most + of the netconn_peer and netconn_addr processing is done inside tcpip_thread + context in do_getaddr. + + 2007-11-10 Simon Goldschmidt + * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can + happen any time). Now the packet simply isn't enqueued when out of memory. + + 2007-11-01 Simon Goldschmidt + * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or + TCP_MSS if that is smaller) as long as no MSS option is received from the + remote host. + + 2007-11-01 Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) + is now based on TCP_MSS instead of pcb->mss (on passive open now effectively + sending our configured TCP_MSS instead of the one received). + + 2007-11-01 Simon Goldschmidt + * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was + calculated based on the configured TCP_MSS, not on the MSS option received + with SYN+ACK. + + 2007-10-09 Simon Goldschmidt + * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too + short and also was generated wrong if checksum coverage != tot_len; + receive: checksum was calculated wrong if checksum coverage != tot_len + + 2007-10-08 Simon Goldschmidt + * mem.c: lfree was not updated in mem_realloc! + + 2007-10-07 Frédéric Bernon + * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential + crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: + this change cause an API breakage for netconn_addr, since a parameter + type change. Any compiler should cause an error without any changes in + yours netconn_peer calls (so, it can't be a "silent change"). It also + reduce a little bit the footprint for socket layer (lwip_getpeername & + lwip_getsockname use now a common lwip_getaddrname function since + netconn_peer & netconn_addr have the same parameters). + + 2007-09-20 Simon Goldschmidt + * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) + by checking tcp_tw_pcbs also + + 2007-09-19 Simon Goldschmidt + * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) + + 2007-09-15 Mike Kleshov + * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) + + 2007-09-06 Frédéric Bernon + * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove + it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which + already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" + if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. + + 2007-08-30 Frédéric Bernon + * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, + and fix some coding style. + + 2007-08-28 Frédéric Bernon + * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any + kind of packets. These packets are considered like Ethernet packets (payload + pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets + are considered like IP packets (payload pointing to iphdr). + + 2007-08-27 Frédéric Bernon + * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error + problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state + and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). + + 2007-08-24 Kieran Mansley + * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy + compiler (Paradigm C++) + + 2007-08-09 Frédéric Bernon, Bill Florac + * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. + Introduce IGMP_STATS to centralize statistics management. + + 2007-08-09 Frédéric Bernon, Bill Florac + * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast + packet on a udp pcb binded on an netif's IP address, and not on "any". + + 2007-08-09 Frédéric Bernon, Bill Florac + * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. + This is mainly on using lookup/lookfor, and some coding styles... + + 2007-07-26 Frédéric Bernon (and "thedoctor") + * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. + + 2007-07-25 Simon Goldschmidt + * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if + tcp_output fails in tcp_close, the code in do_close_internal gets simpler + (tcp_output is called again later from tcp timers). + + 2007-07-25 Simon Goldschmidt + * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old + copy_from_pbuf, which illegally modified the given pbuf. + + 2007-07-25 Simon Goldschmidt + * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: + changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). + + 2007-07-24 Simon Goldschmidt + * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the + correct state (must be CLOSED). + + 2007-07-13 Thomas Taranowski (commited by Jared Grubb) + * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed + allocation. It now returns NULL. + + 2007-07-13 Frédéric Bernon + * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in + all error cases. + + 2007-07-13 Frédéric Bernon + * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, + because current code doesn't follow rawapi.txt documentation. + + 2007-07-13 Kieran Mansley + * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in + out of sequence processing of received packets + + 2007-07-03 Simon Goldschmidt + * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an + assumption is made that this pbuf is in one piece (i.e. not chained). These + assumptions clash with the possibility of converting to fully pool-based + pbuf implementations, where PBUF_RAM pbufs might be chained. + + 2007-07-03 Simon Goldschmidt + * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems + when closing tcp netconns: removed conn->sem, less context switches when + closing, both netconn_close and netconn_delete should safely close tcp + connections. + + 2007-07-02 Simon Goldschmidt + * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, + tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) + to cache ARP table indices with each pcb instead of single-entry cache for + the complete stack. + + 2007-07-02 Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent + warnings when assigning to smaller types. + + 2007-06-28 Simon Goldschmidt + * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. + + 2007-06-28 Simon Goldschmidt + * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if + a segment contained chained pbufs) + + 2007-06-28 Frédéric Bernon + * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute + a "pseudo-random" value based on netif's MAC and some autoip fields. It's always + possible to define this macro in your own lwipopts.h to always use C library's + rand(). Note that autoip_create_rand_addr doesn't use this macro. + + 2007-06-28 Frédéric Bernon + * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option + LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications + in api_lib/api_msg (use pointers and not type with table, etc...) + + 2007-06-26 Simon Goldschmidt + * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. + + 2007-06-25 Simon Goldschmidt + * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload + for udp packets with no matching pcb. + + 2007-06-25 Simon Goldschmidt + * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match + could get udp input packets if the remote side matched. + + 2007-06-13 Simon Goldschmidt + * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get + changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. + + 2007-06-13 Simon Goldschmidt + * api_msg.c: pcb_new sets conn->err if protocol is not implemented + -> netconn_new_..() does not allocate a new connection for unsupported + protocols. + + 2007-06-13 Frédéric Bernon, Simon Goldschmidt + * api_lib.c: change return expression in netconn_addr and netconn_peer, because + conn->err was reset to ERR_OK without any reasons (and error was lost)... + + 2007-06-13 Frédéric Bernon, Matthias Weisser + * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename + MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid + some macro names collision with some OS macros. + + 2007-06-11 Simon Goldschmidt + * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, + create checksum over the complete packet. On RX, if it's < 8 (and not 0), + discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both + UDP & UDP Lite. + + 2007-06-11 Srinivas Gollakota & Oleg Tyshev + * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" + where TCP flags wasn't initialized in tcp_keepalive. + + 2007-06-03 Simon Goldschmidt + * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function + registered, p->payload was modified without modifying p->len if sending + icmp_dest_unreach() (had no negative effect but was definitively wrong). + + 2007-06-03 Simon Goldschmidt + * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp + re-used the input pbuf even if that didn't have enough space to include the + link headers. Now the space is tested and a new pbuf is allocated for the + echo response packet if the echo request pbuf isn't big enough. + + 2007-06-01 Simon Goldschmidt + * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. + + 2007-05-23 Frédéric Bernon + * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only + allocated by do_listen if success) and netconn_accept errors handling. In + most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" + by ASSERT, except for netconn_delete. + + 2007-05-23 Frédéric Bernon + * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return + an error code if it's impossible to fetch a pbuf on a TCP connection (and not + directly close the recvmbox). + + 2007-05-22 Simon Goldschmidt + * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of + bound but unconnected (and non-listening) tcp_pcbs. + + 2007-05-22 Frédéric Bernon + * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only + used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of + sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features + like "sys_timeout" in their application threads. + + 2007-05-22 Frédéric Bernon + * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see + which parameters are used by which do_xxx function, and to avoid "misusing" + parameters (patch #5938). + + 2007-05-22 Simon Goldschmidt + * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: + changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto + is only 8 bits wide. This affects the api, as there, the protocol was + u16_t, too. + + 2007-05-18 Simon Goldschmidt + * memp.c: addition to patch #5913: smaller pointer was returned but + memp_memory was the same size -> did not save memory. + + 2007-05-16 Simon Goldschmidt + * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns + != ERR_OK. + + 2007-05-16 Simon Goldschmidt + * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same + as the one of the netif used for sending to prevent sending from old + addresses after a netif address gets changed (partly fixes bug #3168). + + 2007-05-16 Frédéric Bernon + * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work + with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in + tcpip_init) because we have to be sure that network interfaces are already + added (mac filter is updated only in igmp_init for the moment). + + 2007-05-16 Simon Goldschmidt + * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls + into sys_arch_sem_wait calls to prevent timers from running while waiting + for the heap. This fixes bug #19167. + + 2007-05-13 Simon Goldschmidt + * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines + for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from + tcp.h to sockets.h. + + 2007-05-07 Simon Goldschmidt + * mem.c: Another attempt to fix bug #17922. + + 2007-05-04 Simon Goldschmidt + * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() + implementation so that it can be reused (don't allocate the target + pbuf inside pbuf_copy()). + + 2007-05-04 Simon Goldschmidt + * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem + to save a little RAM (next pointer of memp is not used while not in pool). + + 2007-05-03 "maq" + * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. + (patch #3574). + + 2007-04-23 Simon Goldschmidt + * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results + in NULL reference for incoming TCP packets". Loopif has to be configured + (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() + (multithreading environments, e.g. netif->input() = tcpip_input()) or + putting packets on a list that is fed to the stack by calling loopif_poll() + (single-thread / NO_SYS / polling environment where e.g. + netif->input() = ip_input). + + 2007-04-17 Jonathan Larmour + * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold + the difference between two u16_t's. + * sockets.h: FD_SETSIZE needs to match number of sockets, which is + MEMP_NUM_NETCONN in sockets.c right now. + + 2007-04-12 Jonathan Larmour + * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). + + 2007-04-12 Kieran Mansley + * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission + timer is reset to fix bug#19434, with help from Oleg Tyshev. + + 2007-04-11 Simon Goldschmidt + * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than + previously thought need to be copied (everything but PBUF_ROM!). Cleaned up + pbuf.c: removed functions no needed any more (by etharp). + + 2007-04-11 Kieran Mansley + * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix + "Constant is long" warnings with 16bit compilers. Contributed by + avatar@mmlab.cse.yzu.edu.tw + + 2007-04-05 Frédéric Bernon, Jonathan Larmour + * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on + the mailbox is active". Now, the post is only done during a connect, and do_send, + do_write and do_join_leave_group don't do anything if a previous error was signaled. + + 2007-04-03 Frédéric Bernon + * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output + packets. See patch #5834. + + 2007-03-30 Frédéric Bernon + * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add + missing pcb allocations checking (in do_bind, and for each raw_new). Fix style. + + 2007-03-30 Frédéric Bernon + * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with + others environment defines (these were too "generic"). + + 2007-03-28 Frédéric Bernon + * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call + result and can cause a crash. lwip_send now check netbuf_ref result. + + 2007-03-28 Simon Goldschmidt + * sockets.c Remove "#include " from sockets.c to avoid multiple + definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is + defined. This is the way it should have been already (looking at + doc/sys_arch.txt) + + 2007-03-28 Kieran Mansley + * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + + IP and TCP headers *and* physical link headers + + 2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) + * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause + to send some garbage. It is not a definitive solution, but the patch does solve + the problem for most cases. + + 2007-03-22 Frédéric Bernon + * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). + + 2007-03-22 Frédéric Bernon + * api_lib.c: somes resources couldn't be freed if there was errors during + netconn_new_with_proto_and_callback. + + 2007-03-22 Frédéric Bernon + * ethernetif.c: update netif->input calls to check return value. In older ports, + it's a good idea to upgrade them, even if before, there could be another problem + (access to an uninitialized mailbox). + + 2007-03-21 Simon Goldschmidt + * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed + by casting to unsigned). + + 2007-03-21 Frédéric Bernon + * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from + api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a + dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. + Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a + faster and more reliable communication between api_lib and tcpip. + + 2007-03-21 Frédéric Bernon + * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. + + 2007-03-21 Frédéric Bernon + * api_msg.c, igmp.c, igmp.h: Fix C++ style comments + + 2007-03-21 Kieran Mansley + * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + + IP and TCP headers + + 2007-03-21 Kieran Mansley + * Fix all uses of pbuf_header to check the return value. In some + cases just assert if it fails as I'm not sure how to fix them, but + this is no worse than before when they would carry on regardless + of the failure. + + 2007-03-21 Kieran Mansley + * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and + comment out missing header include in icmp.c + + 2007-03-20 Frédéric Bernon + * memp.h, stats.c: Fix stats_display function where memp_names table wasn't + synchronized with memp.h. + + 2007-03-20 Frédéric Bernon + * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, + tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with + network interfaces. Also fix a compiler warning. + + 2007-03-20 Kieran Mansley + * udp.c: Only try and use pbuf_header() to make space for headers if + not a ROM or REF pbuf. + + 2007-03-19 Frédéric Bernon + * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() + and api_msg_post(). + + 2007-03-19 Frédéric Bernon + * Remove unimplemented "memp_realloc" function from memp.h. + + 2007-03-11 Simon Goldschmidt + * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused + memory corruption. + + 2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) + * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 + (missing `const' qualifier in socket functions), to get more compatible to + standard POSIX sockets. + + 2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) + * sockets.c: Add asserts inside bind, connect and sendto to check input + parameters. Remove excessive set_errno() calls after get_socket(), because + errno is set inside of get_socket(). Move last sock_set_errno() inside + lwip_close. + + 2007-03-09 Simon Goldschmidt + * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory + was allocated too small. + + 2007-03-06 Simon Goldschmidt + * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect + the stack from concurrent access. + + 2007-03-06 Frédéric Bernon, Dmitry Potapov + * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy + call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). + + 2007-03-06 Simon Goldschmidt + * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files + if IP_FRAG == 0 and IP_REASSEMBLY == 0 + + 2007-03-06 Frédéric Bernon, Simon Goldschmidt + * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration + option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. + Allow to do ARP processing for incoming packets inside tcpip_thread + (protecting ARP layer against concurrent access). You can also disable + old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. + Older ports have to use tcpip_ethinput. + + 2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) + * err.h, err.c: fixed compiler warning "initialization dircards qualifiers + from pointer target type" + + 2007-03-05 Frédéric Bernon + * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, + ETHARP_TRUST_IP_MAC, review SO_REUSE) + + 2007-03-04 Frédéric Bernon + * api_msg.c: Remove some compiler warnings : parameter "pcb" was never + referenced. + + 2007-03-04 Frédéric Bernon + * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from + Dmitry Potapov). + The api_msg struct stay on the stack (not moved to netconn struct). + + 2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) + * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if + SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) + Also fixed cast warning in pbuf_alloc() + + 2007-03-04 Simon Goldschmidt + * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt + existing pbuf chain when enqueuing multiple pbufs to a pending ARP request + + 2007-03-03 Frédéric Bernon + * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" + It is static, and never used in udp.c except udp_init(). + + 2007-03-02 Simon Goldschmidt + * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from + tcpip_thread() to tcpip_init(). This way, raw API connections can be + initialized before tcpip_thread is running (e.g. before OS is started) + + 2007-03-02 Frédéric Bernon + * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call + interval. + + 2007-02-28 Kieran Mansley + * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved + outside the region of the pbuf by pbuf_header() + + 2007-02-28 Kieran Mansley + * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero + when supplied timeout is also non-zero + +(STABLE-1.2.0) + + 2006-12-05 Leon Woestenberg + * CHANGELOG: Mention STABLE-1.2.0 release. + + ++ New features: + + 2006-12-01 Christiaan Simons + * mem.h, opt.h: Added MEM_LIBC_MALLOC option. + Note this is a workaround. Currently I have no other options left. + + 2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) + * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define + to include/lwip/opt.h. + * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. + Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. + * opt.h: Add above new options. + + 2006-08-18 Christiaan Simons + * tcp_{in,out}.c: added SNMP counters. + * ipv4/ip.c: added SNMP counters. + * ipv4/ip_frag.c: added SNMP counters. + + 2006-08-08 Christiaan Simons + * etharp.{c,h}: added etharp_find_addr() to read + (stable) ethernet/IP address pair from ARP table + + 2006-07-14 Christiaan Simons + * mib_structs.c: added + * include/lwip/snmp_structs.h: added + * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct + + 2006-07-06 Christiaan Simons + * snmp/asn1_{enc,dec}.c added + * snmp/mib2.c added + * snmp/msg_{in,out}.c added + * include/lwip/snmp_asn1.h added + * include/lwip/snmp_msg.h added + * doc/snmp_agent.txt added + + 2006-03-29 Christiaan Simons + * inet.c, inet.h: Added platform byteswap support. + Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and + optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. + + ++ Bug fixes: + + 2006-11-30 Christiaan Simons + * dhcp.c: Fixed false triggers of request_timeout. + + 2006-11-28 Christiaan Simons + * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. + + 2006-10-11 Christiaan Simons + * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: + Partially accepted patch #5449 for ANSI C compatibility / build fixes. + * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol + identifier from 170 to 136 (bug #17574). + + 2006-10-10 Christiaan Simons + * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. + + 2006-08-17 Christiaan Simons + * udp.c: Fixed bug #17200, added check for broadcast + destinations for PCBs bound to a unicast address. + + 2006-08-07 Christiaan Simons + * api_msg.c: Flushing TCP output in do_close() (bug #15926). + + 2006-06-27 Christiaan Simons + * api_msg.c: Applied patch for cold case (bug #11135). + In accept_function() ensure newconn->callback is always initialized. + + 2006-06-15 Christiaan Simons + * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), + facilitate printing of mem_size_t and u16_t statistics. + + 2006-06-14 Christiaan Simons + * api_msg.c: Applied patch #5146 to handle allocation failures + in accept() by Kevin Lawson. + + 2006-05-26 Christiaan Simons + * api_lib.c: Removed conn->sem creation and destruction + from netconn_write() and added sys_sem_new to netconn_new_*. + +(STABLE-1_1_1) + + 2006-03-03 Christiaan Simons + * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap + access and added pbuf_alloc() return value checks. + + 2006-01-01 Leon Woestenberg + * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is + now handled by the checksum routine properly. + + 2006-02-27 Leon Woestenberg + * pbuf.c: Fix alignment; pbuf_init() would not work unless + pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) + + 2005-12-20 Leon Woestenberg + * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch + submitted by Mitrani Hiroshi. + + 2005-12-15 Christiaan Simons + * inet.c: Disabled the added summing routine to preserve code space. + + 2005-12-14 Leon Woestenberg + * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. + Added Curt McDowell's optimized checksumming routine for future + inclusion. Need to create test case for unaliged, aligned, odd, + even length combination of cases on various endianess machines. + + 2005-12-09 Christiaan Simons + * inet.c: Rewrote standard checksum routine in proper portable C. + + 2005-11-25 Christiaan Simons + * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. + * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, + u32_t, s32_t typedefs. This solves most debug word-length assumes. + + 2005-07-17 Leon Woestenberg + * inet.c: Fixed unaligned 16-bit access in the standard checksum + routine by Peter Jolasson. + * slipif.c: Fixed implementation assumption of single-pbuf datagrams. + + 2005-02-04 Leon Woestenberg + * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. + * tcp_{out|in}.c: Applied patch fixing unaligned access. + + 2005-01-04 Leon Woestenberg + * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. + + 2005-01-03 Leon Woestenberg + * udp.c: UDP pcb->recv() was called even when it was NULL. + +(STABLE-1_1_0) + + 2004-12-28 Leon Woestenberg + * etharp.*: Disabled multiple packets on the ARP queue. + This clashes with TCP queueing. + + 2004-11-28 Leon Woestenberg + * etharp.*: Fixed race condition from ARP request to ARP timeout. + Halved the ARP period, doubled the period counts. + ETHARP_MAX_PENDING now should be at least 2. This prevents + the counter from reaching 0 right away (which would allow + too little time for ARP responses to be received). + + 2004-11-25 Leon Woestenberg + * dhcp.c: Decline messages were not multicast but unicast. + * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. + Do not try hard to insert arbitrary packet's source address, + etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. + etharp_query() now always DOES call ETHARP_TRY_HARD so that users + querying an address will see it appear in the cache (DHCP could + suffer from this when a server invalidly gave an in-use address.) + * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are + comparing network addresses (identifiers), not the network masks + themselves. + * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given + IP address actually belongs to the network of the given interface. + + 2004-11-24 Kieran Mansley + * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. + +(STABLE-1_1_0-RC1) + + 2004-10-16 Kieran Mansley + * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, + even if one is already pending, if the rcv_wnd is above a threshold + (currently TCP_WND/2). This avoids waiting for a timer to expire to send a + delayed ACK in order to open the window if the stack is only receiving data. + + 2004-09-12 Kieran Mansley + * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. + + 2004-08-20 Tony Mountifield + * etharp.c: Make sure the first pbuf queued on an ARP entry + is properly ref counted. + + 2004-07-27 Tony Mountifield + * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler + warnings about comparison. + * pbuf.c: Stopped compiler complaining of empty if statement + when LWIP_DEBUGF() empty. Closed an unclosed comment. + * tcp.c: Stopped compiler complaining of empty if statement + when LWIP_DEBUGF() empty. + * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). + * inet.c: Added a couple of casts to quiet the compiler. + No need to test isascii(c) before isdigit(c) or isxdigit(c). + + 2004-07-22 Tony Mountifield + * inet.c: Made data types consistent in inet_ntoa(). + Added casts for return values of checksum routines, to pacify compiler. + * ip_frag.c, tcp_out.c, sockets.c, pbuf.c + Small corrections to some debugging statements, to pacify compiler. + + 2004-07-21 Tony Mountifield + * etharp.c: Removed spurious semicolon and added missing end-of-comment. + * ethernetif.c Updated low_level_output() to match prototype for + netif->linkoutput and changed low_level_input() similarly for consistency. + * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype + of raw_recv() in raw.h and so avoid compiler error. + * sockets.c: Added trivial (int) cast to keep compiler happier. + * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. + +(STABLE-1_0_0) + + ++ Changes: + + 2004-07-05 Leon Woestenberg + * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure + your cc.h file defines this either 1 or 0. If non-defined, + defaults to 1. + * .c: Added and includes where used. + * etharp.c: Made some array indices unsigned. + + 2004-06-27 Leon Woestenberg + * netif.*: Added netif_set_up()/down(). + * dhcp.c: Changes to restart program flow. + + 2004-05-07 Leon Woestenberg + * etharp.c: In find_entry(), instead of a list traversal per candidate, do a + single-pass lookup for different candidates. Should exploit locality. + + 2004-04-29 Leon Woestenberg + * tcp*.c: Cleaned up source comment documentation for Doxygen processing. + * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. + * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by + the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. + + ++ Bug fixes: + + 2004-04-27 Leon Woestenberg + * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution + suggested by Timmy Brolin. Fix for 32-bit processors that cannot access + non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix + is to prefix the 14-bit Ethernet headers with two padding bytes. + + 2004-04-23 Leon Woestenberg + * ip_addr.c: Fix in the ip_addr_isbroadcast() check. + * etharp.c: Fixed the case where the packet that initiates the ARP request + is not queued, and gets lost. Fixed the case where the packets destination + address is already known; we now always queue the packet and perform an ARP + request. + +(STABLE-0_7_0) + + ++ Bug fixes: + + * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. + * Fixed TCP bug in dequeueing of FIN from out of order segment queue. + * Fixed two possible NULL references in rare cases. + +(STABLE-0_6_6) + + ++ Bug fixes: + + * Fixed DHCP which did not include the IP address in DECLINE messages. + + ++ Changes: + + * etharp.c has been hauled over a bit. + +(STABLE-0_6_5) + + ++ Bug fixes: + + * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. + * Packets sent from ARP queue had invalid source hardware address. + + ++ Changes: + + * Pass-by ARP requests do now update the cache. + + ++ New features: + + * No longer dependent on ctype.h. + * New socket options. + * Raw IP pcb support. + +(STABLE-0_6_4) + + ++ Bug fixes: + + * Some debug formatters and casts fixed. + * Numereous fixes in PPP. + + ++ Changes: + + * DEBUGF now is LWIP_DEBUGF + * pbuf_dechain() has been re-enabled. + * Mentioned the changed use of CVS branches in README. + +(STABLE-0_6_3) + + ++ Bug fixes: + + * Fixed pool pbuf memory leak in pbuf_alloc(). + Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. + Reported by Savin Zlobec. + + * PBUF_POOL chains had their tot_len field not set for non-first + pbufs. Fixed in pbuf_alloc(). + + ++ New features: + + * Added PPP stack contributed by Marc Boucher + + ++ Changes: + + * Now drops short packets for ICMP/UDP/TCP protocols. More robust. + + * ARP queueuing now queues the latest packet instead of the first. + This is the RFC recommended behaviour, but can be overridden in + lwipopts.h. + +(0.6.2) + + ++ Bugfixes: + + * TCP has been fixed to deal with the new use of the pbuf->ref + counter. + + * DHCP dhcp_inform() crash bug fixed. + + ++ Changes: + + * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed + pbuf_refresh(). This has sped up pbuf pool operations considerably. + Implemented by David Haas. + +(0.6.1) + + ++ New features: + + * The packet buffer implementation has been enhanced to support + zero-copy and copy-on-demand for packet buffers which have their + payloads in application-managed memory. + Implemented by David Haas. + + Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy + if an outgoing packet can be directly sent on the link, or perform + a copy-on-demand when necessary. + + The application can safely assume the packet is sent, and the RAM + is available to the application directly after calling udp_send() + or similar function. + + ++ Bugfixes: + + * ARP_QUEUEING should now correctly work for all cases, including + PBUF_REF. + Implemented by Leon Woestenberg. + + ++ Changes: + + * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer + to a '0.0.0.0' IP address. + + * The packet buffer implementation is changed. The pbuf->ref counter + meaning has changed, and several pbuf functions have been + adapted accordingly. + + * netif drivers have to be changed to set the hardware address length field + that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). + See the contrib/ports/c16x cs8900 driver as a driver example. + + * netif's have a dhcp field that must be initialized to NULL by the driver. + See the contrib/ports/c16x cs8900 driver as a driver example. + +(0.5.x) This file has been unmaintained up to 0.6.1. All changes are + logged in CVS but have not been explained here. + +(0.5.3) Changes since version 0.5.2 + + ++ Bugfixes: + + * memp_malloc(MEMP_API_MSG) could fail with multiple application + threads because it wasn't protected by semaphores. + + ++ Other changes: + + * struct ip_addr now packed. + + * The name of the time variable in arp.c has been changed to ctime + to avoid conflicts with the time() function. + +(0.5.2) Changes since version 0.5.1 + + ++ New features: + + * A new TCP function, tcp_tmr(), now handles both TCP timers. + + ++ Bugfixes: + + * A bug in tcp_parseopt() could cause the stack to hang because of a + malformed TCP option. + + * The address of new connections in the accept() function in the BSD + socket library was not handled correctly. + + * pbuf_dechain() did not update the ->tot_len field of the tail. + + * Aborted TCP connections were not handled correctly in all + situations. + + ++ Other changes: + + * All protocol header structs are now packed. + + * The ->len field in the tcp_seg structure now counts the actual + amount of data, and does not add one for SYN and FIN segments. + +(0.5.1) Changes since version 0.5.0 + + ++ New features: + + * Possible to run as a user process under Linux. + + * Preliminary support for cross platform packed structs. + + * ARP timer now implemented. + + ++ Bugfixes: + + * TCP output queue length was badly initialized when opening + connections. + + * TCP delayed ACKs were not sent correctly. + + * Explicit initialization of BSS segment variables. + + * read() in BSD socket library could drop data. + + * Problems with memory alignment. + + * Situations when all TCP buffers were used could lead to + starvation. + + * TCP MSS option wasn't parsed correctly. + + * Problems with UDP checksum calculation. + + * IP multicast address tests had endianess problems. + + * ARP requests had wrong destination hardware address. + + ++ Other changes: + + * struct eth_addr changed from u16_t[3] array to u8_t[6]. + + * A ->linkoutput() member was added to struct netif. + + * TCP and UDP ->dest_* struct members where changed to ->remote_*. + + * ntoh* macros are now null definitions for big endian CPUs. + +(0.5.0) Changes since version 0.4.2 + + ++ New features: + + * Redesigned operating system emulation layer to make porting easier. + + * Better control over TCP output buffers. + + * Documenation added. + + ++ Bugfixes: + + * Locking issues in buffer management. + + * Bugfixes in the sequential API. + + * IP forwarding could cause memory leakage. This has been fixed. + + ++ Other changes: + + * Directory structure somewhat changed; the core/ tree has been + collapsed. + +(0.4.2) Changes since version 0.4.1 + + ++ New features: + + * Experimental ARP implementation added. + + * Skeleton Ethernet driver added. + + * Experimental BSD socket API library added. + + ++ Bugfixes: + + * In very intense situations, memory leakage could occur. This has + been fixed. + + ++ Other changes: + + * Variables named "data" and "code" have been renamed in order to + avoid name conflicts in certain compilers. + + * Variable++ have in appliciable cases been translated to ++variable + since some compilers generate better code in the latter case. + +(0.4.1) Changes since version 0.4 + + ++ New features: + + * TCP: Connection attempts time out earlier than data + transmissions. Nagle algorithm implemented. Push flag set on the + last segment in a burst. + + * UDP: experimental support for UDP-Lite extensions. + + ++ Bugfixes: + + * TCP: out of order segments were in some cases handled incorrectly, + and this has now been fixed. Delayed acknowledgements was broken + in 0.4, has now been fixed. Binding to an address that is in use + now results in an error. Reset connections sometimes hung an + application; this has been fixed. + + * Checksum calculation sometimes failed for chained pbufs with odd + lengths. This has been fixed. + + * API: a lot of bug fixes in the API. The UDP API has been improved + and tested. Error reporting and handling has been + improved. Logical flaws and race conditions for incoming TCP + connections has been found and removed. + + * Memory manager: alignment issues. Reallocating memory sometimes + failed, this has been fixed. + + * Generic library: bcopy was flawed and has been fixed. + + ++ Other changes: + + * API: all datatypes has been changed from generic ones such as + ints, to specified ones such as u16_t. Functions that return + errors now have the correct type (err_t). + + * General: A lot of code cleaned up and debugging code removed. Many + portability issues have been fixed. + + * The license was changed; the advertising clause was removed. + + * C64 port added. + + * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri + Kosunen, Mikael Caleres, and Frits Wilmink for reporting and + fixing bugs! + +(0.4) Changes since version 0.3.1 + + * Memory management has been radically changed; instead of + allocating memory from a shared heap, memory for objects that are + rapidly allocated and deallocated is now kept in pools. Allocation + and deallocation from those memory pools is very fast. The shared + heap is still present but is used less frequently. + + * The memory, memory pool, and packet buffer subsystems now support + 4-, 2-, or 1-byte alignment. + + * "Out of memory" situations are handled in a more robust way. + + * Stack usage has been reduced. + + * Easier configuration of lwIP parameters such as memory usage, + TTLs, statistics gathering, etc. All configuration parameters are + now kept in a single header file "lwipopts.h". + + * The directory structure has been changed slightly so that all + architecture specific files are kept under the src/arch + hierarchy. + + * Error propagation has been improved, both in the protocol modules + and in the API. + + * The code for the RTXC architecture has been implemented, tested + and put to use. + + * Bugs have been found and corrected in the TCP, UDP, IP, API, and + the Internet checksum modules. + + * Bugs related to porting between a 32-bit and a 16-bit architecture + have been found and corrected. + + * The license has been changed slightly to conform more with the + original BSD license, including the advertisement clause. + +(0.3.1) Changes since version 0.3 + + * Fix of a fatal bug in the buffer management. Pbufs with allocated + RAM never returned the RAM when the pbuf was deallocated. + + * TCP congestion control, window updates and retransmissions did not + work correctly. This has now been fixed. + + * Bugfixes in the API. + +(0.3) Changes since version 0.2 + + * New and improved directory structure. All include files are now + kept in a dedicated include/ directory. + + * The API now has proper error handling. A new function, + netconn_err(), now returns an error code for the connection in + case of errors. + + * Improvements in the memory management subsystem. The system now + keeps a pointer to the lowest free memory block. A new function, + mem_malloc2() tries to allocate memory once, and if it fails tries + to free some memory and retry the allocation. + + * Much testing has been done with limited memory + configurations. lwIP now does a better job when overloaded. + + * Some bugfixes and improvements to the buffer (pbuf) subsystem. + + * Many bugfixes in the TCP code: + + - Fixed a bug in tcp_close(). + + - The TCP receive window was incorrectly closed when out of + sequence segments was received. This has been fixed. + + - Connections are now timed-out of the FIN-WAIT-2 state. + + - The initial congestion window could in some cases be too + large. This has been fixed. + + - The retransmission queue could in some cases be screwed up. This + has been fixed. + + - TCP RST flag now handled correctly. + + - Out of sequence data was in some cases never delivered to the + application. This has been fixed. + + - Retransmitted segments now contain the correct acknowledgment + number and advertised window. + + - TCP retransmission timeout backoffs are not correctly computed + (ala BSD). After a number of retransmissions, TCP now gives up + the connection. + + * TCP connections now are kept on three lists, one for active + connections, one for listening connections, and one for + connections that are in TIME-WAIT. This greatly speeds up the fast + timeout processing for sending delayed ACKs. + + * TCP now provides proper feedback to the application when a + connection has been successfully set up. + + * More comments have been added to the code. The code has also been + somewhat cleaned up. + +(0.2) Initial public release. diff --git a/Sming/third-party/lwip2/lwip2-src/COPYING b/Sming/third-party/lwip2/lwip2-src/COPYING new file mode 100644 index 0000000000..e23898b5e8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/COPYING @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + diff --git a/Sming/third-party/lwip2/lwip2-src/FILES b/Sming/third-party/lwip2/lwip2-src/FILES new file mode 100644 index 0000000000..e6e09989d9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/FILES @@ -0,0 +1,5 @@ +src/ - The source code for the lwIP TCP/IP stack. +doc/ - The documentation for lwIP. +test/ - Some code to test whether the sources do what they should. + +See also the FILES file in each subdirectory. diff --git a/Sming/third-party/lwip2/lwip2-src/README b/Sming/third-party/lwip2/lwip2-src/README new file mode 100644 index 0000000000..0884d27bea --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/README @@ -0,0 +1,100 @@ +INTRODUCTION + +lwIP is a small independent implementation of the TCP/IP protocol +suite that has been developed by Adam Dunkels at the Computer and +Networks Architectures (CNA) lab at the Swedish Institute of Computer +Science (SICS). + +The focus of the lwIP TCP/IP implementation is to reduce the RAM usage +while still having a full scale TCP. This making lwIP suitable for use +in embedded systems with tens of kilobytes of free RAM and room for +around 40 kilobytes of code ROM. + + +FEATURES + + * IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over + multiple network interfaces + * ICMP (Internet Control Message Protocol) for network maintenance and debugging + * IGMP (Internet Group Management Protocol) for multicast traffic management + * MLD (Multicast listener discovery for IPv6). Aims to be compliant with + RFC 2710. No support for MLDv2 + * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). + Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + (Address autoconfiguration) + * UDP (User Datagram Protocol) including experimental UDP-lite extensions + * TCP (Transmission Control Protocol) with congestion control, RTT estimation + and fast recovery/fast retransmit + * raw/native API for enhanced performance + * Optional Berkeley-like socket API + * DNS (Domain names resolver) + + +APPLICATIONS + + * HTTP server with SSI and CGI + * SNMPv2c agent with MIB compiler (Simple Network Management Protocol) + * SNTP (Simple network time protocol) + * NetBIOS name service responder + * MDNS (Multicast DNS) responder + * iPerf server implementation + + +LICENSE + +lwIP is freely available under a BSD license. + + +DEVELOPMENT + +lwIP has grown into an excellent TCP/IP stack for embedded devices, +and developers using the stack often submit bug fixes, improvements, +and additions to the stack to further increase its usefulness. + +Development of lwIP is hosted on Savannah, a central point for +software development, maintenance and distribution. Everyone can +help improve lwIP by use of Savannah's interface, Git and the +mailing list. A core team of developers will commit changes to the +Git source tree. + +The lwIP TCP/IP stack is maintained in the 'lwip' Git module and +contributions (such as platform ports) are in the 'contrib' Git module. + +See doc/savannah.txt for details on Git server access for users and +developers. + +The current Git trees are web-browsable: + http://git.savannah.gnu.org/cgit/lwip.git + http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git + +Submit patches and bugs via the lwIP project page: + http://savannah.nongnu.org/projects/lwip/ + +Continuous integration builds (GCC, clang): + https://travis-ci.org/yarrick/lwip-merged + + +DOCUMENTATION + +Self documentation of the source code is regularly extracted from the current +Git sources and is available from this web page: + http://www.nongnu.org/lwip/ + +There is now a constantly growing wiki about lwIP at + http://lwip.wikia.com/wiki/LwIP_Wiki + +Also, there are mailing lists you can subscribe at + http://savannah.nongnu.org/mail/?group=lwip +plus searchable archives: + http://lists.nongnu.org/archive/html/lwip-users/ + http://lists.nongnu.org/archive/html/lwip-devel/ + +lwIP was originally written by Adam Dunkels: + http://dunkels.com/adam/ + +Reading Adam's papers, the files in docs/, browsing the source code +documentation and browsing the mailing list archives is a good way to +become familiar with the design of lwIP. + +Adam Dunkels +Leon Woestenberg diff --git a/Sming/third-party/lwip2/lwip2-src/UPGRADING b/Sming/third-party/lwip2/lwip2-src/UPGRADING new file mode 100644 index 0000000000..f48f59113a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/UPGRADING @@ -0,0 +1,235 @@ +This file lists major changes between release versions that require +ports or applications to be changed. Use it to update a port or an +application written for an older version of lwIP to correctly work +with newer versions. + + +(git master) + + * [Enter new changes just after this line - do not remove this line] + +(2.0.1) + + ++ Application changes: + + * UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific + netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare + ip_current_netif() to the desired netif for every packet. + See bug #49662 for an explanation. + +(2.0.0) + + ++ Application changes: + + * Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of + "ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif + has to be set "up" before starting the DHCP client + * Added IPv6 support (dual-stack or IPv4/IPv6 only) + * Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only). + * Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs); + supports SNMPv2c (experimental v3 support) + * Moved some core applications from contrib repository to src/apps (and include/lwip/apps) + + +++ Raw API: + * Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/ + tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb + + +++ Socket API: + * Added an implementation for posix sendmsg() + * Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram + + ++ Port changes + + +++ new files: + * MANY new and moved files! + * Added src/Filelists.mk for use in Makefile projects + * Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv" + to let abc.h only contain the actual application programmer's API + + +++ sys layer: + * Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than + the traditional message passing (although with LWIP_COMPAT_MUTEX you are still + open to priority inversion, so this is not recommended any more) + * Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread + instead of using one per netconn (these semaphores are used even with core locking + enabled as some longer lasting functions like big writes still need to delay) + * Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr() + in def.h (to be overridden in cc.h) instead of config + options for netbiosns, httpd, dns, etc. ... + * New abstraction for hton* and ntoh* functions in def.h. + To override them, use the following in cc.h: + #define lwip_htons(x) + #define lwip_htonl(x) + + +++ new options: + * TODO + + +++ new pools: + * Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools + that share memp.c code but do not have to be made global via lwippools.h + * Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc. + * added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item + is now available + + * Signature of LWIP_HOOK_VLAN_SET macro was changed + + * LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp) + or to move buffers to dedicated memory using compiler attributes + + * Standard C headers are used to define sized types and printf formatters + (disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler + does not support these) + + + ++ Major bugfixes/improvements + + * Added IPv6 support (dual-stack or IPv4/IPv6 only) + * Major rewrite of PPP (incl. keep-up with apache pppd) + see doc/ppp.txt for an upgrading how-to + * Major rewrite of SNMP (incl. MIB parser) + * Fixed timing issues that might have lead to losing a DHCP lease + * Made rx processing path more robust against crafted errors + * TCP window scaling support + * modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads) + * made DNS client more robust + * support PBUF_REF for RX packets + * LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate + threads each (needs LWIP_NETCONN_SEM_PER_THREAD) + * Moved and reordered stats (mainly memp/mib2) + +(1.4.0) + + ++ Application changes: + + * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for + compatibility to old applications, but will be removed in the future). + + * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() + + +++ Raw API: + * Changed the semantics of tcp_close() (since it was rather a + shutdown before): Now the application does *NOT* get any calls to the recv + callback (aside from NULL/closed) after calling tcp_close() + + * When calling tcp_abort() from a raw API TCP callback function, + make sure you return ERR_ABRT to prevent accessing unallocated memory. + (ERR_ABRT now means the applicaiton has called tcp_abort!) + + +++ Netconn API: + * Changed netconn_receive() and netconn_accept() to return + err_t, not a pointer to new data/netconn. + + +++ Socket API: + * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they + now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. + + * Added a minimal version of posix fctl() to have a + standardised way to set O_NONBLOCK for nonblocking sockets. + + +++ all APIs: + * correctly implemented SO(F)_REUSEADDR + + ++ Port changes + + +++ new files: + + * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: + + * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains + the actual application programmer's API + + * Separated timer implementation from sys.h/.c, moved to timers.h/.c; + Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you + still want to use your own timer implementation for NO_SYS==0 (as before). + + +++ sys layer: + + * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ + sys_sem_t; + + * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; + + * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use + binary semaphores instead of mutexes - as before) + + +++ new options: + + * Don't waste memory when chaining segments, added option TCP_OVERSIZE to + prevent creating many small pbufs when calling tcp_write with many small + blocks of data. Instead, pbufs are allocated larger than needed and the + space is used for later calls to tcp_write. + + * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs + in tcp_write/udp_send. + + * Added an additional option LWIP_ETHERNET to support ethernet without ARP + (necessary for pure PPPoE) + + * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may + be used to place these pools into user-defined memory by using external + declaration. + + * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT + + +++ new pools: + + * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, + so MEMP_NUM_NETDB has to be set accordingly. + + * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so + MEMP_NUM_LOCALHOSTLIST has to be set accordingly. + + * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have + to be set accordingly. + + * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES + has to be set accordingly + + * Integrated loopif into netif.c - loopif does not have to be created by the + port any more, just define LWIP_HAVE_LOOPIF to 1. + + * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined + in cc.h, e.g. used by igmp) + + * Added printf-formatter X8_F to printf u8_t as hex + + * The heap now may be moved to user-defined memory by defining + LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address + + * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work + with user-allocated structs instead of calling mem_malloc + + * Added const char* name to mem- and memp-stats for easier debugging. + + * Calculate the TCP/UDP checksum while copying to only fetch data once: + Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum + + * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to + more than one pcb. + + * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned + off any more, if this is set to 0, only one packet (the most recent one) is + queued (like demanded by RFC 1122). + + + ++ Major bugfixes/improvements + + * Implemented tcp_shutdown() to only shut down one end of a connection + * Implemented shutdown() at socket- and netconn-level + * Added errorset support to select() + improved select speed overhead + * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) + * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 + * Use macros defined in ip_addr.h to work with IP addresses + * Implemented many nonblocking socket/netconn functions + * Fixed ARP input processing: only add a new entry if a request was directed as us + * mem_realloc() to mem_trim() to prevent confusion with realloc() + * Some improvements for AutoIP (don't route/forward link-local addresses, don't break + existing connections when assigning a routable address) + * Correctly handle remote side overrunning our rcv_wnd in ooseq case + * Removed packing from ip_addr_t, the packed version is now only used in protocol headers + * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 + * Added support for static ARP table entries + +(STABLE-1.3.2) + + * initial version of this file diff --git a/Sming/third-party/lwip2/lwip2-src/doc/FILES b/Sming/third-party/lwip2/lwip2-src/doc/FILES new file mode 100644 index 0000000000..e588575085 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/FILES @@ -0,0 +1,9 @@ +doxygen/ - Configuration files and scripts to create the lwIP doxygen source + documentation (found at http://www.nongnu.org/lwip/) + +savannah.txt - How to obtain the current development source code. +contrib.txt - How to contribute to lwIP as a developer. +rawapi.txt - The documentation for the core API of lwIP. + Also provides an overview about the other APIs and multithreading. +sys_arch.txt - The documentation for a system abstraction layer of lwIP. +ppp.txt - Documentation of the PPP interface for lwIP. diff --git a/Sming/third-party/lwip2/lwip2-src/doc/NO_SYS_SampleCode.c b/Sming/third-party/lwip2/lwip2-src/doc/NO_SYS_SampleCode.c new file mode 100644 index 0000000000..f5c6c10b61 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/NO_SYS_SampleCode.c @@ -0,0 +1,117 @@ +void eth_mac_irq() +{ + /* Service MAC IRQ here */ + + /* Allocate pbuf from pool (avoid using heap in interrupts) */ + struct pbuf* p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL); + + if(p != NULL) { + /* Copy ethernet frame into pbuf */ + pbuf_take(p, eth_data, eth_data_count); + + /* Put in a queue which is processed in main loop */ + if(!queue_try_put(&queue, p)) { + /* queue is full -> packet loss */ + pbuf_free(p); + } + } +} + +static err_t netif_output(struct netif *netif, struct pbuf *p) +{ + LINK_STATS_INC(link.xmit); + + /* Update SNMP stats (only if you use SNMP) */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + int unicast = ((p->payload[0] & 0x01) == 0); + if (unicast) { + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } else { + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } + + lock_interrupts(); + pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0); + /* Start MAC transmit here */ + unlock_interrupts(); + + return ERR_OK; +} + +static void netif_status_callback(struct netif *netif) +{ + printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif))); +} + +static err_t netif_init(struct netif *netif) +{ + netif->linkoutput = netif_output; + netif->output = etharp_output; + netif->output_ip6 = ethip6_output; + netif->mtu = ETHERNET_MTU; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6; + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000); + + SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr)); + netif->hwaddr_len = sizeof(netif->hwaddr); + + return ERR_OK; +} + +void main(void) +{ + struct netif netif; + + lwip_init(); + + netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input); + netif.name[0] = 'e'; + netif.name[1] = '0'; + netif_create_ip6_linklocal_address(&netif, 1); + netif.ip6_autoconfig_enabled = 1; + netif_set_status_callback(&netif, netif_status_callback); + netif_set_default(&netif); + netif_set_up(&netif); + + /* Start DHCP and HTTPD */ + dhcp_init(); + httpd_init(); + + while(1) { + /* Check link state, e.g. via MDIO communication with PHY */ + if(link_state_changed()) { + if(link_is_up()) { + netif_set_link_up(&netif); + } else { + netif_set_link_down(&netif); + } + } + + /* Check for received frames, feed them to lwIP */ + lock_interrupts(); + struct pbuf* p = queue_try_get(&queue); + unlock_interrupts(); + + if(p != NULL) { + LINK_STATS_INC(link.recv); + + /* Update SNMP stats (only if you use SNMP) */ + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + int unicast = ((p->payload[0] & 0x01) == 0); + if (unicast) { + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } else { + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } + + if(netif.input(p, &netif) != ERR_OK) { + pbuf_free(p); + } + } + + /* Cyclic lwIP timers check */ + sys_check_timeouts(); + + /* your application goes here */ + } +} diff --git a/Sming/third-party/lwip2/lwip2-src/doc/contrib.txt b/Sming/third-party/lwip2/lwip2-src/doc/contrib.txt new file mode 100644 index 0000000000..6f0d7bc516 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/contrib.txt @@ -0,0 +1,58 @@ +1 Introduction + +This document describes some guidelines for people participating +in lwIP development. + +2 How to contribute to lwIP + +Here is a short list of suggestions to anybody working with lwIP and +trying to contribute bug reports, fixes, enhancements, platform ports etc. +First of all as you may already know lwIP is a volunteer project so feedback +to fixes or questions might often come late. Hopefully the bug and patch tracking +features of Savannah help us not lose users' input. + +2.1 Source code style: + +1. do not use tabs. +2. indentation is two spaces per level (i.e. per tab). +3. end debug messages with a trailing newline (\n). +4. one space between keyword and opening bracket. +5. no space between function and opening bracket. +6. one space and no newline before opening curly braces of a block. +7. closing curly brace on a single line. +8. spaces surrounding assignment and comparisons. +9. don't initialize static and/or global variables to zero, the compiler takes care of that. +10. use current source code style as further reference. + +2.2 Source code documentation style: + +1. JavaDoc compliant and Doxygen compatible. +2. Function documentation above functions in .c files, not .h files. + (This forces you to synchronize documentation and implementation.) +3. Use current documentation style as further reference. + +2.3 Bug reports and patches: + +1. Make sure you are reporting bugs or send patches against the latest + sources. (From the latest release and/or the current Git sources.) +2. If you think you found a bug make sure it's not already filed in the + bugtracker at Savannah. +3. If you have a fix put the patch on Savannah. If it is a patch that affects + both core and arch specific stuff please separate them so that the core can + be applied separately while leaving the other patch 'open'. The preferred way + is to NOT touch archs you can't test and let maintainers take care of them. + This is a good way to see if they are used at all - the same goes for unix + netifs except tapif. +4. Do not file a bug and post a fix to it to the patch area. Either a bug report + or a patch will be enough. + If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area. +5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other + trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you + change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than + if it's not to the point and long :) so the chances for it to be applied are greater. + +2.4 Platform porters: + +1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and + you think it could benefit others[1] you might want discuss this on the mailing list. You + can also ask for Git access to submit and maintain your port in the contrib Git module. diff --git a/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.bat b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.bat new file mode 100644 index 0000000000..99afb124be --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.bat @@ -0,0 +1 @@ +doxygen lwip.Doxyfile diff --git a/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.sh b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.sh new file mode 100755 index 0000000000..89344b0e81 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/generate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +doxygen lwip.Doxyfile diff --git a/Sming/third-party/lwip2/lwip2-src/doc/doxygen/lwip.Doxyfile b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/lwip.Doxyfile new file mode 100644 index 0000000000..0e3349a79a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/doxygen/lwip.Doxyfile @@ -0,0 +1,2505 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "lwIP" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = "2.0.2" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Lightweight IP stack" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = output + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text " + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = main_page.h ../../src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, +# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.inc \ + *.m \ + *.mm \ + *.dox + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = ../../src/include/netif/ppp/polarssl + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = ../ ../../ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = main_page.h + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = lwip.chm + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /index.html + + diff --git a/Sming/third-party/lwip2/lwip2-src/doc/mdns.txt b/Sming/third-party/lwip2/lwip2-src/doc/mdns.txt new file mode 100644 index 0000000000..c322843217 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/mdns.txt @@ -0,0 +1,113 @@ +Multicast DNS for lwIP + +Author: Erik Ekman + + +Note! The MDNS responder does not have all features required by the standards. +See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal +cases - but watch out if many devices on the same network try to use the same +host/service instance names. + + +How to enable: +============== + +MDNS support does not depend on DNS. +MDNS supports using IPv4 only, v6 only, or v4+v6. + +To enable MDNS responder, set + LWIP_MDNS_RESPONDER = 1 +in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build. + +The max number of services supported per netif is defined by MDNS_MAX_SERVICES, +default is 1. + +Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB. +Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif). + +MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1. +MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is +generated. + +The MDNS code puts its structs on the stack where suitable to reduce dynamic +memory allocation. It may use up to 1kB of stack. + +MDNS needs a strncasecmp() implementation. If you have one, define +LWIP_MDNS_STRNCASECMP to it. Otherwise the code will provide an implementation +for you. + + +How to use: +=========== + +Call mdns_resp_init() during system initialization. +This opens UDP sockets on port 5353 for IPv4 and IPv6. + + +To start responding on a netif, run + mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl) + +The hostname will be copied. If this returns successfully, the netif will join +the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast +to port 5353 will be handled: +- .local type A, AAAA or ANY returns relevant IP addresses +- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses + returns .local +Answers will use the supplied TTL (in seconds) +MDNS allows UTF-8 names, but it is recommended to stay within ASCII, +since the default case-insensitive comparison assumes this. + +It is recommended to call this function after an IPv4 address has been set, +since there is currently no check if the v4 address is valid. + +Call mdns_resp_netif_settings_changed() every time the IP address +on the netif has changed. + +To stop responding on a netif, run + mdns_resp_remove_netif(struct netif *netif) + + +Adding services: +================ + +The netif first needs to be registered. Then run + mdns_resp_add_service(struct netif *netif, char *name, char *service, + u16_t proto, u16_t port, u32_t dns_ttl, + service_get_txt_fn_t txt_fn, void *txt_userdata); + +The name and service pointers will be copied. Name refers to the name of the +service instance, and service is the type of service, like _http +proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp. +If this call returns successfully, the following queries will be answered: +- _services._dns-sd._udp.local type PTR returns ..local +- ..local type PTR returns ...local +- ...local type SRV returns hostname and port of service +- ...local type TXT builds text strings by calling txt_fn + with the supplied userdata. The callback adds strings to the reply by calling + mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt, + int txt_len). Example callback method: + + static void srv_txt(struct mdns_service *service, void *txt_userdata) + { + res = mdns_resp_add_service_txtitem(service, "path=/", 6); + LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return); + } + + Since a hostname struct is used for TXT storage each single item can be max + 63 bytes long, and the total max length (including length bytes for each + item) is 255 bytes. + +If your device runs a webserver on port 80, an example call might be: + + mdns_resp_add_service(netif, "myweb", "_http" + DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL); + +which will publish myweb._http._tcp.local for any hosts looking for web servers, +and point them to .local:80 + +Relevant information will be sent as additional records to reduce number of +requests required from a client. + +Removing services is currently not supported. Services are removed when the +netif is removed. + diff --git a/Sming/third-party/lwip2/lwip2-src/doc/mqtt_client.txt b/Sming/third-party/lwip2/lwip2-src/doc/mqtt_client.txt new file mode 100644 index 0000000000..3e67defdc5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/mqtt_client.txt @@ -0,0 +1,162 @@ +MQTT client for lwIP + +Author: Erik Andersson + +Details of the MQTT protocol can be found at: +http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html + +----------------------------------------------------------------- +1. Initial steps, reserve memory and make connection to server: + +1.1: Provide storage + +Static allocation: + mqtt_client_t static_client; + example_do_connect(&static_client); + +Dynamic allocation: + mqtt_client_t *client = mqtt_client_new(); + if(client != NULL) { + example_do_connect(&client); + } + +1.2: Establish Connection with server + +void example_do_connect(mqtt_client_t *client) +{ + struct mqtt_connect_client_info_t ci; + err_t err; + + /* Setup an empty client info structure */ + memset(&ci, 0, sizeof(ci)); + + /* Minimal amount of information required is client identifier, so set it here */ + ci.client_id = "lwip_test"; + + /* Initiate client and connect to server, if this fails immediately an error code is returned + otherwise mqtt_connection_cb will be called with connection result after attempting + to establish a connection with the server. + For now MQTT version 3.1.1 is always used */ + + err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci); + + /* For now just print the result code if something goes wrong + if(err != ERR_OK) { + printf("mqtt_connect return %d\n", err); + } +} + +Connection to server can also be probed by calling mqtt_client_is_connected(client) + +----------------------------------------------------------------- +2. Implementing the connection status callback + + +static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) +{ + err_t err; + if(status == MQTT_CONNECT_ACCEPTED) { + printf("mqtt_connection_cb: Successfully connected\n"); + + /* Setup callback for incoming publish requests */ + mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg); + + /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ + err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg); + + if(err != ERR_OK) { + printf("mqtt_subscribe return: %d\n", err); + } + } else { + printf("mqtt_connection_cb: Disconnected, reason: %d\n", status); + + /* Its more nice to be connected, so try to reconnect */ + example_do_connect(client); + } +} + +static void mqtt_sub_request_cb(void *arg, err_t result) +{ + /* Just print the result code here for simplicity, + normal behaviour would be to take some action if subscribe fails like + notifying user, retry subscribe or disconnect from server */ + printf("Subscribe result: %d\n", result); +} + +----------------------------------------------------------------- +3. Implementing callbacks for incoming publish and data + +/* The idea is to demultiplex topic and create some reference to be used in data callbacks + Example here uses a global variable, better would be to use a member in arg + If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of + the topic string and use it in mqtt_incoming_data_cb +*/ +static int inpub_id; +static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) +{ + printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len); + + /* Decode topic string into a user defined reference */ + if(strcmp(topic, "print_payload") == 0) { + inpub_id = 0; + } else if(topic[0] == 'A') { + /* All topics starting with 'A' might be handled at the same way */ + inpub_id = 1; + } else { + /* For all other topics */ + inpub_id = 2; + } +} + +static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) +{ + printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags); + + if(flags & MQTT_DATA_FLAG_LAST) { + /* Last fragment of payload received (or whole part if payload fits receive buffer + See MQTT_VAR_HEADER_BUFFER_LEN) */ + + /* Call function or do action depending on reference, in this case inpub_id */ + if(inpub_id == 0) { + /* Don't trust the publisher, check zero termination */ + if(data[len-1] == 0) { + printf("mqtt_incoming_data_cb: %s\n", (const char *)data); + } + } else if(inpub_id == 1) { + /* Call an 'A' function... */ + } else { + printf("mqtt_incoming_data_cb: Ignoring payload...\n"); + } + } else { + /* Handle fragmented payload, store in buffer, write to file or whatever */ + } +} + +----------------------------------------------------------------- +4. Using outgoing publish + + +void example_publish(mqtt_client_t *client, void *arg) +{ + const char *pub_payload= "PubSubHubLubJub"; + err_t err; + u8_t qos = 2; /* 0 1 or 2, see MQTT specification */ + u8_t retain = 0; /* No don't retain such crappy payload... */ + err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg); + if(err != ERR_OK) { + printf("Publish err: %d\n", err); + } +} + +/* Called when publish is complete either with sucess or failure */ +static void mqtt_pub_request_cb(void *arg, err_t result) +{ + if(result != ERR_OK) { + printf("Publish result: %d\n", result); + } +} + +----------------------------------------------------------------- +5. Disconnecting + +Simply call mqtt_disconnect(client) diff --git a/Sming/third-party/lwip2/lwip2-src/doc/ppp.txt b/Sming/third-party/lwip2/lwip2-src/doc/ppp.txt new file mode 100644 index 0000000000..8b88b3a671 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/ppp.txt @@ -0,0 +1,529 @@ +PPP interface for lwIP + +Author: Sylvain Rochet + +Table of Contents: + +1 - Supported PPP protocols and features +2 - Raw API PPP example for all protocols +3 - PPPoS input path (raw API, IRQ safe API, TCPIP API) +4 - Thread safe PPP API (PPPAPI) +5 - Notify phase callback (PPP_NOTIFY_PHASE) +6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x + + + +1 Supported PPP protocols and features +====================================== + +Supported Low level protocols: +* PPP over serial using HDLC-like framing, such as wired dialup modems + or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems +* PPP over Ethernet, such as xDSL modems +* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator), + IP tunnel over UDP, such as VPN access + +Supported auth protocols: +* PAP, Password Authentication Protocol +* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5 +* MSCHAPv1, Microsoft version of CHAP, version 1 +* MSCHAPv2, Microsoft version of CHAP, version 2 +* EAP, Extensible Authentication Protocol + +Supported address protocols: +* IPCP, IP Control Protocol, IPv4 addresses negotiation +* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation + +Supported encryption protocols: +* MPPE, Microsoft Point-to-Point Encryption + +Supported compression or miscellaneous protocols, for serial links only: +* PFC, Protocol Field Compression +* ACFC, Address-and-Control-Field-Compression +* ACCM, Asynchronous-Control-Character-Map +* VJ, Van Jacobson TCP/IP Header Compression + + + +2 Raw API PPP example for all protocols +======================================= + +As usual, raw API for lwIP means the lightweight API which *MUST* only be used +for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems. + +/* + * Globals + * ======= + */ + +/* The PPP control block */ +ppp_pcb *ppp; + +/* The PPP IP interface */ +struct netif ppp_netif; + + +/* + * PPP status callback + * =================== + * + * PPP status callback is called on PPP status change (up, down, …) from lwIP + * core thread + */ + +/* PPP status callback example */ +static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) { + struct netif *pppif = ppp_netif(pcb); + LWIP_UNUSED_ARG(ctx); + + switch(err_code) { + case PPPERR_NONE: { +#if LWIP_DNS + const ip_addr_t *ns; +#endif /* LWIP_DNS */ + printf("status_cb: Connected\n"); +#if PPP_IPV4_SUPPORT + printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr)); + printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw)); + printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask)); +#if LWIP_DNS + ns = dns_getserver(0); + printf(" dns1 = %s\n", ipaddr_ntoa(ns)); + ns = dns_getserver(1); + printf(" dns2 = %s\n", ipaddr_ntoa(ns)); +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); +#endif /* PPP_IPV6_SUPPORT */ + break; + } + case PPPERR_PARAM: { + printf("status_cb: Invalid parameter\n"); + break; + } + case PPPERR_OPEN: { + printf("status_cb: Unable to open PPP session\n"); + break; + } + case PPPERR_DEVICE: { + printf("status_cb: Invalid I/O device for PPP\n"); + break; + } + case PPPERR_ALLOC: { + printf("status_cb: Unable to allocate resources\n"); + break; + } + case PPPERR_USER: { + printf("status_cb: User interrupt\n"); + break; + } + case PPPERR_CONNECT: { + printf("status_cb: Connection lost\n"); + break; + } + case PPPERR_AUTHFAIL: { + printf("status_cb: Failed authentication challenge\n"); + break; + } + case PPPERR_PROTOCOL: { + printf("status_cb: Failed to meet protocol\n"); + break; + } + case PPPERR_PEERDEAD: { + printf("status_cb: Connection timeout\n"); + break; + } + case PPPERR_IDLETIMEOUT: { + printf("status_cb: Idle Timeout\n"); + break; + } + case PPPERR_CONNECTTIME: { + printf("status_cb: Max connect time reached\n"); + break; + } + case PPPERR_LOOPBACK: { + printf("status_cb: Loopback detected\n"); + break; + } + default: { + printf("status_cb: Unknown error code %d\n", err_code); + break; + } + } + +/* + * This should be in the switch case, this is put outside of the switch + * case for example readability. + */ + + if (err_code == PPPERR_NONE) { + return; + } + + /* ppp_close() was previously called, don't reconnect */ + if (err_code == PPPERR_USER) { + /* ppp_free(); -- can be called here */ + return; + } + + /* + * Try to reconnect in 30 seconds, if you need a modem chatscript you have + * to do a much better signaling here ;-) + */ + ppp_connect(pcb, 30); + /* OR ppp_listen(pcb); */ +} + + +/* + * Creating a new PPPoS session + * ============================ + * + * In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial. + */ + +#include "netif/ppp/pppos.h" + +/* + * PPPoS serial output callback + * + * ppp_pcb, PPP control block + * data, buffer to write to serial port + * len, length of the data buffer + * ctx, optional user-provided callback context pointer + * + * Return value: len if write succeed + */ +static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { + return uart_write(UART, data, len); +} + +/* + * Create a new PPPoS interface + * + * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface + * output_cb, PPPoS serial output callback + * status_cb, PPP status callback, called on PPP status change (up, down, …) + * ctx_cb, optional user-provided callback context pointer + */ +ppp = pppos_create(&ppp_netif, + output_cb, status_cb, ctx_cb); + + +/* + * Creating a new PPPoE session + * ============================ + */ + +#include "netif/ppp/pppoe.h" + +/* + * Create a new PPPoE interface + * + * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface + * ethif, already existing and setup Ethernet interface to use + * service_name, PPPoE service name discriminator (not supported yet) + * concentrator_name, PPPoE concentrator name discriminator (not supported yet) + * status_cb, PPP status callback, called on PPP status change (up, down, …) + * ctx_cb, optional user-provided callback context pointer + */ +ppp = pppoe_create(&ppp_netif, + ðif, + service_name, concentrator_name, + status_cb, ctx_cb); + + +/* + * Creating a new PPPoL2TP session + * =============================== + */ + +#include "netif/ppp/pppol2tp.h" + +/* + * Create a new PPPoL2TP interface + * + * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface + * netif, optional already existing and setup output netif, necessary if you + * want to set this interface as default route to settle the chicken + * and egg problem with VPN links + * ipaddr, IP to connect to + * port, UDP port to connect to (usually 1701) + * secret, L2TP secret to use + * secret_len, size in bytes of the L2TP secret + * status_cb, PPP status callback, called on PPP status change (up, down, …) + * ctx_cb, optional user-provided callback context pointer + */ +ppp = pppol2tp_create(&ppp_netif, + struct netif *netif, ip_addr_t *ipaddr, u16_t port, + u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + + +/* + * Initiate PPP client connection + * ============================== + */ + +/* Set this interface as default route */ +ppp_set_default(ppp); + +/* + * Basic PPP client configuration. Can only be set if PPP session is in the + * dead state (i.e. disconnected). We don't need to provide thread-safe + * equivalents through PPPAPI because those helpers are only changing + * structure members while session is inactive for lwIP core. Configuration + * only need to be done once. + */ + +/* Ask the peer for up to 2 DNS server addresses. */ +ppp_set_usepeerdns(ppp, 1); + +/* Auth configuration, this is pretty self-explanatory */ +ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); + +/* + * Initiate PPP negotiation, without waiting (holdoff=0), can only be called + * if PPP session is in the dead state (i.e. disconnected). + */ +u16_t holdoff = 0; +ppp_connect(ppp, holdoff); + + +/* + * Initiate PPP server listener + * ============================ + */ + +/* + * Basic PPP server configuration. Can only be set if PPP session is in the + * dead state (i.e. disconnected). We don't need to provide thread-safe + * equivalents through PPPAPI because those helpers are only changing + * structure members while session is inactive for lwIP core. Configuration + * only need to be done once. + */ +ip4_addr_t addr; + +/* Set our address */ +IP4_ADDR(&addr, 192,168,0,1); +ppp_set_ipcp_ouraddr(ppp, &addr); + +/* Set peer(his) address */ +IP4_ADDR(&addr, 192,168,0,2); +ppp_set_ipcp_hisaddr(ppp, &addr); + +/* Set primary DNS server */ +IP4_ADDR(&addr, 192,168,10,20); +ppp_set_ipcp_dnsaddr(ppp, 0, &addr); + +/* Set secondary DNS server */ +IP4_ADDR(&addr, 192,168,10,21); +ppp_set_ipcp_dnsaddr(ppp, 1, &addr); + +/* Auth configuration, this is pretty self-explanatory */ +ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); + +/* Require peer to authenticate */ +ppp_set_auth_required(ppp, 1); + +/* + * Only for PPPoS, the PPP session should be up and waiting for input. + * + * Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing. + * The listen call is meant for future support of PPPoE and PPPoL2TP server + * mode, where we will need to negotiate the incoming PPPoE session or L2TP + * session before initiating PPP itself. We need this call because there is + * two passive modes for PPPoS, ppp_set_passive and ppp_set_silent. + */ +ppp_set_silent(pppos, 1); + +/* + * Initiate PPP listener (i.e. wait for an incoming connection), can only + * be called if PPP session is in the dead state (i.e. disconnected). + */ +ppp_listen(ppp); + + +/* + * Closing PPP connection + * ====================== + */ + +/* + * Initiate the end of the PPP session, without carrier lost signal + * (nocarrier=0), meaning a clean shutdown of PPP protocols. + * You can call this function at anytime. + */ +u8_t nocarrier = 0; +ppp_close(ppp, nocarrier); +/* + * Then you must wait your status_cb() to be called, it may takes from a few + * seconds to several tens of seconds depending on the current PPP state. + */ + +/* + * Freeing a PPP connection + * ======================== + */ + +/* + * Free the PPP control block, can only be called if PPP session is in the + * dead state (i.e. disconnected). You need to call ppp_close() before. + */ +ppp_free(ppp); + + + +3 PPPoS input path (raw API, IRQ safe API, TCPIP API) +===================================================== + +Received data on serial port should be sent to lwIP using the pppos_input() +function or the pppos_input_tcpip() function. + +If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input() +is not IRQ safe and then *MUST* only be called inside your main loop. + +Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ +safe and can be safely called from an interrupt context, using that is going +to reduce your need of buffer if pppos_input() is called byte after byte in +your rx serial interrupt. + +if NO_SYS is 0, the thread safe way outside an interrupt context is to use +the pppos_input_tcpip() function to pass input data to the lwIP core thread +using the TCPIP API. This is thread safe in all cases but you should avoid +passing data byte after byte because it uses heavy locking (mailbox) and it +allocates pbuf, better fill them ! + +if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input() +from an RX thread, however pppos_input() is not thread safe by itself. You can +do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and +ppp_free() if pppos_input() can still be running, doing this is NOT thread safe +at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you +really know what you are doing, your move ;-) + + +/* + * Fonction to call for received data + * + * ppp, PPP control block + * buffer, input buffer + * buffer_len, buffer length in bytes + */ +void pppos_input(ppp, buffer, buffer_len); + +or + +void pppos_input_tcpip(ppp, buffer, buffer_len); + + + +4 Thread safe PPP API (PPPAPI) +============================== + +There is a thread safe API for all corresponding ppp_* functions, you have to +enable LWIP_PPP_API in your lwipopts.h file, then see +include/netif/ppp/pppapi.h, this is actually pretty obvious. + + + +5 Notify phase callback (PPP_NOTIFY_PHASE) +========================================== + +Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let +you configure a callback that is called on each PPP internal state change. +This is different from the status callback which only warns you about +up(running) and down(dead) events. + +Notify phase callback can be used, for example, to set a LED pattern depending +on the current phase of the PPP session. Here is a callback example which +tries to mimic what we usually see on xDSL modems while they are negotiating +the link, which should be self-explanatory: + +static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) { + switch (phase) { + + /* Session is down (either permanently or briefly) */ + case PPP_PHASE_DEAD: + led_set(PPP_LED, LED_OFF); + break; + + /* We are between two sessions */ + case PPP_PHASE_HOLDOFF: + led_set(PPP_LED, LED_SLOW_BLINK); + break; + + /* Session just started */ + case PPP_PHASE_INITIALIZE: + led_set(PPP_LED, LED_FAST_BLINK); + break; + + /* Session is running */ + case PPP_PHASE_RUNNING: + led_set(PPP_LED, LED_ON); + break; + + default: + break; + } +} + + + +6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x +=============================================== + +PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting +from previous lwIP version is pretty easy: + +* Previous PPP API used an integer to identify PPP sessions, we are now + using ppp_pcb* control block, therefore all functions changed from "int ppp" + to "ppp_pcb *ppp" + +* struct netif was moved outside the PPP structure, you have to provide a netif + for PPP interface in pppoX_create() functions + +* PPP session are not started automatically after you created them anymore, + you have to call ppp_connect(), this way you can configure the session before + starting it. + +* Previous PPP API used CamelCase, we are now using snake_case. + +* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore, + PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed + pppoe_, common functions are now prefixed ppp_. + +* New PPPERR_ error codes added, check you have all of them in your status + callback function + +* Only the following include files should now be used in user application: + #include "netif/ppp/pppapi.h" + #include "netif/ppp/pppos.h" + #include "netif/ppp/pppoe.h" + #include "netif/ppp/pppol2tp.h" + + Functions from ppp.h can be used, but you don't need to include this header + file as it is already included by above header files. + +* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create + your own serial rx thread + +* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed + PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above + because you might have been fooled by that + +* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use + the PPPAPI API instead. + +* ppp_sighup and ppp_close functions were merged using an optional argument + "nocarrier" on ppp_close. + +* DNS servers are now only remotely asked if LWIP_DNS is set and if + ppp_set_usepeerdns() is set to true, they are now automatically registered + using the dns_setserver() function so you don't need to do that in the PPP + callback anymore. + +* PPPoS does not use the SIO API anymore, as such it now requires a serial + output callback in place of sio_write + +* PPP_MAXIDLEFLAG is now in ms instead of jiffies diff --git a/Sming/third-party/lwip2/lwip2-src/doc/rawapi.txt b/Sming/third-party/lwip2/lwip2-src/doc/rawapi.txt new file mode 100644 index 0000000000..0cdfdcead1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/rawapi.txt @@ -0,0 +1,499 @@ +Raw TCP/IP interface for lwIP + +Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons + +lwIP provides three Application Program's Interfaces (APIs) for programs +to use for communication with the TCP/IP code: +* low-level "core" / "callback" or "raw" API. +* higher-level "sequential" API. +* BSD-style socket API. + +The raw API (sometimes called native API) is an event-driven API designed +to be used without an operating system that implements zero-copy send and +receive. This API is also used by the core stack for interaction between +the various protocols. It is the only API available when running lwIP +without an operating system. + +The sequential API provides a way for ordinary, sequential, programs +to use the lwIP stack. It is quite similar to the BSD socket API. The +model of execution is based on the blocking open-read-write-close +paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP +code and the application program must reside in different execution +contexts (threads). + +The socket API is a compatibility API for existing applications, +currently it is built on top of the sequential API. It is meant to +provide all functions needed to run socket API applications running +on other platforms (e.g. unix / windows etc.). However, due to limitations +in the specification of this API, there might be incompatibilities +that require small modifications of existing programs. + +** Multithreading + +lwIP started targeting single-threaded environments. When adding multi- +threading support, instead of making the core thread-safe, another +approach was chosen: there is one main thread running the lwIP core +(also known as the "tcpip_thread"). When running in a multithreaded +environment, raw API functions MUST only be called from the core thread +since raw API functions are not protected from concurrent access (aside +from pbuf- and memory management functions). Application threads using +the sequential- or socket API communicate with this main thread through +message passing. + + As such, the list of functions that may be called from + other threads or an ISR is very limited! Only functions + from these API header files are thread-safe: + - api.h + - netbuf.h + - netdb.h + - netifapi.h + - pppapi.h + - sockets.h + - sys.h + + Additionaly, memory (de-)allocation functions may be + called from multiple threads (not ISR!) with NO_SYS=0 + since they are protected by SYS_LIGHTWEIGHT_PROT and/or + semaphores. + + Netconn or Socket API functions are thread safe against the + core thread but they are not reentrant at the control block + granularity level. That is, a UDP or TCP control block must + not be shared among multiple threads without proper locking. + + If SYS_LIGHTWEIGHT_PROT is set to 1 and + LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, + pbuf_free() may also be called from another thread or + an ISR (since only then, mem_free - for PBUF_RAM - may + be called from an ISR: otherwise, the HEAP is only + protected by semaphores). + + +** The remainder of this document discusses the "raw" API. ** + +The raw TCP/IP interface allows the application program to integrate +better with the TCP/IP code. Program execution is event based by +having callback functions being called from within the TCP/IP +code. The TCP/IP code and the application program both run in the same +thread. The sequential API has a much higher overhead and is not very +well suited for small systems since it forces a multithreaded paradigm +on the application. + +The raw TCP/IP interface is not only faster in terms of code execution +time but is also less memory intensive. The drawback is that program +development is somewhat harder and application programs written for +the raw TCP/IP interface are more difficult to understand. Still, this +is the preferred way of writing applications that should be small in +code size and memory usage. + +All APIs can be used simultaneously by different application +programs. In fact, the sequential API is implemented as an application +program using the raw TCP/IP interface. + +Do not confuse the lwIP raw API with raw Ethernet or IP sockets. +The former is a way of interfacing the lwIP network stack (including +TCP and UDP), the later refers to processing raw Ethernet or IP data +instead of TCP connections or UDP packets. + +Raw API applications may never block since all packet processing +(input and output) as well as timer processing (TCP mainly) is done +in a single execution context. + +--- Callbacks + +Program execution is driven by callbacks functions, which are then +invoked by the lwIP core when activity related to that application +occurs. A particular application may register to be notified via a +callback function for events such as incoming data available, outgoing +data sent, error notifications, poll timer expiration, connection +closed, etc. An application can provide a callback function to perform +processing for any or all of these events. Each callback is an ordinary +C function that is called from within the TCP/IP code. Every callback +function is passed the current TCP or UDP connection state as an +argument. Also, in order to be able to keep program specific state, +the callback functions are called with a program specified argument +that is independent of the TCP/IP state. + +The function for setting the application connection state is: + +- void tcp_arg(struct tcp_pcb *pcb, void *arg) + + Specifies the program specific state that should be passed to all + other callback functions. The "pcb" argument is the current TCP + connection control block, and the "arg" argument is the argument + that will be passed to the callbacks. + + +--- TCP connection setup + +The functions used for setting up connections is similar to that of +the sequential API and of the BSD socket API. A new TCP connection +identifier (i.e., a protocol control block - PCB) is created with the +tcp_new() function. This PCB can then be either set to listen for new +incoming connections or be explicitly connected to another host. + +- struct tcp_pcb *tcp_new(void) + + Creates a new connection identifier (PCB). If memory is not + available for creating the new pcb, NULL is returned. + +- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port) + + Binds the pcb to a local IP address and port number. The IP address + can be specified as IP_ADDR_ANY in order to bind the connection to + all local IP addresses. + + If another connection is bound to the same port, the function will + return ERR_USE, otherwise ERR_OK is returned. + +- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) + + Commands a pcb to start listening for incoming connections. When an + incoming connection is accepted, the function specified with the + tcp_accept() function will be called. The pcb will have to be bound + to a local port with the tcp_bind() function. + + The tcp_listen() function returns a new connection identifier, and + the one passed as an argument to the function will be + deallocated. The reason for this behavior is that less memory is + needed for a connection that is listening, so tcp_listen() will + reclaim the memory needed for the original connection and allocate a + new smaller memory block for the listening connection. + + tcp_listen() may return NULL if no memory was available for the + listening connection. If so, the memory associated with the pcb + passed as an argument to tcp_listen() will not be deallocated. + +- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) + + Same as tcp_listen, but limits the number of outstanding connections + in the listen queue to the value specified by the backlog argument. + To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. + +- void tcp_accept(struct tcp_pcb *pcb, + err_t (* accept)(void *arg, struct tcp_pcb *newpcb, + err_t err)) + + Specified the callback function that should be called when a new + connection arrives on a listening connection. + +- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, err_t (* connected)(void *arg, + struct tcp_pcb *tpcb, + err_t err)); + + Sets up the pcb to connect to the remote host and sends the + initial SYN segment which opens the connection. + + The tcp_connect() function returns immediately; it does not wait for + the connection to be properly setup. Instead, it will call the + function specified as the fourth argument (the "connected" argument) + when the connection is established. If the connection could not be + properly established, either because the other host refused the + connection or because the other host didn't answer, the "err" + callback function of this pcb (registered with tcp_err, see below) + will be called. + + The tcp_connect() function can return ERR_MEM if no memory is + available for enqueueing the SYN segment. If the SYN indeed was + enqueued successfully, the tcp_connect() function returns ERR_OK. + + +--- Sending TCP data + +TCP data is sent by enqueueing the data with a call to +tcp_write(). When the data is successfully transmitted to the remote +host, the application will be notified with a call to a specified +callback function. + +- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags) + + Enqueues the data pointed to by the argument dataptr. The length of + the data is passed as the len parameter. The apiflags can be one or more of: + - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated + for the data to be copied into. If this flag is not given, no new memory + should be allocated and the data should only be referenced by pointer. This + also means that the memory behind dataptr must not change until the data is + ACKed by the remote host + - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted, + the PSH flag is set in the last segment created by this call to tcp_write. + If this flag is given, the PSH flag is not set. + + The tcp_write() function will fail and return ERR_MEM if the length + of the data exceeds the current send buffer size or if the length of + the queue of outgoing segment is larger than the upper limit defined + in lwipopts.h. The number of bytes available in the output queue can + be retrieved with the tcp_sndbuf() function. + + The proper way to use this function is to call the function with at + most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, + the application should wait until some of the currently enqueued + data has been successfully received by the other host and try again. + +- void tcp_sent(struct tcp_pcb *pcb, + err_t (* sent)(void *arg, struct tcp_pcb *tpcb, + u16_t len)) + + Specifies the callback function that should be called when data has + successfully been received (i.e., acknowledged) by the remote + host. The len argument passed to the callback function gives the + amount bytes that was acknowledged by the last acknowledgment. + + +--- Receiving TCP data + +TCP data reception is callback based - an application specified +callback function is called when new data arrives. When the +application has taken the data, it has to call the tcp_recved() +function to indicate that TCP can advertise increase the receive +window. + +- void tcp_recv(struct tcp_pcb *pcb, + err_t (* recv)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err)) + + Sets the callback function that will be called when new data + arrives. The callback function will be passed a NULL pbuf to + indicate that the remote host has closed the connection. If + there are no errors and the callback function is to return + ERR_OK, then it must free the pbuf. Otherwise, it must not + free the pbuf so that lwIP core code can store it. + +- void tcp_recved(struct tcp_pcb *pcb, u16_t len) + + Must be called when the application has received the data. The len + argument indicates the length of the received data. + + +--- Application polling + +When a connection is idle (i.e., no data is either transmitted or +received), lwIP will repeatedly poll the application by calling a +specified callback function. This can be used either as a watchdog +timer for killing connections that have stayed idle for too long, or +as a method of waiting for memory to become available. For instance, +if a call to tcp_write() has failed because memory wasn't available, +the application may use the polling functionality to call tcp_write() +again when the connection has been idle for a while. + +- void tcp_poll(struct tcp_pcb *pcb, + err_t (* poll)(void *arg, struct tcp_pcb *tpcb), + u8_t interval) + + Specifies the polling interval and the callback function that should + be called to poll the application. The interval is specified in + number of TCP coarse grained timer shots, which typically occurs + twice a second. An interval of 10 means that the application would + be polled every 5 seconds. + + +--- Closing and aborting connections + +- err_t tcp_close(struct tcp_pcb *pcb) + + Closes the connection. The function may return ERR_MEM if no memory + was available for closing the connection. If so, the application + should wait and try again either by using the acknowledgment + callback or the polling functionality. If the close succeeds, the + function returns ERR_OK. + + The pcb is deallocated by the TCP code after a call to tcp_close(). + +- void tcp_abort(struct tcp_pcb *pcb) + + Aborts the connection by sending a RST (reset) segment to the remote + host. The pcb is deallocated. This function never fails. + + ATTENTION: When calling this from one of the TCP callbacks, make + sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + or you will risk accessing deallocated memory or memory leaks! + + +If a connection is aborted because of an error, the application is +alerted of this event by the err callback. Errors that might abort a +connection are when there is a shortage of memory. The callback +function to be called is set using the tcp_err() function. + +- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, + err_t err)) + + The error callback function does not get the pcb passed to it as a + parameter since the pcb may already have been deallocated. + + +--- UDP interface + +The UDP interface is similar to that of TCP, but due to the lower +level of complexity of UDP, the interface is significantly simpler. + +- struct udp_pcb *udp_new(void) + + Creates a new UDP pcb which can be used for UDP communication. The + pcb is not active until it has either been bound to a local address + or connected to a remote address. + +- void udp_remove(struct udp_pcb *pcb) + + Removes and deallocates the pcb. + +- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port) + + Binds the pcb to a local address. The IP-address argument "ipaddr" + can be IP_ADDR_ANY to indicate that it should listen to any local IP + address. The function currently always return ERR_OK. + +- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port) + + Sets the remote end of the pcb. This function does not generate any + network traffic, but only set the remote address of the pcb. + +- err_t udp_disconnect(struct udp_pcb *pcb) + + Remove the remote end of the pcb. This function does not generate + any network traffic, but only removes the remote address of the pcb. + +- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) + + Sends the pbuf p. The pbuf is not deallocated. + +- void udp_recv(struct udp_pcb *pcb, + void (* recv)(void *arg, struct udp_pcb *upcb, + struct pbuf *p, + ip_addr_t *addr, + u16_t port), + void *recv_arg) + + Specifies a callback function that should be called when a UDP + datagram is received. + + +--- System initalization + +A truly complete and generic sequence for initializing the lwIP stack +cannot be given because it depends on additional initializations for +your runtime environment (e.g. timers). + +We can give you some idea on how to proceed when using the raw API. +We assume a configuration using a single Ethernet netif and the +UDP and TCP transport layers, IPv4 and the DHCP client. + +Call these functions in the order of appearance: + +- lwip_init() + + Initialize the lwIP stack and all of its subsystems. + +- netif_add(struct netif *netif, const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, const ip4_addr_t *gw, + void *state, netif_init_fn init, netif_input_fn input) + + Adds your network interface to the netif_list. Allocate a struct + netif and pass a pointer to this structure as the first argument. + Give pointers to cleared ip_addr structures when using DHCP, + or fill them with sane numbers otherwise. The state pointer may be NULL. + + The init function pointer must point to a initialization function for + your Ethernet netif interface. The following code illustrates its use. + + err_t netif_if_init(struct netif *netif) + { + u8_t i; + + for (i = 0; i < ETHARP_HWADDR_LEN; i++) { + netif->hwaddr[i] = some_eth_addr[i]; + } + init_my_eth_device(); + return ERR_OK; + } + + For Ethernet drivers, the input function pointer must point to the lwIP + function ethernet_input() declared in "netif/etharp.h". Other drivers + must use ip_input() declared in "lwip/ip.h". + +- netif_set_default(struct netif *netif) + + Registers the default network interface. + +- netif_set_link_up(struct netif *netif) + + This is the hardware link state; e.g. whether cable is plugged for wired + Ethernet interface. This function must be called even if you don't know + the current state. Having link up and link down events is optional but + DHCP and IPv6 discover benefit well from those events. + +- netif_set_up(struct netif *netif) + + This is the administrative (= software) state of the netif, when the + netif is fully configured this function must be called. + +- dhcp_start(struct netif *netif) + + Creates a new DHCP client for this interface on the first call. + + You can peek in the netif->dhcp struct for the actual DHCP status. + +- sys_check_timeouts() + + When the system is running, you have to periodically call + sys_check_timeouts() which will handle all timers for all protocols in + the stack; add this to your main loop or equivalent. + + +--- Optimalization hints + +The first thing you want to optimize is the lwip_standard_checksum() +routine from src/core/inet.c. You can override this standard +function with the #define LWIP_CHKSUM . + +There are C examples given in inet.c or you might want to +craft an assembly function for this. RFC1071 is a good +introduction to this subject. + +Other significant improvements can be made by supplying +assembly or inline replacements for htons() and htonl() +if you're using a little-endian architecture. +#define lwip_htons(x) +#define lwip_htonl(x) +If you #define them to htons() and htonl(), you should +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from +defining hton*/ntoh* compatibility macros. + +Check your network interface driver if it reads at +a higher speed than the maximum wire-speed. If the +hardware isn't serviced frequently and fast enough +buffer overflows are likely to occur. + +E.g. when using the cs8900 driver, call cs8900if_service(ethif) +as frequently as possible. When using an RTOS let the cs8900 interrupt +wake a high priority task that services your driver using a binary +semaphore or event flag. Some drivers might allow additional tuning +to match your application and network. + +For a production release it is recommended to set LWIP_STATS to 0. +Note that speed performance isn't influenced much by simply setting +high values to the memory options. + +For more optimization hints take a look at the lwIP wiki. + +--- Zero-copy MACs + +To achieve zero-copy on transmit, the data passed to the raw API must +remain unchanged until sent. Because the send- (or write-)functions return +when the packets have been enqueued for sending, data must be kept stable +after that, too. + +This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions +must *not* be reused by the application unless their ref-count is 1. + +For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too, +but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while +PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change). + +Also, data passed to tcp_write without the copy-flag must not be changed! + +Therefore, be careful which type of PBUF you use and if you copy TCP data +or not! diff --git a/Sming/third-party/lwip2/lwip2-src/doc/savannah.txt b/Sming/third-party/lwip2/lwip2-src/doc/savannah.txt new file mode 100644 index 0000000000..d7d19eb6eb --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/savannah.txt @@ -0,0 +1,120 @@ +Daily Use Guide for using Savannah for lwIP + +Table of Contents: + +1 - Obtaining lwIP from the Git repository +2 - Committers/developers Git access using SSH +3 - Merging a development branch to master branch +4 - How to release lwIP + + + +1 Obtaining lwIP from the Git repository +---------------------------------------- + +To perform an anonymous Git clone of the master branch (this is where +bug fixes and incremental enhancements occur), do this: + git clone git://git.savannah.nongnu.org/lwip.git + +Or, obtain a stable branch (updated with bug fixes only) as follows: + git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git + +Or, obtain a specific (fixed) release as follows: + git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git + + +2 Committers/developers Git access using SSH +-------------------------------------------- + +The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption. +As such, Git commits to the server occur through a SSH tunnel for project members. +To create a SSH2 key pair in UNIX-like environments, do this: + ssh-keygen -t dsa + +Under Windows, a recommended SSH client is "PuTTY", freely available with good +documentation and a graphic user interface. Use its key generator. + +Now paste the id_dsa.pub contents into your Savannah account public key list. Wait +a while so that Savannah can update its configuration (This can take minutes). + +Try to login using SSH: + ssh -v your_login@git.sv.gnu.org + +If it tells you: + Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686 + + Interactive shell login is not possible for security reasons. + VCS commands are allowed. + Last login: Tue May 15 23:10:12 2012 from 82.245.102.129 + You tried to execute: + Sorry, you are not allowed to execute that command. + Shared connection to git.sv.gnu.org closed. + +then you could login; Savannah refuses to give you a shell - which is OK, as we +are allowed to use SSH for Git only. Now, you should be able to do this: + git clone your_login@git.sv.gnu.org:/srv/git/lwip.git + +After which you can edit your local files with bug fixes or new features and +commit them. Make sure you know what you are doing when using Git to make +changes on the repository. If in doubt, ask on the lwip-members mailing list. + +(If SSH asks about authenticity of the host, you can check the key +fingerprint against https://savannah.nongnu.org/git/?group=lwip + + +3 - Merging a development branch to master branch +------------------------------------------------- + +Merging is a straightforward process in Git. How to merge all changes in a +development branch since our last merge from main: + +Checkout the master branch: + git checkout master + +Merge the development branch to master: + git merge your-development-branch + +Resolve any conflict. + +Commit the merge result. + git commit -a + +Push your commits: + git push + + +4 How to release lwIP +--------------------- + +First, tag the release using Git: (I use release number 1.4.1 throughout +this example). + git tag -a STABLE-1_4_1 + +Share the tag reference by pushing it to remote: + git push origin STABLE-1_4_1 + +Prepare the release: + cp -r lwip lwip-1.4.1 + rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes + +Archive the current directory using tar, gzip'd, bzip2'd and zip'd. + tar czvf lwip-1.4.1.tar.gz lwip-1.4.1 + tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1 + zip -r lwip-1.4.1.zip lwip-1.4.1 + +Now, sign the archives with a detached GPG binary signature as follows: + gpg -b lwip-1.4.1.tar.gz + gpg -b lwip-1.4.1.tar.bz2 + gpg -b lwip-1.4.1.zip + +Upload these files using anonymous FTP: + ncftp ftp://savannah.gnu.org/incoming/savannah/lwip + ncftp> mput *1.4.1.* + +Additionally, you may post a news item on Savannah, like this: + +A new 1.4.1 release is now available here: +http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1 + +You will have to submit this via the user News interface, then approve +this via the Administrator News interface. diff --git a/Sming/third-party/lwip2/lwip2-src/doc/sys_arch.txt b/Sming/third-party/lwip2/lwip2-src/doc/sys_arch.txt new file mode 100644 index 0000000000..4dc727b657 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/doc/sys_arch.txt @@ -0,0 +1,303 @@ +sys_arch interface for lwIP + +Author: Adam Dunkels + Simon Goldschmidt + +The operating system emulation layer provides a common interface +between the lwIP code and the underlying operating system kernel. The +general idea is that porting lwIP to new architectures requires only +small changes to a few header files and a new sys_arch +implementation. It is also possible to do a sys_arch implementation +that does not rely on any underlying operating system. + +The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full +lwIP functionality, multiple threads support can be implemented in the +sys_arch, but this is not required for the basic lwIP +functionality. Timer scheduling is implemented in lwIP, but can be implemented +by the sys_arch port (LWIP_TIMERS_CUSTOM==1). + +In addition to the source file providing the functionality of sys_arch, +the OS emulation layer must provide several header files defining +macros used throughout lwip. The files required and the macros they +must define are listed below the sys_arch description. + +Semaphores can be either counting or binary - lwIP works with both +kinds. Mailboxes should be implemented as a queue which allows multiple messages +to be posted (implementing as a rendez-vous point where only one message can be +posted at a time can have a highly negative impact on performance). A message +in a mailbox is just a pointer, nothing more. + +Semaphores are represented by the type "sys_sem_t" which is typedef'd +in the sys_arch.h file. Mailboxes are equivalently represented by the +type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t". +lwIP does not place any restrictions on how these types are represented +internally. + +Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that +allows both using pointers or actual OS structures to be used. This way, memory +required for such types can be either allocated in place (globally or on the +stack) or on the heap (allocated internally in the "*_new()" functions). + +The following functions must be implemented by the sys_arch: + +- void sys_init(void) + + Is called to initialize the sys_arch layer. + +- err_t sys_sem_new(sys_sem_t *sem, u8_t count) + + Creates a new semaphore. The semaphore is allocated to the memory that 'sem' + points to (which can be both a pointer or the actual OS structure). + The "count" argument specifies the initial state of the semaphore (which is + either 0 or 1). + If the semaphore has been created, ERR_OK should be returned. Returning any + other error will provide a hint what went wrong, but except for assertions, + no real error handling is implemented. + +- void sys_sem_free(sys_sem_t *sem) + + Deallocates a semaphore. + +- void sys_sem_signal(sys_sem_t *sem) + + Signals a semaphore. + +- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) + + Blocks the thread while waiting for the semaphore to be + signaled. If the "timeout" argument is non-zero, the thread should + only be blocked for the specified time (measured in + milliseconds). If the "timeout" argument is zero, the thread should be + blocked until the semaphore is signalled. + + If the timeout argument is non-zero, the return value is the number of + milliseconds spent waiting for the semaphore to be signaled. If the + semaphore wasn't signaled within the specified time, the return value is + SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore + (i.e., it was already signaled), the function may return zero. + + Notice that lwIP implements a function with a similar name, + sys_sem_wait(), that uses the sys_arch_sem_wait() function. + +- int sys_sem_valid(sys_sem_t *sem) + + Returns 1 if the semaphore is valid, 0 if it is not valid. + When using pointers, a simple way is to check the pointer for != NULL. + When directly using OS structures, implementing this may be more complex. + This may also be a define, in which case the function is not prototyped. + +- void sys_sem_set_invalid(sys_sem_t *sem) + + Invalidate a semaphore so that sys_sem_valid() returns 0. + ATTENTION: This does NOT mean that the semaphore shall be deallocated: + sys_sem_free() is always called before calling this function! + This may also be a define, in which case the function is not prototyped. + +- void sys_mutex_new(sys_mutex_t *mutex) + + Creates a new mutex. The mutex is allocated to the memory that 'mutex' + points to (which can be both a pointer or the actual OS structure). + If the mutex has been created, ERR_OK should be returned. Returning any + other error will provide a hint what went wrong, but except for assertions, + no real error handling is implemented. + +- void sys_mutex_free(sys_mutex_t *mutex) + + Deallocates a mutex. + +- void sys_mutex_lock(sys_mutex_t *mutex) + + Blocks the thread until the mutex can be grabbed. + +- void sys_mutex_unlock(sys_mutex_t *mutex) + + Releases the mutex previously locked through 'sys_mutex_lock()'. + +- void sys_mutex_valid(sys_mutex_t *mutex) + + Returns 1 if the mutes is valid, 0 if it is not valid. + When using pointers, a simple way is to check the pointer for != NULL. + When directly using OS structures, implementing this may be more complex. + This may also be a define, in which case the function is not prototyped. + +- void sys_mutex_set_invalid(sys_mutex_t *mutex) + + Invalidate a mutex so that sys_mutex_valid() returns 0. + ATTENTION: This does NOT mean that the mutex shall be deallocated: + sys_mutex_free() is always called before calling this function! + This may also be a define, in which case the function is not prototyped. + +- err_t sys_mbox_new(sys_mbox_t *mbox, int size) + + Creates an empty mailbox for maximum "size" elements. Elements stored + in mailboxes are pointers. You have to define macros "_MBOX_SIZE" + in your lwipopts.h, or ignore this parameter in your implementation + and use a default size. + If the mailbox has been created, ERR_OK should be returned. Returning any + other error will provide a hint what went wrong, but except for assertions, + no real error handling is implemented. + +- void sys_mbox_free(sys_mbox_t *mbox) + + Deallocates a mailbox. If there are messages still present in the + mailbox when the mailbox is deallocated, it is an indication of a + programming error in lwIP and the developer should be notified. + +- void sys_mbox_post(sys_mbox_t *mbox, void *msg) + + Posts the "msg" to the mailbox. This function have to block until + the "msg" is really posted. + +- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) + + Try to post the "msg" to the mailbox. Returns ERR_MEM if this one + is full, else, ERR_OK if the "msg" is posted. + +- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) + + Blocks the thread until a message arrives in the mailbox, but does + not block the thread longer than "timeout" milliseconds (similar to + the sys_arch_sem_wait() function). If "timeout" is 0, the thread should + be blocked until a message arrives. The "msg" argument is a result + parameter that is set by the function (i.e., by doing "*msg = + ptr"). The "msg" parameter maybe NULL to indicate that the message + should be dropped. + + The return values are the same as for the sys_arch_sem_wait() function: + Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a + timeout. + + Note that a function with a similar name, sys_mbox_fetch(), is + implemented by lwIP. + +- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) + + This is similar to sys_arch_mbox_fetch, however if a message is not + present in the mailbox, it immediately returns with the code + SYS_MBOX_EMPTY. On success 0 is returned. + + To allow for efficient implementations, this can be defined as a + function-like macro in sys_arch.h instead of a normal function. For + example, a naive implementation could be: + #define sys_arch_mbox_tryfetch(mbox,msg) \ + sys_arch_mbox_fetch(mbox,msg,1) + although this would introduce unnecessary delays. + +- int sys_mbox_valid(sys_mbox_t *mbox) + + Returns 1 if the mailbox is valid, 0 if it is not valid. + When using pointers, a simple way is to check the pointer for != NULL. + When directly using OS structures, implementing this may be more complex. + This may also be a define, in which case the function is not prototyped. + +- void sys_mbox_set_invalid(sys_mbox_t *mbox) + + Invalidate a mailbox so that sys_mbox_valid() returns 0. + ATTENTION: This does NOT mean that the mailbox shall be deallocated: + sys_mbox_free() is always called before calling this function! + This may also be a define, in which case the function is not prototyped. + +If threads are supported by the underlying operating system and if +such functionality is needed in lwIP, the following function will have +to be implemented as well: + +- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) + + Starts a new thread named "name" with priority "prio" that will begin its + execution in the function "thread()". The "arg" argument will be passed as an + argument to the thread() function. The stack size to used for this thread is + the "stacksize" parameter. The id of the new thread is returned. Both the id + and the priority are system dependent. + +When lwIP is used from more than one context (e.g. from multiple threads OR from +main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled! + +- sys_prot_t sys_arch_protect(void) + + This optional function does a "fast" critical region protection and returns + the previous protection level. This function is only called during very short + critical regions. An embedded system which supports ISR-based drivers might + want to implement this function by disabling interrupts. Task-based systems + might want to implement this by using a mutex or disabling tasking. This + function should support recursive calls from the same task or interrupt. In + other words, sys_arch_protect() could be called while already protected. In + that case the return value indicates that it is already protected. + + sys_arch_protect() is only required if your port is supporting an operating + system. + +- void sys_arch_unprotect(sys_prot_t pval) + + This optional function does a "fast" set of critical region protection to the + value specified by pval. See the documentation for sys_arch_protect() for + more information. This function is only required if your port is supporting + an operating system. + +For some configurations, you also need: + +- u32_t sys_now(void) + + This optional function returns the current time in milliseconds (don't care + for wraparound, this is only used for time diffs). + Not implementing this function means you cannot use some modules (e.g. TCP + timestamps, internal timeouts for NO_SYS==1). + + +Note: + +Be careful with using mem_malloc() in sys_arch. When malloc() refers to +mem_malloc() you can run into a circular function call problem. In mem.c +mem_init() tries to allcate a semaphore using mem_malloc, which of course +can't be performed when sys_arch uses mem_malloc. + +------------------------------------------------------------------------------- +Additional files required for the "OS support" emulation layer: +------------------------------------------------------------------------------- + +cc.h - Architecture environment, some compiler specific, some + environment specific (probably should move env stuff + to sys_arch.h.) + + Typedefs for the types used by lwip - + u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t + + Compiler hints for packing lwip's structures - + PACK_STRUCT_FIELD(x) + PACK_STRUCT_STRUCT + PACK_STRUCT_BEGIN + PACK_STRUCT_END + + Platform specific diagnostic output - + LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. + LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution. + Portability defines for printf formatters: + U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F + + "lightweight" synchronization mechanisms - + SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. + SYS_ARCH_PROTECT(x) - enter protection mode. + SYS_ARCH_UNPROTECT(x) - leave protection mode. + + If the compiler does not provide memset() this file must include a + definition of it, or include a file which defines it. + + This file must either include a system-local which defines + the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO + to make lwip/arch.h define the codes which are used throughout. + + +perf.h - Architecture specific performance measurement. + Measurement calls made throughout lwip, these can be defined to nothing. + PERF_START - start measuring something. + PERF_STOP(x) - stop measuring something, and record the result. + +sys_arch.h - Tied to sys_arch.c + + Arch dependent types for the following objects: + sys_sem_t, sys_mbox_t, sys_thread_t, + And, optionally: + sys_prot_t + + Defines to set vars of sys_mbox_t and sys_sem_t to NULL. + SYS_MBOX_NULL NULL + SYS_SEM_NULL NULL diff --git a/Sming/third-party/lwip2/lwip2-src/src/FILES b/Sming/third-party/lwip2/lwip2-src/src/FILES new file mode 100644 index 0000000000..0be0741d08 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/FILES @@ -0,0 +1,15 @@ +api/ - The code for the high-level wrapper API. Not needed if + you use the lowel-level call-back/raw API. + +apps/ - Higher layer applications that are specifically programmed + with the lwIP low-level raw API. + +core/ - The core of the TPC/IP stack; protocol implementations, + memory and buffer management, and the low-level raw API. + +include/ - lwIP include files. + +netif/ - Generic network interface device drivers are kept here. + +For more information on the various subdirectories, check the FILES +file in each directory. diff --git a/Sming/third-party/lwip2/lwip2-src/src/Filelists.mk b/Sming/third-party/lwip2/lwip2-src/src/Filelists.mk new file mode 100644 index 0000000000..7d30bb8f53 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/Filelists.mk @@ -0,0 +1,181 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +# COREFILES, CORE4FILES: The minimum set of files needed for lwIP. +COREFILES=$(LWIPDIR)/core/init.c \ + $(LWIPDIR)/core/def.c \ + $(LWIPDIR)/core/dns.c \ + $(LWIPDIR)/core/inet_chksum.c \ + $(LWIPDIR)/core/ip.c \ + $(LWIPDIR)/core/mem.c \ + $(LWIPDIR)/core/memp.c \ + $(LWIPDIR)/core/netif.c \ + $(LWIPDIR)/core/pbuf.c \ + $(LWIPDIR)/core/raw.c \ + $(LWIPDIR)/core/stats.c \ + $(LWIPDIR)/core/sys.c \ + $(LWIPDIR)/core/tcp.c \ + $(LWIPDIR)/core/tcp_in.c \ + $(LWIPDIR)/core/tcp_out.c \ + $(LWIPDIR)/core/timeouts.c \ + $(LWIPDIR)/core/udp.c + +CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \ + $(LWIPDIR)/core/ipv4/dhcp.c \ + $(LWIPDIR)/core/ipv4/etharp.c \ + $(LWIPDIR)/core/ipv4/icmp.c \ + $(LWIPDIR)/core/ipv4/igmp.c \ + $(LWIPDIR)/core/ipv4/ip4_frag.c \ + $(LWIPDIR)/core/ipv4/ip4.c \ + $(LWIPDIR)/core/ipv4/ip4_addr.c + +CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \ + $(LWIPDIR)/core/ipv6/ethip6.c \ + $(LWIPDIR)/core/ipv6/icmp6.c \ + $(LWIPDIR)/core/ipv6/inet6.c \ + $(LWIPDIR)/core/ipv6/ip6.c \ + $(LWIPDIR)/core/ipv6/ip6_addr.c \ + $(LWIPDIR)/core/ipv6/ip6_frag.c \ + $(LWIPDIR)/core/ipv6/mld6.c \ + $(LWIPDIR)/core/ipv6/nd6.c + +# APIFILES: The files which implement the sequential and socket APIs. +APIFILES=$(LWIPDIR)/api/api_lib.c \ + $(LWIPDIR)/api/api_msg.c \ + $(LWIPDIR)/api/err.c \ + $(LWIPDIR)/api/netbuf.c \ + $(LWIPDIR)/api/netdb.c \ + $(LWIPDIR)/api/netifapi.c \ + $(LWIPDIR)/api/sockets.c \ + $(LWIPDIR)/api/tcpip.c + +# NETIFFILES: Files implementing various generic network interface functions +NETIFFILES=$(LWIPDIR)/netif/ethernet.c \ + $(LWIPDIR)/netif/slipif.c + +# SIXLOWPAN: 6LoWPAN +SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \ + +# PPPFILES: PPP +PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \ + $(LWIPDIR)/netif/ppp/ccp.c \ + $(LWIPDIR)/netif/ppp/chap-md5.c \ + $(LWIPDIR)/netif/ppp/chap_ms.c \ + $(LWIPDIR)/netif/ppp/chap-new.c \ + $(LWIPDIR)/netif/ppp/demand.c \ + $(LWIPDIR)/netif/ppp/eap.c \ + $(LWIPDIR)/netif/ppp/ecp.c \ + $(LWIPDIR)/netif/ppp/eui64.c \ + $(LWIPDIR)/netif/ppp/fsm.c \ + $(LWIPDIR)/netif/ppp/ipcp.c \ + $(LWIPDIR)/netif/ppp/ipv6cp.c \ + $(LWIPDIR)/netif/ppp/lcp.c \ + $(LWIPDIR)/netif/ppp/magic.c \ + $(LWIPDIR)/netif/ppp/mppe.c \ + $(LWIPDIR)/netif/ppp/multilink.c \ + $(LWIPDIR)/netif/ppp/ppp.c \ + $(LWIPDIR)/netif/ppp/pppapi.c \ + $(LWIPDIR)/netif/ppp/pppcrypt.c \ + $(LWIPDIR)/netif/ppp/pppoe.c \ + $(LWIPDIR)/netif/ppp/pppol2tp.c \ + $(LWIPDIR)/netif/ppp/pppos.c \ + $(LWIPDIR)/netif/ppp/upap.c \ + $(LWIPDIR)/netif/ppp/utils.c \ + $(LWIPDIR)/netif/ppp/vj.c \ + $(LWIPDIR)/netif/ppp/polarssl/arc4.c \ + $(LWIPDIR)/netif/ppp/polarssl/des.c \ + $(LWIPDIR)/netif/ppp/polarssl/md4.c \ + $(LWIPDIR)/netif/ppp/polarssl/md5.c \ + $(LWIPDIR)/netif/ppp/polarssl/sha1.c + +# LWIPNOAPPSFILES: All LWIP files without apps +LWIPNOAPPSFILES=$(COREFILES) \ + $(CORE4FILES) \ + $(CORE6FILES) \ + $(APIFILES) \ + $(NETIFFILES) \ + $(PPPFILES) \ + $(SIXLOWPAN) + +# SNMPFILES: SNMPv2c agent +SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \ + $(LWIPDIR)/apps/snmp/snmp_core.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_snmp.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_system.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \ + $(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \ + $(LWIPDIR)/apps/snmp/snmp_msg.c \ + $(LWIPDIR)/apps/snmp/snmpv3.c \ + $(LWIPDIR)/apps/snmp/snmp_netconn.c \ + $(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \ + $(LWIPDIR)/apps/snmp/snmp_raw.c \ + $(LWIPDIR)/apps/snmp/snmp_scalar.c \ + $(LWIPDIR)/apps/snmp/snmp_table.c \ + $(LWIPDIR)/apps/snmp/snmp_threadsync.c \ + $(LWIPDIR)/apps/snmp/snmp_traps.c \ + $(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \ + $(LWIPDIR)/apps/snmp/snmpv3_dummy.c + +# HTTPDFILES: HTTP server +HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \ + $(LWIPDIR)/apps/httpd/httpd.c + +# LWIPERFFILES: IPERF server +LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c + +# SNTPFILES: SNTP client +SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c + +# MDNSFILES: MDNS responder +MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c + +# NETBIOSNSFILES: NetBIOS name server +NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c + +# TFTPFILES: TFTP server files +TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c + +# MQTTFILES: MQTT client files +MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c + +# LWIPAPPFILES: All LWIP APPs +LWIPAPPFILES=$(SNMPFILES) \ + $(HTTPDFILES) \ + $(LWIPERFFILES) \ + $(SNTPFILES) \ + $(MDNSFILES) \ + $(NETBIOSNSFILES) \ + $(TFTPFILES) \ + $(MQTTFILES) diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/api_lib.c b/Sming/third-party/lwip2/lwip2-src/src/api/api_lib.c new file mode 100644 index 0000000000..3c1d6a6c27 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/api_lib.c @@ -0,0 +1,1010 @@ +/** + * @file + * Sequential API External module + * + * @defgroup netconn Netconn API + * @ingroup sequential_api + * Thread-safe, to be called from non-TCPIP threads only. + * TX/RX handling based on @ref netbuf (containing @ref pbuf) + * to avoid copying data around. + * + * @defgroup netconn_common Common functions + * @ingroup netconn + * For use with TCP and UDP + * + * @defgroup netconn_tcp TCP only + * @ingroup netconn + * TCP only functions + * + * @defgroup netconn_udp UDP only + * @ingroup netconn + * UDP only functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +/* This is the part of the API that is linked with + the application */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api.h" +#include "lwip/memp.h" + +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/api_msg.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/priv/tcpip_priv.h" + +#include + +#define API_MSG_VAR_REF(name) API_VAR_REF(name) +#define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) +#define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM) +#define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL) +#define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) + +static err_t netconn_close_shutdown(struct netconn *conn, u8_t how); + +/** + * Call the lower part of a netconn_* function + * This function is then running in the thread context + * of tcpip_thread and has exclusive access to lwIP core code. + * + * @param fn function to call + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK if the function was called, another err_t if not + */ +static err_t +netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg) +{ + err_t err; + +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->err = ERR_VAL; +#endif /* LWIP_DEBUG */ + +#if LWIP_NETCONN_SEM_PER_THREAD + apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg)); + if (err == ERR_OK) { + return apimsg->err; + } + return err; +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is also created. + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn* +netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) +{ + struct netconn *conn; + API_MSG_VAR_DECLARE(msg); + API_MSG_VAR_ALLOC_RETURN_NULL(msg); + + conn = netconn_alloc(t, callback); + if (conn != NULL) { + err_t err; + + API_MSG_VAR_REF(msg).msg.n.proto = proto; + API_MSG_VAR_REF(msg).conn = conn; + err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg)); + if (err != ERR_OK) { + LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); + LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ +#if !LWIP_NETCONN_SEM_PER_THREAD + LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); + sys_sem_free(&conn->op_completed); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ + sys_mbox_free(&conn->recvmbox); + memp_free(MEMP_NETCONN, conn); + API_MSG_VAR_FREE(msg); + return NULL; + } + } + API_MSG_VAR_FREE(msg); + return conn; +} + +/** + * @ingroup netconn_common + * Close a netconn 'connection' and free its resources. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_delete(struct netconn *conn) +{ + err_t err; + API_MSG_VAR_DECLARE(msg); + + /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ + if (conn == NULL) { + return ERR_OK; + } + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ +#if LWIP_TCP + API_MSG_VAR_REF(msg).msg.sd.polls_left = + ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; +#endif /* LWIP_TCP */ +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + if (err != ERR_OK) { + return err; + } + + netconn_free(conn); + + return ERR_OK; +} + +/** + * Get the local or remote IP address and port of a netconn. + * For RAW netconns, this returns the protocol instead of a port! + * + * @param conn the netconn to query + * @param addr a pointer to which to save the IP address + * @param port a pointer to which to save the port (or protocol for RAW) + * @param local 1 to get the local IP address, 0 to get the remote one + * @return ERR_CONN for invalid connections + * ERR_OK if the information was retrieved + */ +err_t +netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.ad.local = local; +#if LWIP_MPU_COMPATIBLE + err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg)); + *addr = msg->msg.ad.ipaddr; + *port = msg->msg.ad.port; +#else /* LWIP_MPU_COMPATIBLE */ + msg.msg.ad.ipaddr = addr; + msg.msg.ad.port = port; + err = netconn_apimsg(lwip_netconn_do_getaddr, &msg); +#endif /* LWIP_MPU_COMPATIBLE */ + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_common + * Bind a netconn to a specific local IP address and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param addr the local IP address to bind the netconn to + * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses) + * @param port the local port to bind the netconn to (not used for RAW) + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (addr == NULL) { + addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV4 && LWIP_IPV6 + /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY, + * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind + */ + if ((netconn_get_ipv6only(conn) == 0) && + ip_addr_cmp(addr, IP6_ADDR_ANY)) { + addr = IP_ANY_TYPE; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_common + * Connect a netconn to a specific remote IP address and port. + * + * @param conn the netconn to connect + * @param addr the remote IP address to connect to + * @param port the remote port to connect to (no used for RAW) + * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise + */ +err_t +netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (addr == NULL) { + addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr); + API_MSG_VAR_REF(msg).msg.bc.port = port; + err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_udp + * Disconnect a netconn from its current peer (only valid for UDP netconns). + * + * @param conn the netconn to disconnect + * @return See @ref err_t + */ +err_t +netconn_disconnect(struct netconn *conn) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Set a TCP netconn into listen mode + * + * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 + * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns + * don't return any error (yet?)) + */ +err_t +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) +{ +#if LWIP_TCP + API_MSG_VAR_DECLARE(msg); + err_t err; + + /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ + LWIP_UNUSED_ARG(backlog); + + LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_REF(msg).msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ + err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(backlog); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * @ingroup netconn_tcp + * Accept a new connection on a TCP listening netconn. + * + * @param conn the TCP listen netconn + * @param new_conn pointer where the new connection is stored + * @return ERR_OK if a new connection has been received or an error + * code otherwise + */ +err_t +netconn_accept(struct netconn *conn, struct netconn **new_conn) +{ +#if LWIP_TCP + void *accept_ptr; + struct netconn *newconn; +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_DECLARE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + + LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); + *new_conn = NULL; + LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); + + if (ERR_IS_FATAL(conn->last_err)) { + /* don't recv on fatal errors: this might block the application task + waiting on acceptmbox forever! */ + return conn->last_err; + } + if (!sys_mbox_valid(&conn->acceptmbox)) { + return ERR_CLSD; + } + +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_ALLOC(msg); +#endif /* TCP_LISTEN_BACKLOG */ + +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + newconn = (struct netconn *)accept_ptr; + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + + if (accept_ptr == &netconn_aborted) { + /* a connection has been aborted: out of pcbs or out of netconns during accept */ + /* @todo: set netconn error, but this would be fatal and thus block further accepts */ +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + return ERR_ABRT; + } + if (newconn == NULL) { + /* connection has been aborted */ + /* in this special case, we set the netconn error from application thread, as + on a ready-to-accept listening netconn, there should not be anything running + in tcpip_thread */ + NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + return ERR_CLSD; + } +#if TCP_LISTEN_BACKLOG + /* Let the stack know that we have accepted the connection. */ + API_MSG_VAR_REF(msg).conn = newconn; + /* don't care for the return value of lwip_netconn_do_recv */ + netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + + *new_conn = newconn; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(new_conn); + return ERR_ARG; +#endif /* LWIP_TCP */ +} + +/** + * @ingroup netconn_common + * Receive data: actual implementation that doesn't care whether pbuf or netbuf + * is received + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf/netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +static err_t +netconn_recv_data(struct netconn *conn, void **new_buf) +{ + void *buf = NULL; + u16_t len; +#if LWIP_TCP + API_MSG_VAR_DECLARE(msg); +#if LWIP_MPU_COMPATIBLE + msg = NULL; +#endif +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + if (!sys_mbox_valid(&conn->recvmbox)) { + /* This happens when calling this function after receiving FIN */ + return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD; + } + } +#endif /* LWIP_TCP */ + LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); + + if (ERR_IS_FATAL(conn->last_err)) { + /* don't recv on fatal errors: this might block the application task + waiting on recvmbox forever! */ + /* @todo: this does not allow us to fetch data that has been put into recvmbox + before the fatal error occurred - is that a problem? */ + return conn->last_err; + } +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + API_MSG_VAR_ALLOC(msg); + } +#endif /* LWIP_TCP */ + +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + API_MSG_VAR_FREE(msg); + } +#endif /* LWIP_TCP */ + return ERR_TIMEOUT; + } +#else + sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + /* Let the stack know that we have taken the data. */ + /* @todo: Speedup: Don't block and wait for the answer here + (to prevent multiple thread-switches). */ + API_MSG_VAR_REF(msg).conn = conn; + if (buf != NULL) { + API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len; + } else { + API_MSG_VAR_REF(msg).msg.r.len = 1; + } + + /* don't care for the return value of lwip_netconn_do_recv */ + netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + /* If we are closed, we indicate that we no longer wish to use the socket */ + if (buf == NULL) { + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + if (conn->pcb.ip == NULL) { + /* race condition: RST during recv */ + return conn->last_err == ERR_OK ? ERR_RST : conn->last_err; + } + /* RX side is closed, so deallocate the recvmbox */ + netconn_close_shutdown(conn, NETCONN_SHUT_RD); + /* Don' store ERR_CLSD as conn->err since we are only half-closed */ + return ERR_CLSD; + } + len = ((struct pbuf *)buf)->tot_len; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ +#if (LWIP_UDP || LWIP_RAW) + { + LWIP_ASSERT("buf != NULL", buf != NULL); + len = netbuf_len((struct netbuf*)buf); + } +#endif /* (LWIP_UDP || LWIP_RAW) */ + +#if LWIP_SO_RCVBUF + SYS_ARCH_DEC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); + + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +} + +/** + * @ingroup netconn_tcp + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) +{ + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf); +} + +/** + * @ingroup netconn_common + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +err_t +netconn_recv(struct netconn *conn, struct netbuf **new_buf) +{ +#if LWIP_TCP + struct netbuf *buf = NULL; + err_t err; +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + struct pbuf *p = NULL; + /* This is not a listening netconn, since recvmbox is set */ + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + return ERR_MEM; + } + + err = netconn_recv_data(conn, (void **)&p); + if (err != ERR_OK) { + memp_free(MEMP_NETBUF, buf); + return err; + } + LWIP_ASSERT("p != NULL", p != NULL); + + buf->p = p; + buf->ptr = p; + buf->port = 0; + ip_addr_set_zero(&buf->addr); + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ + { +#if (LWIP_UDP || LWIP_RAW) + return netconn_recv_data(conn, (void **)new_buf); +#endif /* (LWIP_UDP || LWIP_RAW) */ + } +} + +/** + * @ingroup netconn_udp + * Send data (in form of a netbuf) to a specific remote IP address and port. + * Only to be used for UDP and RAW netconns (not TCP). + * + * @param conn the netconn over which to send data + * @param buf a netbuf containing the data to send + * @param addr the remote IP address to which to send the data + * @param port the remote port to which to send the data + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port) +{ + if (buf != NULL) { + ip_addr_set(&buf->addr, addr); + buf->port = port; + return netconn_send(conn, buf); + } + return ERR_VAL; +} + +/** + * @ingroup netconn_udp + * Send data over a UDP or RAW netconn (that is already connected). + * + * @param conn the UDP or RAW netconn over which to send data + * @param buf a netbuf containing the data to send + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_send(struct netconn *conn, struct netbuf *buf) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); + + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.b = buf; + err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Send data over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param dataptr pointer to the application buffer that contains the data to send + * @param size size of the application data to send + * @param apiflags combination of following flags : + * - NETCONN_COPY: data will be copied into memory belonging to the stack + * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_DONTBLOCK: only write the data if all data can be written at once + * @param bytes_written pointer to a location that receives the number of written bytes + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + u8_t dontblock; + + LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); + if (size == 0) { + return ERR_OK; + } + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout != 0) { + dontblock = 1; + } +#endif /* LWIP_SO_SNDTIMEO */ + if (dontblock && !bytes_written) { + /* This implies netconn_write() cannot be used for non-blocking send, since + it has no way to return the number of bytes written. */ + return ERR_VAL; + } + + API_MSG_VAR_ALLOC(msg); + /* non-blocking write sends as much */ + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr; + API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags; + API_MSG_VAR_REF(msg).msg.w.len = size; +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout != 0) { + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.w.time_started = sys_now(); + } else { + API_MSG_VAR_REF(msg).msg.w.time_started = 0; + } +#endif /* LWIP_SO_SNDTIMEO */ + + /* For locking the core: this _can_ be delayed on low memory/low send buffer, + but if it is, this is done inside api_msg.c:do_write(), so we can use the + non-blocking version here. */ + err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg)); + if ((err == ERR_OK) && (bytes_written != NULL)) { + if (dontblock) { + /* nonblocking write: maybe the data has been sent partly */ + *bytes_written = API_MSG_VAR_REF(msg).msg.w.len; + } else { + /* blocking call succeeded: all data has been sent if it */ + *bytes_written = size; + } + } + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Close or shutdown a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close or shutdown + * @param how fully close or only shutdown one side? + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +static err_t +netconn_close_shutdown(struct netconn *conn, u8_t how) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + LWIP_UNUSED_ARG(how); + + LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + API_MSG_VAR_REF(msg).conn = conn; +#if LWIP_TCP + /* shutting down both ends is the same as closing */ + API_MSG_VAR_REF(msg).msg.sd.shut = how; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now(); +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + API_MSG_VAR_REF(msg).msg.sd.polls_left = + ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ +#endif /* LWIP_TCP */ + err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} + +/** + * @ingroup netconn_tcp + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ + /* shutting down both ends is the same as closing */ + return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); +} + +/** + * @ingroup netconn_tcp + * Shut down one or both sides of a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to shut down + * @param shut_rx shut down the RX side (no more read possible after this) + * @param shut_tx shut down the TX side (no more write possible after this) + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) +{ + return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); +} + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * @ingroup netconn_udp + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param netif_addr the IP address of the network interface on which to send + * the igmp message + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group(struct netconn *conn, + const ip_addr_t *multiaddr, + const ip_addr_t *netif_addr, + enum netconn_igmp join_or_leave) +{ + API_MSG_VAR_DECLARE(msg); + err_t err; + + LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); + + API_MSG_VAR_ALLOC(msg); + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */ + if (multiaddr == NULL) { + multiaddr = IP4_ADDR_ANY; + } + if (netif_addr == NULL) { + netif_addr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + API_MSG_VAR_REF(msg).conn = conn; + API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr); + API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr); + API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave; + err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg)); + API_MSG_VAR_FREE(msg); + + return err; +} +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/** + * @ingroup netconn_common + * Execute a DNS query, only one IP address is returned + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated ip_addr_t where to store the resolved IP address + * @param dns_addrtype IP address type (IPv4 / IPv6) + * @return ERR_OK: resolving succeeded + * ERR_MEM: memory error, try again later + * ERR_ARG: dns client not initialized or invalid hostname + * ERR_VAL: dns server response was invalid + */ +#if LWIP_IPV4 && LWIP_IPV6 +err_t +netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) +#else +err_t +netconn_gethostbyname(const char *name, ip_addr_t *addr) +#endif +{ + API_VAR_DECLARE(struct dns_api_msg, msg); +#if !LWIP_MPU_COMPATIBLE + sys_sem_t sem; +#endif /* LWIP_MPU_COMPATIBLE */ + err_t err; + err_t cberr; + + LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); +#if LWIP_MPU_COMPATIBLE + if (strlen(name) >= DNS_MAX_NAME_LENGTH) { + return ERR_ARG; + } +#endif + + API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM); +#if LWIP_MPU_COMPATIBLE + strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); + API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; +#else /* LWIP_MPU_COMPATIBLE */ + msg.err = &err; + msg.sem = &sem; + API_VAR_REF(msg).addr = API_VAR_REF(addr); + API_VAR_REF(msg).name = name; +#endif /* LWIP_MPU_COMPATIBLE */ +#if LWIP_IPV4 && LWIP_IPV6 + API_VAR_REF(msg).dns_addrtype = dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_NETCONN_SEM_PER_THREAD + API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD*/ + err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); + if (err != ERR_OK) { + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return err; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); + if (cberr != ERR_OK) { +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return cberr; + } + sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem)); +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ + +#if LWIP_MPU_COMPATIBLE + *addr = msg->addr; + err = msg->err; +#endif /* LWIP_MPU_COMPATIBLE */ + + API_VAR_FREE(MEMP_DNS_API_MSG, msg); + return err; +} +#endif /* LWIP_DNS*/ + +#if LWIP_NETCONN_SEM_PER_THREAD +void +netconn_thread_init(void) +{ + sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); + if ((sem == NULL) || !sys_sem_valid(sem)) { + /* call alloc only once */ + LWIP_NETCONN_THREAD_SEM_ALLOC(); + LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET())); + } +} + +void +netconn_thread_cleanup(void) +{ + sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); + if ((sem != NULL) && sys_sem_valid(sem)) { + /* call free only once */ + LWIP_NETCONN_THREAD_SEM_FREE(); + } +} +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/api_msg.c b/Sming/third-party/lwip2/lwip2-src/src/api/api_msg.c new file mode 100644 index 0000000000..dd99c1e01b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/api_msg.c @@ -0,0 +1,1947 @@ +/** + * @file + * Sequential API Internal module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/api_msg.h" + +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" + +#include "lwip/memp.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/mld6.h" +#include "lwip/priv/tcpip_priv.h" + +#include + +/* netconns are polled once per second (e.g. continue write on memory error) */ +#define NETCONN_TCP_POLL_INTERVAL 2 + +#define SET_NONBLOCKING_CONNECT(conn, val) do { if (val) { \ + (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) +#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) + +/* forward declarations */ +#if LWIP_TCP +#if LWIP_TCPIP_CORE_LOCKING +#define WRITE_DELAYED , 1 +#define WRITE_DELAYED_PARAM , u8_t delayed +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define WRITE_DELAYED +#define WRITE_DELAYED_PARAM +#endif /* LWIP_TCPIP_CORE_LOCKING */ +static err_t lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM); +static err_t lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM); +#endif + +#if LWIP_TCPIP_CORE_LOCKING +#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_TCP +u8_t netconn_aborted; +#endif /* LWIP_TCP */ + +#if LWIP_RAW +/** + * Receive callback function for RAW netconns. + * Doesn't 'eat' the packet, only copies it and sends it to + * conn->recvmbox + * + * @see raw.h (struct raw_pcb.recv) for parameters and return value + */ +static u8_t +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr) +{ + struct pbuf *q; + struct netbuf *buf; + struct netconn *conn; + + LWIP_UNUSED_ARG(addr); + conn = (struct netconn *)arg; + + if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { +#if LWIP_SO_RCVBUF + int recv_avail; + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { + return 0; + } +#endif /* LWIP_SO_RCVBUF */ + /* copy the whole packet into new pbufs */ + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + if (pbuf_copy(q, p) != ERR_OK) { + pbuf_free(q); + q = NULL; + } + } + + if (q != NULL) { + u16_t len; + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(q); + return 0; + } + + buf->p = q; + buf->ptr = q; + ip_addr_copy(buf->addr, *ip_current_src_addr()); + buf->port = pcb->protocol; + + len = q->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return 0; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + } + } + + return 0; /* do not eat the packet */ +} +#endif /* LWIP_RAW*/ + +#if LWIP_UDP +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ +static void +recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port) +{ + struct netbuf *buf; + struct netconn *conn; + u16_t len; +#if LWIP_SO_RCVBUF + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ + LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_udp must have an argument", arg != NULL); + conn = (struct netconn *)arg; + LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); + +#if LWIP_SO_RCVBUF + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || + ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { +#else /* LWIP_SO_RCVBUF */ + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { +#endif /* LWIP_SO_RCVBUF */ + pbuf_free(p); + return; + } + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + pbuf_free(p); + return; + } else { + buf->p = p; + buf->ptr = p; + ip_addr_set(&buf->addr, addr); + buf->port = port; +#if LWIP_NETBUF_RECVINFO + { + /* get the UDP header - always in the first pbuf, ensured by udp_input */ + const struct udp_hdr* udphdr = (const struct udp_hdr*)ip_next_header_ptr(); +#if LWIP_CHECKSUM_ON_COPY + buf->flags = NETBUF_FLAG_DESTADDR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + ip_addr_set(&buf->toaddr, ip_current_dest_addr()); + buf->toport_chksum = udphdr->dest; + } +#endif /* LWIP_NETBUF_RECVINFO */ + } + + len = p->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { + netbuf_delete(buf); + return; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } +} +#endif /* LWIP_UDP */ + +#if LWIP_TCP +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct netconn *conn; + u16_t len; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); + LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); + conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); + + if (!sys_mbox_valid(&conn->recvmbox)) { + /* recvmbox already deleted */ + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } + return ERR_OK; + } + /* Unlike for UDP or RAW pcbs, don't check for available space + using recv_avail since that could break the connection + (data is already ACKed) */ + + /* don't overwrite fatal errors! */ + if (err != ERR_OK) { + NETCONN_SET_SAFE_ERR(conn, err); + } + + if (p != NULL) { + len = p->tot_len; + } else { + len = 0; + } + + if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { + /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ + return ERR_MEM; + } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); + } + + return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn->state == NETCONN_WRITE) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } else if (conn->state == NETCONN_CLOSE) { +#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER + if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { + conn->current_msg->msg.sd.polls_left--; + } +#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */ + lwip_netconn_do_close_internal(conn WRITE_DELAYED); + } + /* @todo: implement connect timeout here? */ + + /* Did a nonblocking write fail before? Then check available write-space. */ + if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } + + return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +static err_t +sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ + struct netconn *conn = (struct netconn *)arg; + + LWIP_UNUSED_ARG(pcb); + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + if (conn) { + if (conn->state == NETCONN_WRITE) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } else if (conn->state == NETCONN_CLOSE) { + lwip_netconn_do_close_internal(conn WRITE_DELAYED); + } + + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); + } + } + + return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +static void +err_tcp(void *arg, err_t err) +{ + struct netconn *conn; + enum netconn_state old_state; + + conn = (struct netconn *)arg; + LWIP_ASSERT("conn != NULL", (conn != NULL)); + + conn->pcb.tcp = NULL; + + /* reset conn->state now before waking up other threads */ + old_state = conn->state; + conn->state = NETCONN_NONE; + + if (old_state == NETCONN_CLOSE) { + /* RST during close: let close return success & dealloc the netconn */ + err = ERR_OK; + NETCONN_SET_SAFE_ERR(conn, ERR_OK); + } else { + /* no check since this is always fatal! */ + SYS_ARCH_SET(conn->last_err, err); + } + + /* @todo: the type of NETCONN_EVT created should depend on 'old_state' */ + + /* Notify the user layer about a connection error. Used to signal select. */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + /* Try to release selects pending on 'read' or 'write', too. + They will get an error if they actually try to read or write. */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + /* pass NULL-message to recvmbox to wake up pending recv */ + if (sys_mbox_valid(&conn->recvmbox)) { + /* use trypost to prevent deadlock */ + sys_mbox_trypost(&conn->recvmbox, NULL); + } + /* pass NULL-message to acceptmbox to wake up pending accept */ + if (sys_mbox_valid(&conn->acceptmbox)) { + /* use trypost to preven deadlock */ + sys_mbox_trypost(&conn->acceptmbox, NULL); + } + + if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || + (old_state == NETCONN_CONNECT)) { + /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary + since the pcb has already been deleted! */ + int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + + if (!was_nonblocking_connect) { + sys_sem_t* op_completed_sem; + /* set error return code */ + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + conn->current_msg->err = err; + op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem)); + conn->current_msg = NULL; + /* wake up the waiting task */ + NETCONN_SET_SAFE_ERR(conn, err); + sys_sem_signal(op_completed_sem); + } + } else { + LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); + } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +static void +setup_tcp(struct netconn *conn) +{ + struct tcp_pcb *pcb; + + pcb = conn->pcb.tcp; + tcp_arg(pcb, conn); + tcp_recv(pcb, recv_tcp); + tcp_sent(pcb, sent_tcp); + tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL); + tcp_err(pcb, err_tcp); +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +static err_t +accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + struct netconn *newconn; + struct netconn *conn = (struct netconn *)arg; + + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); + + if (conn == NULL) { + return ERR_VAL; + } + if (!sys_mbox_valid(&conn->acceptmbox)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); + return ERR_VAL; + } + + if (newpcb == NULL) { + /* out-of-pcbs during connect: pass on this error to the application */ + if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + return ERR_VAL; + } + + /* We have to set the callback here even though + * the new socket is unknown. newconn->socket is marked as -1. */ + newconn = netconn_alloc(conn->type, conn->callback); + if (newconn == NULL) { + /* outof netconns: pass on this error to the application */ + if (sys_mbox_trypost(&conn->acceptmbox, &netconn_aborted) == ERR_OK) { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + return ERR_MEM; + } + newconn->pcb.tcp = newpcb; + setup_tcp(newconn); + /* no protection: when creating the pcb, the netconn is not yet known + to the application thread */ + newconn->last_err = err; + + /* handle backlog counter */ + tcp_backlog_delayed(newpcb); + + if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { + /* When returning != ERR_OK, the pcb is aborted in tcp_process(), + so do nothing here! */ + /* remove all references to this netconn from the pcb */ + struct tcp_pcb* pcb = newconn->pcb.tcp; + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_poll(pcb, NULL, 0); + tcp_err(pcb, NULL); + /* remove reference from to the pcb from this netconn */ + newconn->pcb.tcp = NULL; + /* no need to drain since we know the recvmbox is empty. */ + sys_mbox_free(&newconn->recvmbox); + sys_mbox_set_invalid(&newconn->recvmbox); + netconn_free(newconn); + return ERR_MEM; + } else { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from lwip_netconn_do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + */ +static void +pcb_new(struct api_msg *msg) +{ + enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; + + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + +#if LWIP_IPV6 && LWIP_IPV4 + /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */ + if(NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) { + iptype = IPADDR_TYPE_ANY; + } +#endif + + /* Allocate a PCB for this connection */ + switch(NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto); + if (msg->conn->pcb.raw != NULL) { +#if LWIP_IPV6 + /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */ + if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) { + msg->conn->pcb.raw->chksum_reqd = 1; + msg->conn->pcb.raw->chksum_offset = 2; + } +#endif /* LWIP_IPV6 */ + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new_ip_type(iptype); + if (msg->conn->pcb.udp != NULL) { +#if LWIP_UDPLITE + if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } +#endif /* LWIP_UDPLITE */ + if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new_ip_type(iptype); + if (msg->conn->pcb.tcp != NULL) { + setup_tcp(msg->conn); + } + break; +#endif /* LWIP_TCP */ + default: + /* Unsupported netconn type, e.g. protocol disabled */ + msg->err = ERR_VAL; + return; + } + if (msg->conn->pcb.ip == NULL) { + msg->err = ERR_MEM; + } +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param m the api_msg_msg describing the connection type + */ +void +lwip_netconn_do_newconn(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp == NULL) { + pcb_new(msg); + } + /* Else? This "new" connection already has a PCB allocated. */ + /* Is this an error condition? Should it be deleted? */ + /* We currently just are happy and return. */ + + TCPIP_APIMSG_ACK(msg); +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is NOT created! + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + * NULL on memory error + */ +struct netconn* +netconn_alloc(enum netconn_type t, netconn_callback callback) +{ + struct netconn *conn; + int size; + + conn = (struct netconn *)memp_malloc(MEMP_NETCONN); + if (conn == NULL) { + return NULL; + } + + conn->last_err = ERR_OK; + conn->type = t; + conn->pcb.tcp = NULL; + + /* If all sizes are the same, every compiler should optimize this switch to nothing */ + switch(NETCONNTYPE_GROUP(t)) { +#if LWIP_RAW + case NETCONN_RAW: + size = DEFAULT_RAW_RECVMBOX_SIZE; + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + size = DEFAULT_UDP_RECVMBOX_SIZE; + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + size = DEFAULT_TCP_RECVMBOX_SIZE; + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); + goto free_and_return; + } + + if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { + goto free_and_return; + } +#if !LWIP_NETCONN_SEM_PER_THREAD + if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { + sys_mbox_free(&conn->recvmbox); + goto free_and_return; + } +#endif + +#if LWIP_TCP + sys_mbox_set_invalid(&conn->acceptmbox); +#endif + conn->state = NETCONN_NONE; +#if LWIP_SOCKET + /* initialize socket to -1 since 0 is a valid socket */ + conn->socket = -1; +#endif /* LWIP_SOCKET */ + conn->callback = callback; +#if LWIP_TCP + conn->current_msg = NULL; + conn->write_offset = 0; +#endif /* LWIP_TCP */ +#if LWIP_SO_SNDTIMEO + conn->send_timeout = 0; +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + conn->recv_timeout = 0; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; + conn->recv_avail = 0; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + conn->linger = -1; +#endif /* LWIP_SO_LINGER */ + conn->flags = 0; + return conn; +free_and_return: + memp_free(MEMP_NETCONN, conn); + return NULL; +} + +/** + * Delete a netconn and all its resources. + * The pcb is NOT freed (since we might not be in the right thread context do this). + * + * @param conn the netconn to free + */ +void +netconn_free(struct netconn *conn) +{ + LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + LWIP_ASSERT("recvmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("acceptmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(&conn->op_completed); + sys_sem_set_invalid(&conn->op_completed); +#endif + + memp_free(MEMP_NETCONN, conn); +} + +/** + * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in + * these mboxes + * + * @param conn the netconn to free + * @bytes_drained bytes drained from recvmbox + * @accepts_drained pending connections drained from acceptmbox + */ +static void +netconn_drain(struct netconn *conn) +{ + void *mem; +#if LWIP_TCP + struct pbuf *p; +#endif /* LWIP_TCP */ + + /* This runs in tcpip_thread, so we don't need to lock against rx packets */ + + /* Delete and drain the recvmbox. */ + if (sys_mbox_valid(&conn->recvmbox)) { + while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +#if LWIP_TCP + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { + if (mem != NULL) { + p = (struct pbuf*)mem; + /* pcb might be set to NULL already by err_tcp() */ + if (conn->pcb.tcp != NULL) { + tcp_recved(conn->pcb.tcp, p->tot_len); + } + pbuf_free(p); + } + } else +#endif /* LWIP_TCP */ + { + netbuf_delete((struct netbuf *)mem); + } + } + sys_mbox_free(&conn->recvmbox); + sys_mbox_set_invalid(&conn->recvmbox); + } + + /* Delete and drain the acceptmbox. */ +#if LWIP_TCP + if (sys_mbox_valid(&conn->acceptmbox)) { + while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { + if (mem != &netconn_aborted) { + struct netconn *newconn = (struct netconn *)mem; + /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ + /* pcb might be set to NULL already by err_tcp() */ + /* drain recvmbox */ + netconn_drain(newconn); + if (newconn->pcb.tcp != NULL) { + tcp_abort(newconn->pcb.tcp); + newconn->pcb.tcp = NULL; + } + netconn_free(newconn); + } + } + sys_mbox_free(&conn->acceptmbox); + sys_mbox_set_invalid(&conn->acceptmbox); + } +#endif /* LWIP_TCP */ +} + +#if LWIP_TCP +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +static err_t +lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM) +{ + err_t err; + u8_t shut, shut_rx, shut_tx, close; + u8_t close_finished = 0; + struct tcp_pcb* tpcb; +#if LWIP_SO_LINGER + u8_t linger_wait_required = 0; +#endif /* LWIP_SO_LINGER */ + + LWIP_ASSERT("invalid conn", (conn != NULL)); + LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); + LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); + LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + + tpcb = conn->pcb.tcp; + shut = conn->current_msg->msg.sd.shut; + shut_rx = shut & NETCONN_SHUT_RD; + shut_tx = shut & NETCONN_SHUT_WR; + /* shutting down both ends is the same as closing + (also if RD or WR side was shut down before already) */ + if (shut == NETCONN_SHUT_RDWR) { + close = 1; + } else if (shut_rx && + ((tpcb->state == FIN_WAIT_1) || + (tpcb->state == FIN_WAIT_2) || + (tpcb->state == CLOSING))) { + close = 1; + } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) { + close = 1; + } else { + close = 0; + } + + /* Set back some callback pointers */ + if (close) { + tcp_arg(tpcb, NULL); + } + if (tpcb->state == LISTEN) { + tcp_accept(tpcb, NULL); + } else { + /* some callbacks have to be reset if tcp_close is not successful */ + if (shut_rx) { + tcp_recv(tpcb, NULL); + tcp_accept(tpcb, NULL); + } + if (shut_tx) { + tcp_sent(tpcb, NULL); + } + if (close) { + tcp_poll(tpcb, NULL, 0); + tcp_err(tpcb, NULL); + } + } + /* Try to close the connection */ + if (close) { +#if LWIP_SO_LINGER + /* check linger possibilites before calling tcp_close */ + err = ERR_OK; + /* linger enabled/required at all? (i.e. is there untransmitted data left?) */ + if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) { + if ((conn->linger == 0)) { + /* data left but linger prevents waiting */ + tcp_abort(tpcb); + tpcb = NULL; + } else if (conn->linger > 0) { + /* data left and linger says we should wait */ + if (netconn_is_nonblocking(conn)) { + /* data left on a nonblocking netconn -> cannot linger */ + err = ERR_WOULDBLOCK; + } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= + (conn->linger * 1000)) { + /* data left but linger timeout has expired (this happens on further + calls to this function through poll_tcp */ + tcp_abort(tpcb); + tpcb = NULL; + } else { + /* data left -> need to wait for ACK after successful close */ + linger_wait_required = 1; + } + } + } + if ((err == ERR_OK) && (tpcb != NULL)) +#endif /* LWIP_SO_LINGER */ + { + err = tcp_close(tpcb); + } + } else { + err = tcp_shutdown(tpcb, shut_rx, shut_tx); + } + if (err == ERR_OK) { + close_finished = 1; +#if LWIP_SO_LINGER + if (linger_wait_required) { + /* wait for ACK of all unsent/unacked data by just getting called again */ + close_finished = 0; + err = ERR_INPROGRESS; + } +#endif /* LWIP_SO_LINGER */ + } else { + if (err == ERR_MEM) { + /* Closing failed because of memory shortage, try again later. Even for + nonblocking netconns, we have to wait since no standard socket application + is prepared for close failing because of resource shortage. + Check the timeout: this is kind of an lwip addition to the standard sockets: + we wait for some time when failing to allocate a segment for the FIN */ +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT; +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout > 0) { + close_timeout = conn->send_timeout; + } +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_LINGER + if (conn->linger >= 0) { + /* use linger timeout (seconds) */ + close_timeout = conn->linger * 1000U; + } +#endif + if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) { +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + if (conn->current_msg->msg.sd.polls_left == 0) { +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + close_finished = 1; + if (close) { + /* in this case, we want to RST the connection */ + tcp_abort(tpcb); + err = ERR_OK; + } + } + } else { + /* Closing failed for a non-memory error: give up */ + close_finished = 1; + } + } + if (close_finished) { + /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ + sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + conn->current_msg->err = err; + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + if (err == ERR_OK) { + if (close) { + /* Set back some callback pointers as conn is going away */ + conn->pcb.tcp = NULL; + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + } + if (shut_rx) { + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + if (shut_tx) { + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } + NETCONN_SET_SAFE_ERR(conn, err); +#if LWIP_TCPIP_CORE_LOCKING + if (delayed) +#endif + { + /* wake up the application task */ + sys_sem_signal(op_completed_sem); + } + return ERR_OK; + } + if (!close_finished) { + /* Closing failed and we want to wait: restore some of the callbacks */ + /* Closing of listen pcb will never fail! */ + LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN)); + if (shut_tx) { + tcp_sent(tpcb, sent_tcp); + } + /* when waiting for close, set up poll interval to 500ms */ + tcp_poll(tpcb, poll_tcp, 1); + tcp_err(tpcb, err_tcp); + tcp_arg(tpcb, conn); + /* don't restore recv callback: we don't want to receive any more data */ + } + /* If closing didn't succeed, we get called again either + from poll_tcp or from sent_tcp */ + LWIP_ASSERT("err != ERR_OK", err != ERR_OK); + return err; +} +#endif /* LWIP_TCP */ + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_delconn(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + enum netconn_state state = msg->conn->state; + LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */ + (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)); +#if LWIP_NETCONN_FULLDUPLEX + /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */ + if (state != NETCONN_NONE) { + if ((state == NETCONN_WRITE) || + ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { + /* close requested, abort running write/connect */ + sys_sem_t* op_completed_sem; + LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); + op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); + msg->conn->current_msg->err = ERR_CLSD; + msg->conn->current_msg = NULL; + msg->conn->write_offset = 0; + msg->conn->state = NETCONN_NONE; + NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); + sys_sem_signal(op_completed_sem); + } + } +#else /* LWIP_NETCONN_FULLDUPLEX */ + if (((state != NETCONN_NONE) && + (state != NETCONN_LISTEN) && + (state != NETCONN_CONNECT)) || + ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) { + /* This means either a blocking write or blocking connect is running + (nonblocking write returns and sets state to NONE) */ + msg->err = ERR_INPROGRESS; + } else +#endif /* LWIP_NETCONN_FULLDUPLEX */ + { + LWIP_ASSERT("blocking connect in progress", + (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); + msg->err = ERR_OK; + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + + if (msg->conn->pcb.tcp != NULL) { + + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->conn->pcb.udp->recv_arg = NULL; + udp_remove(msg->conn->pcb.udp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + msg->conn->state = NETCONN_CLOSE; + msg->msg.sd.shut = NETCONN_SHUT_RDWR; + msg->conn->current_msg = msg; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_close_internal(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing + the application thread, so we can return at this point! */ + return; +#endif /* LWIP_TCP */ + default: + break; + } + msg->conn->pcb.tcp = NULL; + } + /* tcp netconns don't come here! */ + + /* @todo: this lets select make the socket readable and writable, + which is wrong! errfd instead? */ + API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + } + if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) { + TCPIP_APIMSG_ACK(msg); + } +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param m the api_msg_msg pointing to the connection and containing + * the IP address and port to bind to + */ +void +lwip_netconn_do_bind(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_VAL; + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_TCP */ + default: + break; + } + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t +lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + struct netconn *conn; + int was_blocking; + sys_sem_t* op_completed_sem = NULL; + + LWIP_UNUSED_ARG(pcb); + + conn = (struct netconn *)arg; + + if (conn == NULL) { + return ERR_VAL; + } + + LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); + LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", + (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); + + if (conn->current_msg != NULL) { + conn->current_msg->err = err; + op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + } + if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { + setup_tcp(conn); + } + was_blocking = !IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + LWIP_ASSERT("blocking connect state error", + (was_blocking && op_completed_sem != NULL) || + (!was_blocking && op_completed_sem == NULL)); + conn->current_msg = NULL; + conn->state = NETCONN_NONE; + NETCONN_SET_SAFE_ERR(conn, ERR_OK); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + if (was_blocking) { + sys_sem_signal(op_completed_sem); + } + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param m the api_msg_msg pointing to the connection and containing + * the IP address and port to connect to + */ +void +lwip_netconn_do_connect(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (msg->conn->pcb.tcp == NULL) { + /* This may happen when calling netconn_connect() a second time */ + msg->err = ERR_CLSD; + } else { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + /* Prevent connect while doing any other action. */ + if (msg->conn->state == NETCONN_CONNECT) { + msg->err = ERR_ALREADY; + } else if (msg->conn->state != NETCONN_NONE) { + msg->err = ERR_ISCONN; + } else { + setup_tcp(msg->conn); + msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), + msg->msg.bc.port, lwip_netconn_do_connected); + if (msg->err == ERR_OK) { + u8_t non_blocking = netconn_is_nonblocking(msg->conn); + msg->conn->state = NETCONN_CONNECT; + SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); + if (non_blocking) { + msg->err = ERR_INPROGRESS; + } else { + msg->conn->current_msg = msg; + /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), + when the connection is established! */ +#if LWIP_TCPIP_CORE_LOCKING + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + return; + } + } + } + break; +#endif /* LWIP_TCP */ + default: + LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); + break; + } + } + /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(), + so use TCPIP_APIMSG_ACK() here. */ + TCPIP_APIMSG_ACK(msg); +} + +/** + * Disconnect a pcb contained inside a netconn + * Only used for UDP netconns. + * Called from netconn_disconnect. + * + * @param m the api_msg_msg pointing to the connection to disconnect + */ +void +lwip_netconn_do_disconnect(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + +#if LWIP_UDP + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { + udp_disconnect(msg->conn->pcb.udp); + msg->err = ERR_OK; + } else +#endif /* LWIP_UDP */ + { + msg->err = ERR_VAL; + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_listen(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + if (msg->conn->state == NETCONN_NONE) { + struct tcp_pcb* lpcb; + if (msg->conn->pcb.tcp->state != CLOSED) { + /* connection is not closed, cannot listen */ + msg->err = ERR_VAL; + } else { + err_t err; + u8_t backlog; +#if TCP_LISTEN_BACKLOG + backlog = msg->msg.lb.backlog; +#else /* TCP_LISTEN_BACKLOG */ + backlog = TCP_DEFAULT_LISTEN_BACKLOG; +#endif /* TCP_LISTEN_BACKLOG */ +#if LWIP_IPV4 && LWIP_IPV6 + /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, + * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen + */ + if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) && + (netconn_get_ipv6only(msg->conn) == 0)) { + /* change PCB type to IPADDR_TYPE_ANY */ + IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip, IPADDR_TYPE_ANY); + IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); + + if (lpcb == NULL) { + /* in this case, the old pcb is still allocated */ + msg->err = err; + } else { + /* delete the recvmbox and allocate the acceptmbox */ + if (sys_mbox_valid(&msg->conn->recvmbox)) { + /** @todo: should we drain the recvmbox here? */ + sys_mbox_free(&msg->conn->recvmbox); + sys_mbox_set_invalid(&msg->conn->recvmbox); + } + msg->err = ERR_OK; + if (!sys_mbox_valid(&msg->conn->acceptmbox)) { + msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); + } + if (msg->err == ERR_OK) { + msg->conn->state = NETCONN_LISTEN; + msg->conn->pcb.tcp = lpcb; + tcp_arg(msg->conn->pcb.tcp, msg->conn); + tcp_accept(msg->conn->pcb.tcp, accept_function); + } else { + /* since the old pcb is already deallocated, free lpcb now */ + tcp_close(lpcb); + msg->conn->pcb.tcp = NULL; + } + } + } + } else if (msg->conn->state == NETCONN_LISTEN) { + /* already listening, allow updating of the backlog */ + msg->err = ERR_OK; + tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog); + } + } else { + msg->err = ERR_ARG; + } + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_send(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; + if (msg->conn->pcb.tcp != NULL) { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); + } else { + msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); + } + break; +#endif +#if LWIP_UDP + case NETCONN_UDP: +#if LWIP_CHECKSUM_ON_COPY + if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } else { + msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, + &msg->msg.b->addr, msg->msg.b->port, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } +#else /* LWIP_CHECKSUM_ON_COPY */ + if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { + msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); + } else { + msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + break; +#endif /* LWIP_UDP */ + default: + break; + } + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_recv(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + u32_t remaining = msg->msg.r.len; + do { + u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; + tcp_recved(msg->conn->pcb.tcp, recved); + remaining -= recved; + } while (remaining != 0); + } + } + TCPIP_APIMSG_ACK(msg); +} + +#if TCP_LISTEN_BACKLOG +/** Indicate that a TCP pcb has been accepted + * Called from netconn_accept + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_accepted(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { + tcp_backlog_accepted(msg->conn->pcb.tcp); + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* TCP_LISTEN_BACKLOG */ + +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from lwip_netconn_do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +static err_t +lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) +{ + err_t err; + const void *dataptr; + u16_t len, available; + u8_t write_finished = 0; + size_t diff; + u8_t dontblock; + u8_t apiflags; + + LWIP_ASSERT("conn != NULL", conn != NULL); + LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); + LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", + conn->write_offset < conn->current_msg->msg.w.len); + + apiflags = conn->current_msg->msg.w.apiflags; + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); + +#if LWIP_SO_SNDTIMEO + if ((conn->send_timeout != 0) && + ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { + write_finished = 1; + if (conn->write_offset == 0) { + /* nothing has been written */ + err = ERR_WOULDBLOCK; + conn->current_msg->msg.w.len = 0; + } else { + /* partial write */ + err = ERR_OK; + conn->current_msg->msg.w.len = conn->write_offset; + conn->write_offset = 0; + } + } else +#endif /* LWIP_SO_SNDTIMEO */ + { + dataptr = (const u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; + diff = conn->current_msg->msg.w.len - conn->write_offset; + if (diff > 0xffffUL) { /* max_u16_t */ + len = 0xffff; + apiflags |= TCP_WRITE_FLAG_MORE; + } else { + len = (u16_t)diff; + } + available = tcp_sndbuf(conn->pcb.tcp); + if (available < len) { + /* don't try to write more than sendbuf */ + len = available; + if (dontblock) { + if (!len) { + err = ERR_WOULDBLOCK; + goto err_mem; + } + } else { + apiflags |= TCP_WRITE_FLAG_MORE; + } + } + LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + /* if OK or memory error, check available space */ + if ((err == ERR_OK) || (err == ERR_MEM)) { +err_mem: + if (dontblock && (len < conn->current_msg->msg.w.len)) { + /* non-blocking write did not write everything: mark the pcb non-writable + and let poll_tcp check writable space to mark the pcb writable again */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + } + } + + if (err == ERR_OK) { + err_t out_err; + conn->write_offset += len; + if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { + /* return sent length */ + conn->current_msg->msg.w.len = conn->write_offset; + /* everything was written */ + write_finished = 1; + } + out_err = tcp_output(conn->pcb.tcp); + if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { + /* If tcp_output fails with fatal error or no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + conn->current_msg->msg.w.len = 0; + } + } else if (err == ERR_MEM) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. + For blocking sockets, we do NOT return to the application + thread, since ERR_MEM is only a temporary error! Non-blocking + will remain non-writable until sent_tcp/poll_tcp is called */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + err_t out_err = tcp_output(conn->pcb.tcp); + if (ERR_IS_FATAL(out_err) || (out_err == ERR_RTE)) { + /* If tcp_output fails with fatal error or no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + conn->current_msg->msg.w.len = 0; + } else if (dontblock) { + /* non-blocking write is done on ERR_MEM */ + err = ERR_WOULDBLOCK; + write_finished = 1; + conn->current_msg->msg.w.len = 0; + } + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + conn->current_msg->msg.w.len = 0; + } + } + if (write_finished) { + /* everything was written: set back connection state + and back to application task */ + sys_sem_t* op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); + conn->current_msg->err = err; + conn->current_msg = NULL; + conn->write_offset = 0; + conn->state = NETCONN_NONE; + NETCONN_SET_SAFE_ERR(conn, err); +#if LWIP_TCPIP_CORE_LOCKING + if (delayed) +#endif + { + sys_sem_signal(op_completed_sem); + } + } +#if LWIP_TCPIP_CORE_LOCKING + else { + return ERR_MEM; + } +#endif + return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_write(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { +#if LWIP_TCP + if (msg->conn->state != NETCONN_NONE) { + /* netconn is connecting, closing or in blocking write */ + msg->err = ERR_INPROGRESS; + } else if (msg->conn->pcb.tcp != NULL) { + msg->conn->state = NETCONN_WRITE; + /* set all the variables used by lwip_netconn_do_writemore */ + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); + msg->conn->current_msg = msg; + msg->conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_writemore(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG + since lwip_netconn_do_writemore ACKs it! */ + return; + } else { + msg->err = ERR_CONN; + } +#else /* LWIP_TCP */ + msg->err = ERR_VAL; +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_getaddr(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (msg->conn->pcb.ip != NULL) { + if (msg->msg.ad.local) { + ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->local_ip); + } else { + ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->remote_ip); + } + + msg->err = ERR_OK; + switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW + case NETCONN_RAW: + if (msg->msg.ad.local) { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; + } else { + /* return an error as connecting is only a helper for upper layers */ + msg->err = ERR_CONN; + } + break; +#endif /* LWIP_RAW */ +#if LWIP_UDP + case NETCONN_UDP: + if (msg->msg.ad.local) { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; + } else { + if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { + msg->err = ERR_CONN; + } else { + API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; + } + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + if ((msg->msg.ad.local == 0) && + ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { + /* pcb is not connected and remote name is requested */ + msg->err = ERR_CONN; + } else { + API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); + } + break; +#endif /* LWIP_TCP */ + default: + LWIP_ASSERT("invalid netconn_type", 0); + break; + } + } else { + msg->err = ERR_CONN; + } + TCPIP_APIMSG_ACK(msg); +} + +/** + * Close or half-shutdown a TCP pcb contained in a netconn + * Called from netconn_close + * In contrast to closing sockets, the netconn is not deallocated. + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_close(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + +#if LWIP_TCP + enum netconn_state state = msg->conn->state; + /* First check if this is a TCP netconn and if it is in a correct state + (LISTEN doesn't support half shutdown) */ + if ((msg->conn->pcb.tcp != NULL) && + (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) && + ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) { + /* Check if we are in a connected state */ + if (state == NETCONN_CONNECT) { + /* TCP connect in progress: cannot shutdown */ + msg->err = ERR_CONN; + } else if (state == NETCONN_WRITE) { +#if LWIP_NETCONN_FULLDUPLEX + if (msg->msg.sd.shut & NETCONN_SHUT_WR) { + /* close requested, abort running write */ + sys_sem_t* write_completed_sem; + LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL); + write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg); + msg->conn->current_msg->err = ERR_CLSD; + msg->conn->current_msg = NULL; + msg->conn->write_offset = 0; + msg->conn->state = NETCONN_NONE; + state = NETCONN_NONE; + NETCONN_SET_SAFE_ERR(msg->conn, ERR_CLSD); + sys_sem_signal(write_completed_sem); + } else { + LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD); + /* In this case, let the write continue and do not interfere with + conn->current_msg or conn->state! */ + msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0); + } + } + if (state == NETCONN_NONE) { +#else /* LWIP_NETCONN_FULLDUPLEX */ + msg->err = ERR_INPROGRESS; + } else { +#endif /* LWIP_NETCONN_FULLDUPLEX */ + if (msg->msg.sd.shut & NETCONN_SHUT_RD) { + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + } + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + msg->conn->state = NETCONN_CLOSE; + msg->conn->current_msg = msg; +#if LWIP_TCPIP_CORE_LOCKING + if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + lwip_netconn_do_close_internal(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ + return; + } + } else +#endif /* LWIP_TCP */ + { + msg->err = ERR_CONN; + } + TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param m the api_msg_msg pointing to the connection + */ +void +lwip_netconn_do_join_leave_group(void *m) +{ + struct api_msg *msg = (struct api_msg*)m; + + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + if (msg->conn->pcb.tcp != NULL) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP +#if LWIP_IPV6 && LWIP_IPV6_MLD + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); + } + } + else +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + { +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } else { + msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)), + ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr))); + } +#endif /* LWIP_IGMP */ + } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) + } else { + msg->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ + } + } else { + msg->err = ERR_CONN; + } + } + TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/** + * Callback function that is called when DNS name is resolved + * (or on timeout). A waiting application thread is waked up by + * signaling the semaphore. + */ +static void +lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg*)arg; + + /* we trust the internal implementation to be correct :-) */ + LWIP_UNUSED_ARG(name); + + if (ipaddr == NULL) { + /* timeout or memory error */ + API_EXPR_DEREF(msg->err) = ERR_VAL; + } else { + /* address was resolved */ + API_EXPR_DEREF(msg->err) = ERR_OK; + API_EXPR_DEREF(msg->addr) = *ipaddr; + } + /* wake up the application task waiting in netconn_gethostbyname */ + sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); +} + +/** + * Execute a DNS query + * Called from netconn_gethostbyname + * + * @param arg the dns_api_msg pointing to the query + */ +void +lwip_netconn_do_gethostbyname(void *arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg*)arg; + u8_t addrtype = +#if LWIP_IPV4 && LWIP_IPV6 + msg->dns_addrtype; +#else + LWIP_DNS_ADDRTYPE_DEFAULT; +#endif + + API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, + API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); + if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { + /* on error or immediate success, wake up the application + * task waiting in netconn_gethostbyname */ + sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); + } +} +#endif /* LWIP_DNS */ + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/err.c b/Sming/third-party/lwip2/lwip2-src/src/api/err.c new file mode 100644 index 0000000000..35e9c025ea --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/err.c @@ -0,0 +1,115 @@ +/** + * @file + * Error Management module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/err.h" +#include "lwip/def.h" +#include "lwip/sys.h" + +#include "lwip/errno.h" + +#if !NO_SYS +/** Table to quickly map an lwIP error (err_t) to a socket error + * by using -err as an index */ +static const int err_to_errno_table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + ENOMEM, /* ERR_MEM -1 Out of memory error. */ + ENOBUFS, /* ERR_BUF -2 Buffer error. */ + EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + EINVAL, /* ERR_VAL -6 Illegal value. */ + EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + EADDRINUSE, /* ERR_USE -8 Address in use. */ + EALREADY, /* ERR_ALREADY -9 Already connecting. */ + EISCONN, /* ERR_ISCONN -10 Conn already established.*/ + ENOTCONN, /* ERR_CONN -11 Not connected. */ + -1, /* ERR_IF -12 Low-level netif error */ + ECONNABORTED, /* ERR_ABRT -13 Connection aborted. */ + ECONNRESET, /* ERR_RST -14 Connection reset. */ + ENOTCONN, /* ERR_CLSD -15 Connection closed. */ + EIO /* ERR_ARG -16 Illegal argument. */ +}; + +int +err_to_errno(err_t err) +{ + if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_to_errno_table))) { + return EIO; + } + return err_to_errno_table[-err]; +} +#endif /* !NO_SYS */ + +#ifdef LWIP_DEBUG + +static const char *err_strerr[] = { + "Ok.", /* ERR_OK 0 */ + "Out of memory error.", /* ERR_MEM -1 */ + "Buffer error.", /* ERR_BUF -2 */ + "Timeout.", /* ERR_TIMEOUT -3 */ + "Routing problem.", /* ERR_RTE -4 */ + "Operation in progress.", /* ERR_INPROGRESS -5 */ + "Illegal value.", /* ERR_VAL -6 */ + "Operation would block.", /* ERR_WOULDBLOCK -7 */ + "Address in use.", /* ERR_USE -8 */ + "Already connecting.", /* ERR_ALREADY -9 */ + "Already connected.", /* ERR_ISCONN -10 */ + "Not connected.", /* ERR_CONN -11 */ + "Low-level netif error.", /* ERR_IF -12 */ + "Connection aborted.", /* ERR_ABRT -13 */ + "Connection reset.", /* ERR_RST -14 */ + "Connection closed.", /* ERR_CLSD -15 */ + "Illegal argument." /* ERR_ARG -16 */ +}; + +/** + * Convert an lwip internal error to a string representation. + * + * @param err an lwip internal err_t + * @return a string representation for err + */ +const char * +lwip_strerr(err_t err) +{ + if ((err > 0) || (-err >= (err_t)LWIP_ARRAYSIZE(err_strerr))) { + return "Unknown error."; + } + return err_strerr[-err]; +} + +#endif /* LWIP_DEBUG */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/netbuf.c b/Sming/third-party/lwip2/lwip2-src/src/api/netbuf.c new file mode 100644 index 0000000000..eb250115ff --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/netbuf.c @@ -0,0 +1,246 @@ +/** + * @file + * Network buffer management + * + * @defgroup netbuf Network buffers + * @ingroup netconn + * Network buffer descriptor for @ref netconn. Based on @ref pbuf internally + * to avoid copying data around.\n + * Buffers must not be shared accross multiple threads, all functions except + * netbuf_new() and netbuf_delete() are not thread-safe. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netbuf.h" +#include "lwip/memp.h" + +#include + +/** + * @ingroup netbuf + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * + * @return a pointer to a new netbuf + * NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ + struct netbuf *buf; + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf != NULL) { + memset(buf, 0, sizeof(struct netbuf)); + } + return buf; +} + +/** + * @ingroup netbuf + * Deallocate a netbuf allocated by netbuf_new(). + * + * @param buf pointer to a netbuf allocated by netbuf_new() + */ +void +netbuf_delete(struct netbuf *buf) +{ + if (buf != NULL) { + if (buf->p != NULL) { + pbuf_free(buf->p); + buf->p = buf->ptr = NULL; + } + memp_free(MEMP_NETBUF, buf); + } +} + +/** + * @ingroup netbuf + * Allocate memory for a packet buffer for a given netbuf. + * + * @param buf the netbuf for which to allocate a packet buffer + * @param size the size of the packet buffer to allocate + * @return pointer to the allocated memory + * NULL if no memory could be allocated + */ +void * +netbuf_alloc(struct netbuf *buf, u16_t size) +{ + LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); + + /* Deallocate any previously allocated memory. */ + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (buf->p == NULL) { + return NULL; + } + LWIP_ASSERT("check that first pbuf can hold size", + (buf->p->len >= size)); + buf->ptr = buf->p; + return buf->p->payload; +} + +/** + * @ingroup netbuf + * Free the packet buffer included in a netbuf + * + * @param buf pointer to the netbuf which contains the packet buffer to free + */ +void +netbuf_free(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = buf->ptr = NULL; +} + +/** + * @ingroup netbuf + * Let a netbuf reference existing (non-volatile) data. + * + * @param buf netbuf which should reference the data + * @param dataptr pointer to the data to reference + * @param size size of the data + * @return ERR_OK if data is referenced + * ERR_MEM if data couldn't be referenced due to lack of memory + */ +err_t +netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) +{ + LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); + if (buf->p != NULL) { + pbuf_free(buf->p); + } + buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + if (buf->p == NULL) { + buf->ptr = NULL; + return ERR_MEM; + } + ((struct pbuf_rom*)buf->p)->payload = dataptr; + buf->p->len = buf->p->tot_len = size; + buf->ptr = buf->p; + return ERR_OK; +} + +/** + * @ingroup netbuf + * Chain one netbuf to another (@see pbuf_chain) + * + * @param head the first netbuf + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning + */ +void +netbuf_chain(struct netbuf *head, struct netbuf *tail) +{ + LWIP_ERROR("netbuf_chain: invalid head", (head != NULL), return;); + LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); + pbuf_cat(head->p, tail->p); + head->ptr = head->p; + memp_free(MEMP_NETBUF, tail); +} + +/** + * @ingroup netbuf + * Get the data pointer and length of the data inside a netbuf. + * + * @param buf netbuf to get the data from + * @param dataptr pointer to a void pointer where to store the data pointer + * @param len pointer to an u16_t where the length of the data is stored + * @return ERR_OK if the information was retrieved, + * ERR_BUF on error. + */ +err_t +netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) +{ + LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); + LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); + + if (buf->ptr == NULL) { + return ERR_BUF; + } + *dataptr = buf->ptr->payload; + *len = buf->ptr->len; + return ERR_OK; +} + +/** + * @ingroup netbuf + * Move the current data pointer of a packet buffer contained in a netbuf + * to the next part. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + * @return -1 if there is no next part + * 1 if moved to the next part but now there is no next part + * 0 if moved to the next part and there are still more parts + */ +s8_t +netbuf_next(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_next: invalid buf", (buf != NULL), return -1;); + if (buf->ptr->next == NULL) { + return -1; + } + buf->ptr = buf->ptr->next; + if (buf->ptr->next == NULL) { + return 1; + } + return 0; +} + +/** + * @ingroup netbuf + * Move the current data pointer of a packet buffer contained in a netbuf + * to the beginning of the packet. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + */ +void +netbuf_first(struct netbuf *buf) +{ + LWIP_ERROR("netbuf_first: invalid buf", (buf != NULL), return;); + buf->ptr = buf->p; +} + +#endif /* LWIP_NETCONN */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/netdb.c b/Sming/third-party/lwip2/lwip2-src/src/api/netdb.c new file mode 100644 index 0000000000..ccd9586fda --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/netdb.c @@ -0,0 +1,413 @@ +/** + * @file + * API functions for name resolving + * + * @defgroup netdbapi NETDB API + * @ingroup socket + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/netdb.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/err.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/api.h" +#include "lwip/dns.h" + +#include /* memset */ +#include /* atoi */ + +/** helper struct for gethostbyname_r to access the char* buffer */ +struct gethostbyname_r_helper { + ip_addr_t *addr_list[2]; + ip_addr_t addr; + char *aliases; +}; + +/** h_errno is exported in netdb.h for access by applications. */ +#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + +/** define "hostent" variables storage: 0 if we use a static (but unprotected) + * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +#ifndef LWIP_DNS_API_HOSTENT_STORAGE +#define LWIP_DNS_API_HOSTENT_STORAGE 0 +#endif + +/** define "hostent" variables storage */ +#if LWIP_DNS_API_HOSTENT_STORAGE +#define HOSTENT_STORAGE +#else +#define HOSTENT_STORAGE static +#endif /* LWIP_DNS_API_STATIC_HOSTENT */ + +/** + * Returns an entry containing addresses of address family AF_INET + * for the host with name name. + * Due to dns_gethostbyname limitations, only one address is returned. + * + * @param name the hostname to resolve + * @return an entry containing addresses of address family AF_INET + * for the host with name name + */ +struct hostent* +lwip_gethostbyname(const char *name) +{ + err_t err; + ip_addr_t addr; + + /* buffer variables for lwip_gethostbyname() */ + HOSTENT_STORAGE struct hostent s_hostent; + HOSTENT_STORAGE char *s_aliases; + HOSTENT_STORAGE ip_addr_t s_hostent_addr; + HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; + HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; + + /* query host IP address */ + err = netconn_gethostbyname(name, &addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + h_errno = HOST_NOT_FOUND; + return NULL; + } + + /* fill hostent */ + s_hostent_addr = addr; + s_phostent_addr[0] = &s_hostent_addr; + s_phostent_addr[1] = NULL; + strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH); + s_hostname[DNS_MAX_NAME_LENGTH] = 0; + s_hostent.h_name = s_hostname; + s_aliases = NULL; + s_hostent.h_aliases = &s_aliases; + s_hostent.h_addrtype = AF_INET; + s_hostent.h_length = sizeof(ip_addr_t); + s_hostent.h_addr_list = (char**)&s_phostent_addr; + +#if DNS_DEBUG + /* dump hostent */ + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void*)s_hostent.h_aliases)); + /* h_aliases are always empty */ + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void*)s_hostent.h_addr_list)); + if (s_hostent.h_addr_list != NULL) { + u8_t idx; + for (idx=0; s_hostent.h_addr_list[idx]; idx++) { + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); + } + } +#endif /* DNS_DEBUG */ + +#if LWIP_DNS_API_HOSTENT_STORAGE + /* this function should return the "per-thread" hostent after copy from s_hostent */ + return sys_thread_hostent(&s_hostent); +#else + return &s_hostent; +#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ +} + +/** + * Thread-safe variant of lwip_gethostbyname: instead of using a static + * buffer, this function takes buffer and errno pointers as arguments + * and uses these for the result. + * + * @param name the hostname to resolve + * @param ret pre-allocated struct where to store the result + * @param buf pre-allocated buffer where to store additional data + * @param buflen the size of buf + * @param result pointer to a hostent pointer that is set to ret on success + * and set to zero on error + * @param h_errnop pointer to an int where to store errors (instead of modifying + * the global h_errno) + * @return 0 on success, non-zero on error, additional error information + * is stored in *h_errnop instead of h_errno to be thread-safe + */ +int +lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop) +{ + err_t err; + struct gethostbyname_r_helper *h; + char *hostname; + size_t namelen; + int lh_errno; + + if (h_errnop == NULL) { + /* ensure h_errnop is never NULL */ + h_errnop = &lh_errno; + } + + if (result == NULL) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + /* first thing to do: set *result to nothing */ + *result = NULL; + if ((name == NULL) || (ret == NULL) || (buf == NULL)) { + /* not all arguments given */ + *h_errnop = EINVAL; + return -1; + } + + namelen = strlen(name); + if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { + /* buf can't hold the data needed + a copy of name */ + *h_errnop = ERANGE; + return -1; + } + + h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); + hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); + + /* query host IP address */ + err = netconn_gethostbyname(name, &h->addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + *h_errnop = HOST_NOT_FOUND; + return -1; + } + + /* copy the hostname into buf */ + MEMCPY(hostname, name, namelen); + hostname[namelen] = 0; + + /* fill hostent */ + h->addr_list[0] = &h->addr; + h->addr_list[1] = NULL; + h->aliases = NULL; + ret->h_name = hostname; + ret->h_aliases = &h->aliases; + ret->h_addrtype = AF_INET; + ret->h_length = sizeof(ip_addr_t); + ret->h_addr_list = (char**)&h->addr_list; + + /* set result != NULL */ + *result = ret; + + /* return success */ + return 0; +} + +/** + * Frees one or more addrinfo structures returned by getaddrinfo(), along with + * any additional storage associated with those structures. If the ai_next field + * of the structure is not null, the entire list of structures is freed. + * + * @param ai struct addrinfo to free + */ +void +lwip_freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + while (ai != NULL) { + next = ai->ai_next; + memp_free(MEMP_NETDB, ai); + ai = next; + } +} + +/** + * Translates the name of a service location (for example, a host name) and/or + * a service name and returns a set of socket addresses and associated + * information to be used in creating a socket with which to address the + * specified service. + * Memory for the result is allocated internally and must be freed by calling + * lwip_freeaddrinfo()! + * + * Due to a limitation in dns_gethostbyname, only the first address of a + * host is returned. + * Also, service names are not supported (only port numbers)! + * + * @param nodename descriptive name or address string of the host + * (may be NULL -> local address) + * @param servname port number as string of NULL + * @param hints structure containing input values that set socktype and protocol + * @param res pointer to a pointer where to store the result (set to NULL on failure) + * @return 0 on success, non-zero on failure + * + * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG + */ +int +lwip_getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + err_t err; + ip_addr_t addr; + struct addrinfo *ai; + struct sockaddr_storage *sa = NULL; + int port_nr = 0; + size_t total_size; + size_t namelen = 0; + int ai_family; + + if (res == NULL) { + return EAI_FAIL; + } + *res = NULL; + if ((nodename == NULL) && (servname == NULL)) { + return EAI_NONAME; + } + + if (hints != NULL) { + ai_family = hints->ai_family; + if ((ai_family != AF_UNSPEC) +#if LWIP_IPV4 + && (ai_family != AF_INET) +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + && (ai_family != AF_INET6) +#endif /* LWIP_IPV6 */ + ) { + return EAI_FAMILY; + } + } else { + ai_family = AF_UNSPEC; + } + + if (servname != NULL) { + /* service name specified: convert to port number + * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ + port_nr = atoi(servname); + if ((port_nr <= 0) || (port_nr > 0xffff)) { + return EAI_SERVICE; + } + } + + if (nodename != NULL) { + /* service location specified, try to resolve */ + if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { + /* no DNS lookup, just parse for an address string */ + if (!ipaddr_aton(nodename, &addr)) { + return EAI_NONAME; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || + (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { + return EAI_NONAME; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + } else { +#if LWIP_IPV4 && LWIP_IPV6 + /* AF_UNSPEC: prefer IPv4 */ + u8_t type = NETCONN_DNS_IPV4_IPV6; + if (ai_family == AF_INET) { + type = NETCONN_DNS_IPV4; + } else if (ai_family == AF_INET6) { + type = NETCONN_DNS_IPV6; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + err = netconn_gethostbyname_addrtype(nodename, &addr, type); + if (err != ERR_OK) { + return EAI_FAIL; + } + } + } else { + /* service location specified, use loopback address */ + if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { + ip_addr_set_any(ai_family == AF_INET6, &addr); + } else { + ip_addr_set_loopback(ai_family == AF_INET6, &addr); + } + } + + total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); + if (nodename != NULL) { + namelen = strlen(nodename); + if (namelen > DNS_MAX_NAME_LENGTH) { + /* invalid name length */ + return EAI_FAIL; + } + LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); + total_size += namelen + 1; + } + /* If this fails, please report to lwip-devel! :-) */ + LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", + total_size <= NETDB_ELEM_SIZE); + ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); + if (ai == NULL) { + return EAI_MEMORY; + } + memset(ai, 0, total_size); + /* cast through void* to get rid of alignment warnings */ + sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo)); + if (IP_IS_V6_VAL(addr)) { +#if LWIP_IPV6 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa; + /* set up sockaddr */ + inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); + sa6->sin6_family = AF_INET6; + sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_port = lwip_htons((u16_t)port_nr); + ai->ai_family = AF_INET6; +#endif /* LWIP_IPV6 */ + } else { +#if LWIP_IPV4 + struct sockaddr_in *sa4 = (struct sockaddr_in*)sa; + /* set up sockaddr */ + inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); + sa4->sin_family = AF_INET; + sa4->sin_len = sizeof(struct sockaddr_in); + sa4->sin_port = lwip_htons((u16_t)port_nr); + ai->ai_family = AF_INET; +#endif /* LWIP_IPV4 */ + } + + /* set up addrinfo */ + if (hints != NULL) { + /* copy socktype & protocol from hints if specified */ + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + } + if (nodename != NULL) { + /* copy nodename to canonname if specified */ + ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + MEMCPY(ai->ai_canonname, nodename, namelen); + ai->ai_canonname[namelen] = 0; + } + ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr*)sa; + + *res = ai; + + return 0; +} + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/netifapi.c b/Sming/third-party/lwip2/lwip2-src/src/api/netifapi.c new file mode 100644 index 0000000000..fef05a34dc --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/netifapi.c @@ -0,0 +1,221 @@ +/** + * @file + * Network Interface Sequential API module + * + * @defgroup netifapi NETIF API + * @ingroup sequential_api + * Thread-safe functions to be called from non-TCPIP threads + * + * @defgroup netifapi_netif NETIF related + * @ingroup netifapi + * To be called from non-TCPIP threads + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netifapi.h" +#include "lwip/memp.h" +#include "lwip/priv/tcpip_priv.h" + +#define NETIFAPI_VAR_REF(name) API_VAR_REF(name) +#define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name) +#define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM) +#define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name) + +/** + * Call netif_add() inside the tcpip_thread context. + */ +static err_t +netifapi_do_netif_add(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; + + if (!netif_add( msg->netif, +#if LWIP_IPV4 + API_EXPR_REF(msg->msg.add.ipaddr), + API_EXPR_REF(msg->msg.add.netmask), + API_EXPR_REF(msg->msg.add.gw), +#endif /* LWIP_IPV4 */ + msg->msg.add.state, + msg->msg.add.init, + msg->msg.add.input)) { + return ERR_IF; + } else { + return ERR_OK; + } +} + +#if LWIP_IPV4 +/** + * Call netif_set_addr() inside the tcpip_thread context. + */ +static err_t +netifapi_do_netif_set_addr(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; + + netif_set_addr( msg->netif, + API_EXPR_REF(msg->msg.add.ipaddr), + API_EXPR_REF(msg->msg.add.netmask), + API_EXPR_REF(msg->msg.add.gw)); + return ERR_OK; +} +#endif /* LWIP_IPV4 */ + +/** + * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the + * tcpip_thread context. + */ +static err_t +netifapi_do_netif_common(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct netifapi_msg */ + struct netifapi_msg *msg = (struct netifapi_msg*)(void*)m; + + if (msg->msg.common.errtfunc != NULL) { + return msg->msg.common.errtfunc(msg->netif); + } else { + msg->msg.common.voidfunc(msg->netif); + return ERR_OK; + } +} + +/** + * @ingroup netifapi_netif + * Call netif_add() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_add() + */ +err_t +netifapi_netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + +#if LWIP_IPV4 + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } +#endif /* LWIP_IPV4 */ + + NETIFAPI_VAR_REF(msg).netif = netif; +#if LWIP_IPV4 + NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); + NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); + NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); +#endif /* LWIP_IPV4 */ + NETIFAPI_VAR_REF(msg).msg.add.state = state; + NETIFAPI_VAR_REF(msg).msg.add.init = init; + NETIFAPI_VAR_REF(msg).msg.add.input = input; + err = tcpip_api_call(netifapi_do_netif_add, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} + +#if LWIP_IPV4 +/** + * @ingroup netifapi_netif + * Call netif_set_addr() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_set_addr() + */ +err_t +netifapi_netif_set_addr(struct netif *netif, + const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY4; + } + if (netmask == NULL) { + netmask = IP4_ADDR_ANY4; + } + if (gw == NULL) { + gw = IP4_ADDR_ANY4; + } + + NETIFAPI_VAR_REF(msg).netif = netif; + NETIFAPI_VAR_REF(msg).msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); + NETIFAPI_VAR_REF(msg).msg.add.netmask = NETIFAPI_VAR_REF(netmask); + NETIFAPI_VAR_REF(msg).msg.add.gw = NETIFAPI_VAR_REF(gw); + err = tcpip_api_call(netifapi_do_netif_set_addr, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} +#endif /* LWIP_IPV4 */ + +/** + * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe + * way by running that function inside the tcpip_thread context. + * + * @note use only for functions where there is only "netif" parameter. + */ +err_t +netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc) +{ + err_t err; + NETIFAPI_VAR_DECLARE(msg); + NETIFAPI_VAR_ALLOC(msg); + + NETIFAPI_VAR_REF(msg).netif = netif; + NETIFAPI_VAR_REF(msg).msg.common.voidfunc = voidfunc; + NETIFAPI_VAR_REF(msg).msg.common.errtfunc = errtfunc; + err = tcpip_api_call(netifapi_do_netif_common, &API_VAR_REF(msg).call); + NETIFAPI_VAR_FREE(msg); + return err; +} + +#endif /* LWIP_NETIF_API */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/sockets.c b/Sming/third-party/lwip2/lwip2-src/src/api/sockets.c new file mode 100644 index 0000000000..b76324893f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/sockets.c @@ -0,0 +1,2827 @@ +/** + * @file + * Sockets BSD-Like API module + * + * @defgroup socket Socket API + * @ingroup sequential_api + * BSD-style socket API.\n + * Thread-safe, to be called from non-TCPIP threads only.\n + * Can be activated by defining @ref LWIP_SOCKET to 1.\n + * Header is in posix/sys/socket.h\b + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * Improved by Marc Boucher and David Haas + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sockets.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/priv/tcpip_priv.h" +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#include + +/* If the netconn API is not required publicly, then we include the necessary + files here to get the implementation */ +#if !LWIP_NETCONN +#undef LWIP_NETCONN +#define LWIP_NETCONN 1 +#include "api_msg.c" +#include "api_lib.c" +#include "netbuf.c" +#undef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +#if LWIP_IPV4 +#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ + (sin)->sin_len = sizeof(struct sockaddr_in); \ + (sin)->sin_family = AF_INET; \ + (sin)->sin_port = lwip_htons((port)); \ + inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ + memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) +#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ + inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ + (port) = lwip_ntohs((sin)->sin_port); }while(0) +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ + (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ + (sin6)->sin6_family = AF_INET6; \ + (sin6)->sin6_port = lwip_htons((port)); \ + (sin6)->sin6_flowinfo = 0; \ + inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ + (sin6)->sin6_scope_id = 0; }while(0) +#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ + inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ + (port) = lwip_ntohs((sin6)->sin6_port); }while(0) +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 && LWIP_IPV6 +static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port); + +#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ + ((namelen) == sizeof(struct sockaddr_in6))) +#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ + ((name)->sa_family == AF_INET6)) +#define SOCK_ADDR_TYPE_MATCH(name, sock) \ + ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ + (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ + if (IP_IS_V6(ipaddr)) { \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ + } else { \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ + } } while(0) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) +#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ + (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ +#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) +#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) +#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ + SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) +#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ +#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) +#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) +#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 +#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) +#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ + SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) +#endif /* LWIP_IPV6 */ + +#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ + IS_SOCK_ADDR_TYPE_VALID(name)) +#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ + SOCK_ADDR_TYPE_MATCH(name, sock)) +#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) + + +#define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ + if ((sock)->conn == NULL) { return EINVAL; } }while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \ + if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0) +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ + if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0) + + +#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) +#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) +#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) +#if LWIP_MPU_COMPATIBLE +#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ + name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ + if (name == NULL) { \ + sock_set_errno(sock, ENOMEM); \ + return -1; \ + } }while(0) +#else /* LWIP_MPU_COMPATIBLE */ +#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) +#endif /* LWIP_MPU_COMPATIBLE */ + +#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD +#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int +#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) +#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval)) +#else +#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval +#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ + s32_t loc = (val); \ + ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \ + ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0) +#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U)) +#endif + +#define NUM_SOCKETS MEMP_NUM_NETCONN + +/** This is overridable for the rare case where more than 255 threads + * select on the same socket... + */ +#ifndef SELWAIT_T +#define SELWAIT_T u8_t +#endif + +/** Contains all internal pointers and states used for a socket */ +struct lwip_sock { + /** sockets currently are built on netconns, each socket has one netconn */ + struct netconn *conn; + /** data that was left from the previous read */ + void *lastdata; + /** offset in the data that was left from the previous read */ + u16_t lastoffset; + /** number of times data was received, set by event_callback(), + tested by the receive and select functions */ + s16_t rcvevent; + /** number of times data was ACKed (free send buffer), set by event_callback(), + tested by select */ + u16_t sendevent; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; + /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */ + u8_t err; + /** counter of how many threads are waiting for this socket using select */ + SELWAIT_T select_waiting; +}; + +#if LWIP_NETCONN_SEM_PER_THREAD +#define SELECT_SEM_T sys_sem_t* +#define SELECT_SEM_PTR(sem) (sem) +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define SELECT_SEM_T sys_sem_t +#define SELECT_SEM_PTR(sem) (&(sem)) +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +/** Description for a task waiting in select */ +struct lwip_select_cb { + /** Pointer to the next waiting task */ + struct lwip_select_cb *next; + /** Pointer to the previous waiting task */ + struct lwip_select_cb *prev; + /** readset passed to select */ + fd_set *readset; + /** writeset passed to select */ + fd_set *writeset; + /** unimplemented: exceptset passed to select */ + fd_set *exceptset; + /** don't signal the same semaphore twice: set to 1 when signalled */ + int sem_signalled; + /** semaphore to wake up a task waiting for select */ + SELECT_SEM_T sem; +}; + +/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ + * sockaddr_in6 if instantiated. + */ +union sockaddr_aligned { + struct sockaddr sa; +#if LWIP_IPV6 + struct sockaddr_in6 sin6; +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + struct sockaddr_in sin; +#endif /* LWIP_IPV4 */ +}; + +#if LWIP_IGMP +/* Define the number of IPv4 multicast memberships, default is one per socket */ +#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS +#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS +#endif + +/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when + a socket is closed */ +struct lwip_socket_multicast_pair { + /** the socket */ + struct lwip_sock* sock; + /** the interface address */ + ip4_addr_t if_addr; + /** the group address */ + ip4_addr_t multi_addr; +}; + +struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; + +static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); +static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); +static void lwip_socket_drop_registered_memberships(int s); +#endif /* LWIP_IGMP */ + +/** The global array of available sockets */ +static struct lwip_sock sockets[NUM_SOCKETS]; +/** The global list of tasks waiting for select */ +static struct lwip_select_cb *select_cb_list; +/** This counter is increased from lwip_select when the list is changed + and checked in event_callback to see if it has changed. */ +static volatile int select_cb_ctr; + +#if LWIP_SOCKET_SET_ERRNO +#ifndef set_errno +#define set_errno(err) do { if (err) { errno = (err); } } while(0) +#endif +#else /* LWIP_SOCKET_SET_ERRNO */ +#define set_errno(err) +#endif /* LWIP_SOCKET_SET_ERRNO */ + +#define sock_set_errno(sk, e) do { \ + const int sockerr = (e); \ + sk->err = (u8_t)sockerr; \ + set_errno(sockerr); \ +} while (0) + +/* Forward declaration of some functions */ +static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +#if !LWIP_TCPIP_CORE_LOCKING +static void lwip_getsockopt_callback(void *arg); +static void lwip_setsockopt_callback(void *arg); +#endif +static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); +static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); + +#if LWIP_IPV4 && LWIP_IPV6 +static void +sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port) +{ + if ((sockaddr->sa_family) == AF_INET6) { + SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port); + ipaddr->type = IPADDR_TYPE_V6; + } else { + SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port); + ipaddr->type = IPADDR_TYPE_V4; + } +} +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void +lwip_socket_thread_init(void) +{ + netconn_thread_init(); +} + +/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ +void +lwip_socket_thread_cleanup(void) +{ + netconn_thread_cleanup(); +} + +/** + * Map a externally used socket index to the internal socket representation. + * + * @param s externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +get_socket(int s) +{ + struct lwip_sock *sock; + + s -= LWIP_SOCKET_OFFSET; + + if ((s < 0) || (s >= NUM_SOCKETS)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET)); + set_errno(EBADF); + return NULL; + } + + sock = &sockets[s]; + + if (!sock->conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET)); + set_errno(EBADF); + return NULL; + } + + return sock; +} + +/** + * Same as get_socket but doesn't set errno + * + * @param s externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +tryget_socket(int s) +{ + s -= LWIP_SOCKET_OFFSET; + if ((s < 0) || (s >= NUM_SOCKETS)) { + return NULL; + } + if (!sockets[s].conn) { + return NULL; + } + return &sockets[s]; +} + +/** + * Allocate a new socket for a given netconn. + * + * @param newconn the netconn for which to allocate a socket + * @param accepted 1 if socket has been created by accept(), + * 0 if socket has been created by socket() + * @return the index of the new socket; -1 on error + */ +static int +alloc_socket(struct netconn *newconn, int accepted) +{ + int i; + SYS_ARCH_DECL_PROTECT(lev); + + /* allocate a new socket identifier */ + for (i = 0; i < NUM_SOCKETS; ++i) { + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + if (!sockets[i].conn && (sockets[i].select_waiting == 0)) { + sockets[i].conn = newconn; + /* The socket is not yet known to anyone, so no need to protect + after having marked it as used. */ + SYS_ARCH_UNPROTECT(lev); + sockets[i].lastdata = NULL; + sockets[i].lastoffset = 0; + sockets[i].rcvevent = 0; + /* TCP sendbuf is empty, but the socket is not yet writable until connected + * (unless it has been created by accept()). */ + sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); + sockets[i].errevent = 0; + sockets[i].err = 0; + return i + LWIP_SOCKET_OFFSET; + } + SYS_ARCH_UNPROTECT(lev); + } + return -1; +} + +/** Free a socket. The socket's netconn must have been + * delete before! + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + */ +static void +free_socket(struct lwip_sock *sock, int is_tcp) +{ + void *lastdata; + + lastdata = sock->lastdata; + sock->lastdata = NULL; + sock->lastoffset = 0; + sock->err = 0; + + /* Protect socket array */ + SYS_ARCH_SET(sock->conn, NULL); + /* don't use 'sock' after this line, as another task might have allocated it */ + + if (lastdata != NULL) { + if (is_tcp) { + pbuf_free((struct pbuf *)lastdata); + } else { + netbuf_delete((struct netbuf *)lastdata); + } + } +} + +/* Below this, the well-known socket functions are implemented. + * Use google.com or opengroup.org to get a good description :-) + * + * Exceptions are documented! + */ + +int +lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + struct lwip_sock *sock, *nsock; + struct netconn *newconn; + ip_addr_t naddr; + u16_t port = 0; + int newsock; + err_t err; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); + set_errno(EWOULDBLOCK); + return -1; + } + + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + } else if (err == ERR_CLSD) { + sock_set_errno(sock, EINVAL); + } else { + sock_set_errno(sock, err_to_errno(err)); + } + return -1; + } + LWIP_ASSERT("newconn != NULL", newconn != NULL); + + newsock = alloc_socket(newconn, 1); + if (newsock == -1) { + netconn_delete(newconn); + sock_set_errno(sock, ENFILE); + return -1; + } + LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); + LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); + nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; + + /* See event_callback: If data comes in right away after an accept, even + * though the server task might not have created a new socket yet. + * In that case, newconn->socket is counted down (newconn->socket--), + * so nsock->rcvevent is >= 1 here! + */ + SYS_ARCH_PROTECT(lev); + nsock->rcvevent += (s16_t)(-1 - newconn->socket); + newconn->socket = newsock; + SYS_ARCH_UNPROTECT(lev); + + /* Note that POSIX only requires us to check addr is non-NULL. addrlen must + * not be NULL if addr is valid. + */ + if (addr != NULL) { + union sockaddr_aligned tempaddr; + /* get the IP address and port of the remote host */ + err = netconn_peer(newconn, &naddr, &port); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); + netconn_delete(newconn); + free_socket(nsock, 1); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); + + IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); + if (*addrlen > tempaddr.sa.sa_len) { + *addrlen = tempaddr.sa.sa_len; + } + MEMCPY(addr, &tempaddr, *addrlen); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); + ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); + } else { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); + } + + sock_set_errno(sock, 0); + return newsock; +} + +int +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + ip_addr_t local_addr; + u16_t local_port; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + + /* check size, family and alignment of 'name' */ + LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(namelen); + + SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); + IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + err = netconn_bind(sock->conn, &local_addr, local_port); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_close(int s) +{ + struct lwip_sock *sock; + int is_tcp = 0; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; + } else { + LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); + } + +#if LWIP_IGMP + /* drop all possibly joined IGMP memberships */ + lwip_socket_drop_registered_memberships(s); +#endif /* LWIP_IGMP */ + + err = netconn_delete(sock->conn); + if (err != ERR_OK) { + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + free_socket(sock, is_tcp); + set_errno(0); + return 0; +} + +int +lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct lwip_sock *sock; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + + LWIP_UNUSED_ARG(namelen); + if (name->sa_family == AF_UNSPEC) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); + err = netconn_disconnect(sock->conn); + } else { + ip_addr_t remote_addr; + u16_t remote_port; + + /* check size, family and alignment of 'name' */ + LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + + SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); + IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + err = netconn_connect(sock->conn, &remote_addr, remote_port); + } + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); + sock_set_errno(sock, 0); + return 0; +} + +/** + * Set a socket into listen mode. + * The socket may not have been used for another connection previously. + * + * @param s the socket to set to listening mode + * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) + * @return 0 on success, non-zero on failure + */ +int +lwip_listen(int s, int backlog) +{ + struct lwip_sock *sock; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* limit the "backlog" parameter to fit in an u8_t */ + backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); + + err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return -1; + } + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + struct lwip_sock *sock; + void *buf = NULL; + struct pbuf *p; + u16_t buflen, copylen; + int off = 0; + u8_t done = 0; + err_t err; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); + sock = get_socket(s); + if (!sock) { + return -1; + } + + do { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); + /* Check if there is data left from the last recv operation. */ + if (sock->lastdata) { + buf = sock->lastdata; + } else { + /* If this is non-blocking call, then check first */ + if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && + (sock->rcvevent <= 0)) { + if (off > 0) { + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); + set_errno(EWOULDBLOCK); + return -1; + } + + /* No data was left from the previous operation, so we try to get + some from the network. */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); + } else { + err = netconn_recv(sock->conn, (struct netbuf **)&buf); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", + err, buf)); + + if (err != ERR_OK) { + if (off > 0) { + if (err == ERR_CLSD) { + /* closed but already received data, ensure select gets the FIN, too */ + event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0); + } + /* already received data, return that */ + sock_set_errno(sock, 0); + return off; + } + /* We should really do some error checking here. */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", + s, lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + if (err == ERR_CLSD) { + return 0; + } else { + return -1; + } + } + LWIP_ASSERT("buf != NULL", buf != NULL); + sock->lastdata = buf; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + p = (struct pbuf *)buf; + } else { + p = ((struct netbuf *)buf)->p; + } + buflen = p->tot_len; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", + buflen, len, off, sock->lastoffset)); + + buflen -= sock->lastoffset; + + if (len > buflen) { + copylen = buflen; + } else { + copylen = (u16_t)len; + } + + /* copy the contents of the received buffer into + the supplied memory pointer mem */ + pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); + + off += copylen; + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); + len -= copylen; + if ((len <= 0) || + (p->flags & PBUF_FLAG_PUSH) || + (sock->rcvevent <= 0) || + ((flags & MSG_PEEK) != 0)) { + done = 1; + } + } else { + done = 1; + } + + /* Check to see from where the data was.*/ + if (done) { +#if !SOCKETS_DEBUG + if (from && fromlen) +#endif /* !SOCKETS_DEBUG */ + { + u16_t port; + ip_addr_t tmpaddr; + ip_addr_t *fromaddr; + union sockaddr_aligned saddr; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + fromaddr = &tmpaddr; + netconn_getaddr(sock->conn, fromaddr, &port, 0); + } else { + port = netbuf_fromport((struct netbuf *)buf); + fromaddr = netbuf_fromaddr((struct netbuf *)buf); + } + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ + if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) { + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); + IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); + ip_addr_debug_print(SOCKETS_DEBUG, fromaddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); +#if SOCKETS_DEBUG + if (from && fromlen) +#endif /* SOCKETS_DEBUG */ + { + if (*fromlen > saddr.sa.sa_len) { + *fromlen = saddr.sa.sa_len; + } + MEMCPY(from, &saddr, *fromlen); + } + } + } + + /* If we don't peek the incoming message... */ + if ((flags & MSG_PEEK) == 0) { + /* If this is a TCP socket, check if there is data left in the + buffer. If so, it should be saved in the sock structure for next + time around. */ + if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { + sock->lastdata = buf; + sock->lastoffset += copylen; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); + } else { + sock->lastdata = NULL; + sock->lastoffset = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + pbuf_free((struct pbuf *)buf); + } else { + netbuf_delete((struct netbuf *)buf); + } + buf = NULL; + } + } + } while (!done); + + sock_set_errno(sock, 0); + return off; +} + +int +lwip_read(int s, void *mem, size_t len) +{ + return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +int +lwip_recv(int s, void *mem, size_t len, int flags) +{ + return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +int +lwip_send(int s, const void *data, size_t size, int flags) +{ + struct lwip_sock *sock; + err_t err; + u8_t write_flags; + size_t written; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", + s, data, size, flags)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) + return lwip_sendto(s, data, size, flags, NULL, 0); +#else /* (LWIP_UDP || LWIP_RAW) */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* (LWIP_UDP || LWIP_RAW) */ + } + + write_flags = NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); + written = 0; + err = netconn_write_partly(sock->conn, data, size, write_flags, &written); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? (int)written : -1); +} + +int +lwip_sendmsg(int s, const struct msghdr *msg, int flags) +{ + struct lwip_sock *sock; + int i; +#if LWIP_TCP + u8_t write_flags; + size_t written; +#endif + int size = 0; + err_t err = ERR_OK; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + + LWIP_UNUSED_ARG(msg->msg_control); + LWIP_UNUSED_ARG(msg->msg_controllen); + LWIP_UNUSED_ARG(msg->msg_flags); + LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + write_flags = NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); + + for (i = 0; i < msg->msg_iovlen; i++) { + u8_t apiflags = write_flags; + if (i + 1 < msg->msg_iovlen) { + apiflags |= NETCONN_MORE; + } + written = 0; + err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written); + if (err == ERR_OK) { + size += written; + /* check that the entire IO vector was accepected, if not return a partial write */ + if (written != msg->msg_iov[i].iov_len) + break; + } + /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */ + else if (err == ERR_WOULDBLOCK && size > 0) { + err = ERR_OK; + /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */ + break; + } else { + size = -1; + break; + } + } + sock_set_errno(sock, err_to_errno(err)); + return size; +#else /* LWIP_TCP */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* LWIP_TCP */ + } + /* else, UDP and RAW NETCONNs */ +#if LWIP_UDP || LWIP_RAW + { + struct netbuf *chain_buf; + + LWIP_UNUSED_ARG(flags); + LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || + IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) , + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + + /* initialize chain buffer with destination */ + chain_buf = netbuf_new(); + if (!chain_buf) { + sock_set_errno(sock, err_to_errno(ERR_MEM)); + return -1; + } + if (msg->msg_name) { + u16_t remote_port; + SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port); + netbuf_fromport(chain_buf) = remote_port; + } +#if LWIP_NETIF_TX_SINGLE_PBUF + for (i = 0; i < msg->msg_iovlen; i++) { + size += msg->msg_iov[i].iov_len; + } + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) { + err = ERR_MEM; + } else { + /* flatten the IO vectors */ + size_t offset = 0; + for (i = 0; i < msg->msg_iovlen; i++) { + MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); + offset += msg->msg_iov[i].iov_len; + } +#if LWIP_CHECKSUM_ON_COPY + { + /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ + u16_t chksum = ~inet_chksum_pbuf(chain_buf->p); + netbuf_set_chksum(chain_buf, chksum); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + err = ERR_OK; + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain + manually to avoid having to allocate, chain, and delete a netbuf for each iov */ + for (i = 0; i < msg->msg_iovlen; i++) { + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); + if (p == NULL) { + err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ + break; + } + p->payload = msg->msg_iov[i].iov_base; + LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF); + p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; + /* netbuf empty, add new pbuf */ + if (chain_buf->p == NULL) { + chain_buf->p = chain_buf->ptr = p; + /* add pbuf to existing pbuf chain */ + } else { + pbuf_cat(chain_buf->p, p); + } + } + /* save size of total chain */ + if (err == ERR_OK) { + size = netbuf_len(chain_buf); + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + if (err == ERR_OK) { +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf->addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr)); + IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* send the data */ + err = netconn_send(sock->conn, chain_buf); + } + + /* deallocated the buffer */ + netbuf_delete(chain_buf); + + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? size : -1); + } +#else /* LWIP_UDP || LWIP_RAW */ + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* LWIP_UDP || LWIP_RAW */ +} + +int +lwip_sendto(int s, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + struct lwip_sock *sock; + err_t err; + u16_t short_size; + u16_t remote_port; + struct netbuf buf; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +#if LWIP_TCP + return lwip_send(s, data, size, flags); +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(flags); + sock_set_errno(sock, err_to_errno(ERR_ARG)); + return -1; +#endif /* LWIP_TCP */ + } + + /* @todo: split into multiple sendto's? */ + LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); + short_size = (u16_t)size; + LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || + (IS_SOCK_ADDR_LEN_VALID(tolen) && + IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), + sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(tolen); + + /* initialize a buffer */ + buf.p = buf.ptr = NULL; +#if LWIP_CHECKSUM_ON_COPY + buf.flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ + if (to) { + SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); + } else { + remote_port = 0; + ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); + } + netbuf_fromport(&buf) = remote_port; + + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", + s, data, short_size, flags)); + ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + + /* make the buffer point to the data that should be sent */ +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Allocate a new netbuf and copy the data into it. */ + if (netbuf_alloc(&buf, short_size) == NULL) { + err = ERR_MEM; + } else { +#if LWIP_CHECKSUM_ON_COPY + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { + u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); + netbuf_set_chksum(&buf, chksum); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + MEMCPY(buf.p->payload, data, short_size); + } + err = ERR_OK; + } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (err == ERR_OK) { +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); + IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* send the data */ + err = netconn_send(sock->conn, &buf); + } + + /* deallocated the buffer */ + netbuf_free(&buf); + + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? short_size : -1); +} + +int +lwip_socket(int domain, int type, int protocol) +{ + struct netconn *conn; + int i; + + LWIP_UNUSED_ARG(domain); /* @todo: check this */ + + /* create a netconn */ + switch (type) { + case SOCK_RAW: + conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), + (u8_t)protocol, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_DGRAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , + event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + case SOCK_STREAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", + domain, type, protocol)); + set_errno(EINVAL); + return -1; + } + + if (!conn) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); + set_errno(ENOBUFS); + return -1; + } + + i = alloc_socket(conn, 0); + + if (i == -1) { + netconn_delete(conn); + set_errno(ENFILE); + return -1; + } + conn->socket = i; + LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); + set_errno(0); + return i; +} + +int +lwip_write(int s, const void *data, size_t size) +{ + return lwip_send(s, data, size, 0); +} + +int +lwip_writev(int s, const struct iovec *iov, int iovcnt) +{ + struct msghdr msg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Hack: we have to cast via number to cast from 'const' pointer to non-const. + Blame the opengroup standard for this inconsistency. */ + msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); + msg.msg_iovlen = iovcnt; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + return lwip_sendmsg(s, &msg, 0); +} + +/** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have + * the sockets enabled that had events. + * + * @param maxfdp1 the highest socket index in the sets + * @param readset_in set of sockets to check for read events + * @param writeset_in set of sockets to check for write events + * @param exceptset_in set of sockets to check for error events + * @param readset_out set of sockets that had read events + * @param writeset_out set of sockets that had write events + * @param exceptset_out set os sockets that had error events + * @return number of sockets that had events (read/write/exception) (>= 0) + */ +static int +lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, + fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) +{ + int i, nready = 0; + fd_set lreadset, lwriteset, lexceptset; + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + + FD_ZERO(&lreadset); + FD_ZERO(&lwriteset); + FD_ZERO(&lexceptset); + + /* Go through each socket in each list to count number of sockets which + currently match */ + for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { + /* if this FD is not in the set, continue */ + if (!(readset_in && FD_ISSET(i, readset_in)) && + !(writeset_in && FD_ISSET(i, writeset_in)) && + !(exceptset_in && FD_ISSET(i, exceptset_in))) { + continue; + } + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket(i); + if (sock != NULL) { + void* lastdata = sock->lastdata; + s16_t rcvevent = sock->rcvevent; + u16_t sendevent = sock->sendevent; + u16_t errevent = sock->errevent; + SYS_ARCH_UNPROTECT(lev); + + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { + FD_SET(i, &lreadset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); + nready++; + } + /* See if netconn of this socket is ready for write */ + if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { + FD_SET(i, &lwriteset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); + nready++; + } + /* See if netconn of this socket had an error */ + if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; + } + } else { + SYS_ARCH_UNPROTECT(lev); + /* continue on to next FD in list */ + } + } + /* copy local sets to the ones provided as arguments */ + *readset_out = lreadset; + *writeset_out = lwriteset; + *exceptset_out = lexceptset; + + LWIP_ASSERT("nready >= 0", nready >= 0); + return nready; +} + +int +lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout) +{ + u32_t waitres = 0; + int nready; + fd_set lreadset, lwriteset, lexceptset; + u32_t msectimeout; + struct lwip_select_cb select_cb; + int i; + int maxfdp2; +#if LWIP_NETCONN_SEM_PER_THREAD + int waited = 0; +#endif + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", + maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, + timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, + timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); + + /* Go through each socket in each list to count number of sockets which + currently match */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + + /* If we don't have any current events, then suspend if we are supposed to */ + if (!nready) { + if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; + } + + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables. */ + + select_cb.next = NULL; + select_cb.prev = NULL; + select_cb.readset = readset; + select_cb.writeset = writeset; + select_cb.exceptset = exceptset; + select_cb.sem_signalled = 0; +#if LWIP_NETCONN_SEM_PER_THREAD + select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) { + /* failed to create semaphore */ + set_errno(ENOMEM); + return -1; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + /* Protect the select_cb_list */ + SYS_ARCH_PROTECT(lev); + + /* Put this select_cb on top of list */ + select_cb.next = select_cb_list; + if (select_cb_list != NULL) { + select_cb_list->prev = &select_cb; + } + select_cb_list = &select_cb; + /* Increasing this counter tells event_callback that the list has changed. */ + select_cb_ctr++; + + /* Now we can safely unprotect */ + SYS_ARCH_UNPROTECT(lev); + + /* Increase select_waiting for each socket we are interested in */ + maxfdp2 = maxfdp1; + for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock; + SYS_ARCH_PROTECT(lev); + sock = tryget_socket(i); + if (sock != NULL) { + sock->select_waiting++; + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + } else { + /* Not a valid socket */ + nready = -1; + maxfdp2 = i; + SYS_ARCH_UNPROTECT(lev); + break; + } + SYS_ARCH_UNPROTECT(lev); + } + } + + if (nready >= 0) { + /* Call lwip_selscan again: there could have been events between + the last scan (without us on the list) and putting us on the list! */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout == 0) { + /* Wait forever */ + msectimeout = 0; + } else { + msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); + if (msectimeout == 0) { + /* Wait 1ms at least (0 means wait forever) */ + msectimeout = 1; + } + } + + waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout); +#if LWIP_NETCONN_SEM_PER_THREAD + waited = 1; +#endif + } + } + + /* Decrease select_waiting for each socket we are interested in */ + for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock; + SYS_ARCH_PROTECT(lev); + sock = tryget_socket(i); + if (sock != NULL) { + /* for now, handle select_waiting==0... */ + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + if (sock->select_waiting > 0) { + sock->select_waiting--; + } + } else { + /* Not a valid socket */ + nready = -1; + } + SYS_ARCH_UNPROTECT(lev); + } + } + /* Take us off the list */ + SYS_ARCH_PROTECT(lev); + if (select_cb.next != NULL) { + select_cb.next->prev = select_cb.prev; + } + if (select_cb_list == &select_cb) { + LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); + select_cb_list = select_cb.next; + } else { + LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); + select_cb.prev->next = select_cb.next; + } + /* Increasing this counter tells event_callback that the list has changed. */ + select_cb_ctr++; + SYS_ARCH_UNPROTECT(lev); + +#if LWIP_NETCONN_SEM_PER_THREAD + if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { + /* don't leave the thread-local semaphore signalled */ + sys_arch_sem_wait(select_cb.sem, 1); + } +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_sem_free(&select_cb.sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + if (nready < 0) { + /* This happens when a socket got closed while waiting */ + set_errno(EBADF); + return -1; + } + + if (waitres == SYS_ARCH_TIMEOUT) { + /* Timeout */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; + } + + /* See what's set */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); +return_copy_fdsets: + set_errno(0); + if (readset) { + *readset = lreadset; + } + if (writeset) { + *writeset = lwriteset; + } + if (exceptset) { + *exceptset = lexceptset; + } + return nready; +} + +/** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. + */ +static void +event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) +{ + int s; + struct lwip_sock *sock; + struct lwip_select_cb *scb; + int last_select_cb_ctr; + SYS_ARCH_DECL_PROTECT(lev); + + LWIP_UNUSED_ARG(len); + + /* Get socket */ + if (conn) { + s = conn->socket; + if (s < 0) { + /* Data comes in right away after an accept, even though + * the server task might not have created a new socket yet. + * Just count down (or up) if that's the case and we + * will use the data later. Note that only receive events + * can happen before the new socket is set up. */ + SYS_ARCH_PROTECT(lev); + if (conn->socket < 0) { + if (evt == NETCONN_EVT_RCVPLUS) { + conn->socket--; + } + SYS_ARCH_UNPROTECT(lev); + return; + } + s = conn->socket; + SYS_ARCH_UNPROTECT(lev); + } + + sock = get_socket(s); + if (!sock) { + return; + } + } else { + return; + } + + SYS_ARCH_PROTECT(lev); + /* Set event as required */ + switch (evt) { + case NETCONN_EVT_RCVPLUS: + sock->rcvevent++; + break; + case NETCONN_EVT_RCVMINUS: + sock->rcvevent--; + break; + case NETCONN_EVT_SENDPLUS: + sock->sendevent = 1; + break; + case NETCONN_EVT_SENDMINUS: + sock->sendevent = 0; + break; + case NETCONN_EVT_ERROR: + sock->errevent = 1; + break; + default: + LWIP_ASSERT("unknown event", 0); + break; + } + + if (sock->select_waiting == 0) { + /* noone is waiting for this socket, no need to check select_cb_list */ + SYS_ARCH_UNPROTECT(lev); + return; + } + + /* Now decide if anyone is waiting for this socket */ + /* NOTE: This code goes through the select_cb_list list multiple times + ONLY IF a select was actually waiting. We go through the list the number + of waiting select calls + 1. This list is expected to be small. */ + + /* At this point, SYS_ARCH is still protected! */ +again: + for (scb = select_cb_list; scb != NULL; scb = scb->next) { + /* remember the state of select_cb_list to detect changes */ + last_select_cb_ctr = select_cb_ctr; + if (scb->sem_signalled == 0) { + /* semaphore not signalled yet */ + int do_signal = 0; + /* Test this select call for our socket */ + if (sock->rcvevent > 0) { + if (scb->readset && FD_ISSET(s, scb->readset)) { + do_signal = 1; + } + } + if (sock->sendevent != 0) { + if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { + do_signal = 1; + } + } + if (sock->errevent != 0) { + if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { + do_signal = 1; + } + } + if (do_signal) { + scb->sem_signalled = 1; + /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might + lead to the select thread taking itself off the list, invalidating the semaphore. */ + sys_sem_signal(SELECT_SEM_PTR(scb->sem)); + } + } + /* unlock interrupts with each step */ + SYS_ARCH_UNPROTECT(lev); + /* this makes sure interrupt protection time is short */ + SYS_ARCH_PROTECT(lev); + if (last_select_cb_ctr != select_cb_ctr) { + /* someone has changed select_cb_list, restart at the beginning */ + goto again; + } + } + SYS_ARCH_UNPROTECT(lev); +} + +/** + * Close one end of a full-duplex connection. + */ +int +lwip_shutdown(int s, int how) +{ + struct lwip_sock *sock; + err_t err; + u8_t shut_rx = 0, shut_tx = 0; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return -1; + } + } else { + sock_set_errno(sock, ENOTCONN); + return -1; + } + + if (how == SHUT_RD) { + shut_rx = 1; + } else if (how == SHUT_WR) { + shut_tx = 1; + } else if (how == SHUT_RDWR) { + shut_rx = 1; + shut_tx = 1; + } else { + sock_set_errno(sock, EINVAL); + return -1; + } + err = netconn_shutdown(sock->conn, shut_rx, shut_tx); + + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? 0 : -1); +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ + struct lwip_sock *sock; + union sockaddr_aligned saddr; + ip_addr_t naddr; + u16_t port; + err_t err; + + sock = get_socket(s); + if (!sock) { + return -1; + } + + /* get the IP address and port */ + err = netconn_getaddr(sock->conn, &naddr, &port, local); + if (err != ERR_OK) { + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ + if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && + IP_IS_V4_VAL(naddr)) { + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); + IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); + + if (*namelen > saddr.sa.sa_len) { + *namelen = saddr.sa.sa_len; + } + MEMCPY(name, &saddr, *namelen); + + sock_set_errno(sock, 0); + return 0; +} + +int +lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 0); +} + +int +lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lwip_getaddrname(s, name, namelen, 1); +} + +int +lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + u8_t err; + struct lwip_sock *sock = get_socket(s); +#if !LWIP_TCPIP_CORE_LOCKING + LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + + if (!sock) { + return -1; + } + + if ((NULL == optval) || (NULL == optlen)) { + sock_set_errno(sock, EFAULT); + return -1; + } + +#if LWIP_TCPIP_CORE_LOCKING + /* core-locking can just call the -impl function */ + LOCK_TCPIP_CORE(); + err = lwip_getsockopt_impl(s, level, optname, optval, optlen); + UNLOCK_TCPIP_CORE(); + +#else /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_MPU_COMPATIBLE + /* MPU_COMPATIBLE copies the optval data, so check for max size here */ + if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { + sock_set_errno(sock, ENOBUFS); + return -1; + } +#endif /* LWIP_MPU_COMPATIBLE */ + + LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; +#if !LWIP_MPU_COMPATIBLE + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; +#endif /* !LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; +#if LWIP_NETCONN_SEM_PER_THREAD + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; +#endif + err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); + if (err != ERR_OK) { + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); + + /* write back optlen and optval */ + *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; +#if LWIP_MPU_COMPATIBLE + MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); +#endif /* LWIP_MPU_COMPATIBLE */ + + /* maybe lwip_getsockopt_internal has changed err */ + err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sock_set_errno(sock, err); + return err ? -1 : 0; +} + +#if !LWIP_TCPIP_CORE_LOCKING +/** lwip_getsockopt_callback: only used without CORE_LOCKING + * to get into the tcpip_thread + */ +static void +lwip_getsockopt_callback(void *arg) +{ + struct lwip_setgetsockopt_data *data; + LWIP_ASSERT("arg != NULL", arg != NULL); + data = (struct lwip_setgetsockopt_data*)arg; + + data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, +#if LWIP_MPU_COMPATIBLE + data->optval, +#else /* LWIP_MPU_COMPATIBLE */ + data->optval.p, +#endif /* LWIP_MPU_COMPATIBLE */ + &data->optlen); + + sys_sem_signal((sys_sem_t*)(data->completed_sem)); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** lwip_getsockopt_impl: the actual implementation of getsockopt: + * same argument as lwip_getsockopt, either called directly or through callback + */ +static u8_t +lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + u8_t err = 0; + struct lwip_sock *sock = tryget_socket(s); + if (!sock) { + return EBADF; + } + + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + +#if LWIP_TCP + case SO_ACCEPTCONN: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { + return ENOPROTOOPT; + } + if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { + *(int*)optval = 1; + } else { + *(int*)optval = 0; + } + break; +#endif /* LWIP_TCP */ + + /* The option flags */ + case SO_BROADCAST: + case SO_KEEPALIVE: +#if SO_REUSE + case SO_REUSEADDR: +#endif /* SO_REUSE */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", + s, optname, (*(int*)optval?"on":"off"))); + break; + + case SO_TYPE: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { + case NETCONN_RAW: + *(int*)optval = SOCK_RAW; + break; + case NETCONN_TCP: + *(int*)optval = SOCK_STREAM; + break; + case NETCONN_UDP: + *(int*)optval = SOCK_DGRAM; + break; + default: /* unrecognized socket type */ + *(int*)optval = netconn_type(sock->conn); + LWIP_DEBUGF(SOCKETS_DEBUG, + ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", + s, *(int *)optval)); + } /* switch (netconn_type(sock->conn)) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", + s, *(int *)optval)); + break; + + case SO_ERROR: + LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int); + /* only overwrite ERR_OK or temporary errors */ + if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) { + sock_set_errno(sock, err_to_errno(sock->conn->last_err)); + } + *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err); + sock->err = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); + break; +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); + break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + *(int *)optval = netconn_get_recvbufsize(sock->conn); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + case SO_LINGER: + { + s16_t conn_linger; + struct linger* linger = (struct linger*)optval; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); + conn_linger = sock->conn->linger; + if (conn_linger >= 0) { + linger->l_onoff = 1; + linger->l_linger = (int)conn_linger; + } else { + linger->l_onoff = 0; + linger->l_linger = 0; + } + } + break; +#endif /* LWIP_SO_LINGER */ +#if LWIP_UDP + case SO_NO_CHECK: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); +#if LWIP_UDPLITE + if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { + /* this flag is only available for UDP, not for UDP lite */ + return EAFNOSUPPORT; + } +#endif /* LWIP_UDPLITE */ + *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; + break; +#endif /* LWIP_UDP*/ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int*)optval = sock->conn->pcb.ip->ttl; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_TOS: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + *(int*)optval = sock->conn->pcb.ip->tos; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", + s, *(int *)optval)); + break; +#if LWIP_MULTICAST_TX_OPTIONS + case IP_MULTICAST_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + return ENOPROTOOPT; + } + *(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", + s, *(int *)optval)); + break; + case IP_MULTICAST_IF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + return ENOPROTOOPT; + } + inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", + s, *(u32_t *)optval)); + break; + case IP_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t*)optval = 1; + } else { + *(u8_t*)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + /* Special case: all IPPROTO_TCP option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); + if (sock->conn->pcb.tcp->state == LISTEN) { + return EINVAL; + } + switch (optname) { + case TCP_NODELAY: + *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", + s, (*(int*)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", + s, *(int *)optval)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPINTVL: + *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", + s, *(int *)optval)); + break; + case TCP_KEEPCNT: + *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", + s, *(int *)optval)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", + s, *(int *)optval)); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + /* Special case: all IPPROTO_UDPLITE option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); + /* If this is no UDP lite socket, ignore any options. */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { + return ENOPROTOOPT; + } + switch (optname) { + case UDPLITE_SEND_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + /* Level: IPPROTO_RAW */ + case IPPROTO_RAW: + switch (optname) { +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); + if (sock->conn->pcb.raw->chksum_reqd == 0) { + *(int *)optval = -1; + } else { + *(int *)optval = sock->conn->pcb.raw->chksum_offset; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", + s, (*(int*)optval)) ); + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + break; + } /* switch (level) */ + + return err; +} + +int +lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + u8_t err = 0; + struct lwip_sock *sock = get_socket(s); +#if !LWIP_TCPIP_CORE_LOCKING + LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + + if (!sock) { + return -1; + } + + if (NULL == optval) { + sock_set_errno(sock, EFAULT); + return -1; + } + +#if LWIP_TCPIP_CORE_LOCKING + /* core-locking can just call the -impl function */ + LOCK_TCPIP_CORE(); + err = lwip_setsockopt_impl(s, level, optname, optval, optlen); + UNLOCK_TCPIP_CORE(); + +#else /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_MPU_COMPATIBLE + /* MPU_COMPATIBLE copies the optval data, so check for max size here */ + if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { + sock_set_errno(sock, ENOBUFS); + return -1; + } +#endif /* LWIP_MPU_COMPATIBLE */ + + LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; +#if LWIP_MPU_COMPATIBLE + MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); +#else /* LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval; +#endif /* LWIP_MPU_COMPATIBLE */ + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; +#if LWIP_NETCONN_SEM_PER_THREAD + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else + LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; +#endif + err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); + if (err != ERR_OK) { + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } + sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); + + /* maybe lwip_getsockopt_internal has changed err */ + err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sock_set_errno(sock, err); + return err ? -1 : 0; +} + +#if !LWIP_TCPIP_CORE_LOCKING +/** lwip_setsockopt_callback: only used without CORE_LOCKING + * to get into the tcpip_thread + */ +static void +lwip_setsockopt_callback(void *arg) +{ + struct lwip_setgetsockopt_data *data; + LWIP_ASSERT("arg != NULL", arg != NULL); + data = (struct lwip_setgetsockopt_data*)arg; + + data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, +#if LWIP_MPU_COMPATIBLE + data->optval, +#else /* LWIP_MPU_COMPATIBLE */ + data->optval.pc, +#endif /* LWIP_MPU_COMPATIBLE */ + data->optlen); + + sys_sem_signal((sys_sem_t*)(data->completed_sem)); +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** lwip_setsockopt_impl: the actual implementation of setsockopt: + * same argument as lwip_setsockopt, either called directly or through callback + */ +static u8_t +lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + u8_t err = 0; + struct lwip_sock *sock = tryget_socket(s); + if (!sock) { + return EBADF; + } + + switch (level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch (optname) { + + /* SO_ACCEPTCONN is get-only */ + + /* The option flags */ + case SO_BROADCAST: + case SO_KEEPALIVE: +#if SO_REUSE + case SO_REUSEADDR: +#endif /* SO_REUSE */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + if (*(const int*)optval) { + ip_set_option(sock->conn->pcb.ip, optname); + } else { + ip_reset_option(sock->conn->pcb.ip, optname); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", + s, optname, (*(const int*)optval?"on":"off"))); + break; + + /* SO_TYPE is get-only */ + /* SO_ERROR is get-only */ + +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); + break; +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO + case SO_RCVTIMEO: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); + netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval)); + break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + case SO_RCVBUF: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); + netconn_set_recvbufsize(sock->conn, *(const int*)optval); + break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + case SO_LINGER: + { + const struct linger* linger = (const struct linger*)optval; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); + if (linger->l_onoff) { + int lingersec = linger->l_linger; + if (lingersec < 0) { + return EINVAL; + } + if (lingersec > 0xFFFF) { + lingersec = 0xFFFF; + } + sock->conn->linger = (s16_t)lingersec; + } else { + sock->conn->linger = -1; + } + } + break; +#endif /* LWIP_SO_LINGER */ +#if LWIP_UDP + case SO_NO_CHECK: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); +#if LWIP_UDPLITE + if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) { + /* this flag is only available for UDP, not for UDP lite */ + return EAFNOSUPPORT; + } +#endif /* LWIP_UDPLITE */ + if (*(const int*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); + } + break; +#endif /* LWIP_UDP */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch (optname) { + case IP_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", + s, sock->conn->pcb.ip->ttl)); + break; + case IP_TOS: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", + s, sock->conn->pcb.ip->tos)); + break; +#if LWIP_MULTICAST_TX_OPTIONS + case IP_MULTICAST_TTL: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval)); + break; + case IP_MULTICAST_IF: + { + ip4_addr_t if_addr; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); + inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval); + udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); + } + break; + case IP_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + if (*(const u8_t*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); + } + break; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#if LWIP_IGMP + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { + /* If this is a TCP or a RAW socket, ignore these options. */ + /* @todo: assign membership to this socket so that it is dropped when closing the socket */ + err_t igmp_err; + const struct ip_mreq *imr = (const struct ip_mreq *)optval; + ip4_addr_t if_addr; + ip4_addr_t multi_addr; + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); + inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); + inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); + if (optname == IP_ADD_MEMBERSHIP) { + if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { + /* cannot track membership (out of memory) */ + err = ENOMEM; + igmp_err = ERR_OK; + } else { + igmp_err = igmp_joingroup(&if_addr, &multi_addr); + } + } else { + igmp_err = igmp_leavegroup(&if_addr, &multi_addr); + lwip_socket_unregister_membership(s, &if_addr, &multi_addr); + } + if (igmp_err != ERR_OK) { + err = EADDRNOTAVAIL; + } + } + break; +#endif /* LWIP_IGMP */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + /* Special case: all IPPROTO_TCP option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); + if (sock->conn->pcb.tcp->state == LISTEN) { + return EINVAL; + } + switch (optname) { + case TCP_NODELAY: + if (*(const int*)optval) { + tcp_nagle_disable(sock->conn->pcb.tcp); + } else { + tcp_nagle_enable(sock->conn->pcb.tcp); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", + s, (*(const int *)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + +#if LWIP_TCP_KEEPALIVE + case TCP_KEEPIDLE: + sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_idle)); + break; + case TCP_KEEPINTVL: + sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_intvl)); + break; + case TCP_KEEPCNT: + sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", + s, sock->conn->pcb.tcp->keep_cnt)); + break; +#endif /* LWIP_TCP_KEEPALIVE */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_TCP*/ + +#if LWIP_IPV6 +/* Level: IPPROTO_IPV6 */ + case IPPROTO_IPV6: + switch (optname) { + case IPV6_V6ONLY: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); + if (*(const int*)optval) { + netconn_set_ipv6only(sock->conn, 1); + } else { + netconn_set_ipv6only(sock->conn, 0); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", + s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + /* Special case: all IPPROTO_UDPLITE option take an int */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); + /* If this is no UDP lite socket, ignore any options. */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { + return ENOPROTOOPT; + } + switch (optname) { + case UDPLITE_SEND_CSCOV: + if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_tx = 8; + } else { + sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", + s, (*(const int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_rx = 8; + } else { + sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", + s, (*(const int*)optval)) ); + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ + /* Level: IPPROTO_RAW */ + case IPPROTO_RAW: + switch (optname) { +#if LWIP_IPV6 && LWIP_RAW + case IPV6_CHECKSUM: + /* It should not be possible to disable the checksum generation with ICMPv6 + * as per RFC 3542 chapter 3.1 */ + if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { + return EINVAL; + } + + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); + if (*(const int *)optval < 0) { + sock->conn->pcb.raw->chksum_reqd = 0; + } else if (*(const int *)optval & 1) { + /* Per RFC3542, odd offsets are not allowed */ + return EINVAL; + } else { + sock->conn->pcb.raw->chksum_reqd = 1; + sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", + s, sock->conn->pcb.raw->chksum_reqd)); + break; +#endif /* LWIP_IPV6 && LWIP_RAW */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + break; + } /* switch (optname) */ + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", + s, level, optname)); + err = ENOPROTOOPT; + break; + } /* switch (level) */ + + return err; +} + +int +lwip_ioctl(int s, long cmd, void *argp) +{ + struct lwip_sock *sock = get_socket(s); + u8_t val; +#if LWIP_SO_RCVBUF + u16_t buflen = 0; + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + + if (!sock) { + return -1; + } + + switch (cmd) { +#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE + case FIONREAD: + if (!argp) { + sock_set_errno(sock, EINVAL); + return -1; + } +#if LWIP_FIONREAD_LINUXMODE + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + struct pbuf *p; + if (sock->lastdata) { + p = ((struct netbuf *)sock->lastdata)->p; + *((int*)argp) = p->tot_len - sock->lastoffset; + } else { + struct netbuf *rxbuf; + err_t err; + if (sock->rcvevent <= 0) { + *((int*)argp) = 0; + } else { + err = netconn_recv(sock->conn, &rxbuf); + if (err != ERR_OK) { + *((int*)argp) = 0; + } else { + sock->lastdata = rxbuf; + sock->lastoffset = 0; + *((int*)argp) = rxbuf->p->tot_len; + } + } + } + return 0; + } +#endif /* LWIP_FIONREAD_LINUXMODE */ + +#if LWIP_SO_RCVBUF + /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ + SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); + if (recv_avail < 0) { + recv_avail = 0; + } + *((int*)argp) = recv_avail; + + /* Check if there is data left from the last recv operation. /maq 041215 */ + if (sock->lastdata) { + struct pbuf *p = (struct pbuf *)sock->lastdata; + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + p = ((struct netbuf *)p)->p; + } + buflen = p->tot_len; + buflen -= sock->lastoffset; + + *((int*)argp) += buflen; + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); + sock_set_errno(sock, 0); + return 0; +#else /* LWIP_SO_RCVBUF */ + break; +#endif /* LWIP_SO_RCVBUF */ +#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ + + case (long)FIONBIO: + val = 0; + if (argp && *(u32_t*)argp) { + val = 1; + } + netconn_set_nonblocking(sock->conn, val); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); + sock_set_errno(sock, 0); + return 0; + + default: + break; + } /* switch (cmd) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + return -1; +} + +/** A minimal implementation of fcntl. + * Currently only the commands F_GETFL and F_SETFL are implemented. + * Only the flag O_NONBLOCK is implemented. + */ +int +lwip_fcntl(int s, int cmd, int val) +{ + struct lwip_sock *sock = get_socket(s); + int ret = -1; + + if (!sock) { + return -1; + } + + switch (cmd) { + case F_GETFL: + ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; + sock_set_errno(sock, 0); + break; + case F_SETFL: + if ((val & ~O_NONBLOCK) == 0) { + /* only O_NONBLOCK, all other bits are zero */ + netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); + ret = 0; + sock_set_errno(sock, 0); + } else { + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + break; + } + return ret; +} + +#if LWIP_IGMP +/** Register a new IGMP membership. On socket close, the membership is dropped automatically. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + * + * @return 1 on success, 0 on failure + */ +static int +lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return 0; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv4_multicast_memberships[i].sock == NULL) { + socket_ipv4_multicast_memberships[i].sock = sock; + ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); + ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); + return 1; + } + } + return 0; +} + +/** Unregister a previously registered membership. This prevents dropping the membership + * on socket close. + * + * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if ((socket_ipv4_multicast_memberships[i].sock == sock) && + ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && + ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { + socket_ipv4_multicast_memberships[i].sock = NULL; + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); + return; + } + } +} + +/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. + * + * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). + */ +static void +lwip_socket_drop_registered_memberships(int s) +{ + struct lwip_sock *sock = get_socket(s); + int i; + + if (!sock) { + return; + } + + for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { + if (socket_ipv4_multicast_memberships[i].sock == sock) { + ip_addr_t multi_addr, if_addr; + ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); + ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); + socket_ipv4_multicast_memberships[i].sock = NULL; + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); + ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); + + netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); + } + } +} +#endif /* LWIP_IGMP */ +#endif /* LWIP_SOCKET */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/api/tcpip.c b/Sming/third-party/lwip2/lwip2-src/src/api/tcpip.c new file mode 100644 index 0000000000..07b2f98434 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/api/tcpip.c @@ -0,0 +1,518 @@ +/** + * @file + * Sequential API Main thread module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcpip_priv.h" +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/mem.h" +#include "lwip/init.h" +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/etharp.h" +#include "netif/ethernet.h" + +#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) +#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) +#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) +#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) + +/* global variables */ +static tcpip_init_done_fn tcpip_init_done; +static void *tcpip_init_done_arg; +static sys_mbox_t mbox; + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +sys_mutex_t lock_tcpip_core; +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_TIMERS +/* wait for a message, timeouts are processed while waiting */ +#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg) +#else /* LWIP_TIMERS */ +/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ +#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) +#endif /* LWIP_TIMERS */ + +/** + * The main lwIP thread. This thread has exclusive access to lwIP core functions + * (unless access to them is not locked). Other threads communicate with this + * thread using message boxes. + * + * It also starts all the timers to make sure they are running in the right + * thread context. + * + * @param arg unused argument + */ +static void +tcpip_thread(void *arg) +{ + struct tcpip_msg *msg; + LWIP_UNUSED_ARG(arg); + + if (tcpip_init_done != NULL) { + tcpip_init_done(tcpip_init_done_arg); + } + + LOCK_TCPIP_CORE(); + while (1) { /* MAIN Loop */ + UNLOCK_TCPIP_CORE(); + LWIP_TCPIP_THREAD_ALIVE(); + /* wait for a message, timeouts are processed while waiting */ + TCPIP_MBOX_FETCH(&mbox, (void **)&msg); + LOCK_TCPIP_CORE(); + if (msg == NULL) { + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + continue; + } + switch (msg->type) { +#if !LWIP_TCPIP_CORE_LOCKING + case TCPIP_MSG_API: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); + msg->msg.api_msg.function(msg->msg.api_msg.msg); + break; + case TCPIP_MSG_API_CALL: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); + msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); + sys_sem_signal(msg->msg.api_call.sem); + break; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + +#if !LWIP_TCPIP_CORE_LOCKING_INPUT + case TCPIP_MSG_INPKT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); + msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + break; +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + case TCPIP_MSG_TIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); + sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + case TCPIP_MSG_UNTIMEOUT: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); + sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + + case TCPIP_MSG_CALLBACK: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + memp_free(MEMP_TCPIP_MSG_API, msg); + break; + + case TCPIP_MSG_CALLBACK_STATIC: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); + msg->msg.cb.function(msg->msg.cb.ctx); + break; + + default: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); + LWIP_ASSERT("tcpip_thread: invalid message", 0); + break; + } + } +} + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet + * @param inp the network interface on which the packet was received + * @param input_fn input function to call + */ +err_t +tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) +{ +#if LWIP_TCPIP_CORE_LOCKING_INPUT + err_t ret; + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); + LOCK_TCPIP_CORE(); + ret = input_fn(p, inp); + UNLOCK_TCPIP_CORE(); + return ret; +#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_INPKT; + msg->msg.inp.p = p; + msg->msg.inp.netif = inp; + msg->msg.inp.input_fn = input_fn; + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + return ERR_MEM; + } + return ERR_OK; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ +} + +/** + * @ingroup lwip_os + * Pass a received packet to tcpip_thread for input processing with + * ethernet_input or ip_input. Don't call directly, pass to netif_add() + * and call netif->input(). + * + * @param p the received packet, p->payload pointing to the Ethernet header or + * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or + * NETIF_FLAG_ETHERNET flags) + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + return tcpip_inpkt(p, inp, ethernet_input); + } else +#endif /* LWIP_ETHERNET */ + return tcpip_inpkt(p, inp, ip_input); +} + +/** + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * + * @param function the function to call + * @param ctx parameter passed to f + * @param block 1 to block until the request is posted, 0 to non-blocking mode + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_CALLBACK; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + if (block) { + sys_mbox_post(&mbox, msg); + } else { + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_API, msg); + return ERR_MEM; + } + } + return ERR_OK; +} + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS +/** + * call sys_timeout in tcpip_thread + * + * @param msecs time in milliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_TIMEOUT; + msg->msg.tmo.msecs = msecs; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&mbox, msg); + return ERR_OK; +} + +/** + * call sys_untimeout in tcpip_thread + * + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ + struct tcpip_msg *msg; + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_UNTIMEOUT; + msg->msg.tmo.h = h; + msg->msg.tmo.arg = arg; + sys_mbox_post(&mbox, msg); + return ERR_OK; +} +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + + +/** + * Sends a message to TCPIP thread to call a function. Caller thread blocks on + * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, + * this has to be done by the user. + * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way + * with least runtime overhead. + * + * @param fn function to be called from TCPIP thread + * @param apimsg argument to API function + * @param sem semaphore to wait on + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem) +{ +#if LWIP_TCPIP_CORE_LOCKING + LWIP_UNUSED_ARG(sem); + LOCK_TCPIP_CORE(); + fn(apimsg); + UNLOCK_TCPIP_CORE(); + return ERR_OK; +#else /* LWIP_TCPIP_CORE_LOCKING */ + TCPIP_MSG_VAR_DECLARE(msg); + + LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + TCPIP_MSG_VAR_ALLOC(msg); + TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; + TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; + TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; + sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); + sys_arch_sem_wait(sem, 0); + TCPIP_MSG_VAR_FREE(msg); + return ERR_OK; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} + +/** + * Synchronously calls function in TCPIP thread and waits for its completion. + * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or + * LWIP_NETCONN_SEM_PER_THREAD. + * If not, a semaphore is created and destroyed on every call which is usually + * an expensive/slow operation. + * @param fn Function to call + * @param call Call parameters + * @return Return value from tcpip_api_call_fn + */ +err_t +tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) +{ +#if LWIP_TCPIP_CORE_LOCKING + err_t err; + LOCK_TCPIP_CORE(); + err = fn(call); + UNLOCK_TCPIP_CORE(); + return err; +#else /* LWIP_TCPIP_CORE_LOCKING */ + TCPIP_MSG_VAR_DECLARE(msg); + +#if !LWIP_NETCONN_SEM_PER_THREAD + err_t err = sys_sem_new(&call->sem, 0); + if (err != ERR_OK) { + return err; + } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + + TCPIP_MSG_VAR_ALLOC(msg); + TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; + TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; + TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; +#if LWIP_NETCONN_SEM_PER_THREAD + TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ + TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); + sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); + TCPIP_MSG_VAR_FREE(msg); + +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_free(&call->sem); +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + return call->err; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +} + +/** + * Allocate a structure for a static callback message and initialize it. + * This is intended to be used to send "static" messages from interrupt context. + * + * @param function the function to call + * @param ctx parameter passed to function + * @return a struct pointer to pass to tcpip_trycallback(). + */ +struct tcpip_callback_msg* +tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) +{ + struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); + if (msg == NULL) { + return NULL; + } + msg->type = TCPIP_MSG_CALLBACK_STATIC; + msg->msg.cb.function = function; + msg->msg.cb.ctx = ctx; + return (struct tcpip_callback_msg*)msg; +} + +/** + * Free a callback message allocated by tcpip_callbackmsg_new(). + * + * @param msg the message to free + */ +void +tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) +{ + memp_free(MEMP_TCPIP_MSG_API, msg); +} + +/** + * Try to post a callback-message to the tcpip_thread mbox + * This is intended to be used to send "static" messages from interrupt context. + * + * @param msg pointer to the message to post + * @return sys_mbox_trypost() return code + */ +err_t +tcpip_trycallback(struct tcpip_callback_msg* msg) +{ + LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); + return sys_mbox_trypost(&mbox, msg); +} + +/** + * @ingroup lwip_os + * Initialize this module: + * - initialize all sub modules + * - start the tcpip_thread + * + * @param initfunc a function to call when tcpip_thread is running and finished initializing + * @param arg argument to pass to initfunc + */ +void +tcpip_init(tcpip_init_done_fn initfunc, void *arg) +{ + lwip_init(); + + tcpip_init_done = initfunc; + tcpip_init_done_arg = arg; + if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { + LWIP_ASSERT("failed to create tcpip_thread mbox", 0); + } +#if LWIP_TCPIP_CORE_LOCKING + if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { + LWIP_ASSERT("failed to create lock_tcpip_core", 0); + } +#endif /* LWIP_TCPIP_CORE_LOCKING */ + + sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); +} + +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ + struct pbuf *q = (struct pbuf *)p; + pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ + return tcpip_callback_with_block(pbuf_free_int, p, 0); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ + return tcpip_callback_with_block(mem_free, m, 0); +} + +#endif /* !NO_SYS */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs.c b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs.c new file mode 100644 index 0000000000..35b5e31038 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/apps/httpd_opts.h" +#include "lwip/def.h" +#include "lwip/apps/fs.h" +#include "fsdata.h" +#include + + +#if HTTPD_USE_CUSTOM_FSDATA +#include "fsdata_custom.c" +#else /* HTTPD_USE_CUSTOM_FSDATA */ +#include "fsdata.c" +#endif /* HTTPD_USE_CUSTOM_FSDATA */ + +/*-----------------------------------------------------------------------------------*/ + +#if LWIP_HTTPD_CUSTOM_FILES +int fs_open_custom(struct fs_file *file, const char *name); +void fs_close_custom(struct fs_file *file); +#if LWIP_HTTPD_FS_ASYNC_READ +u8_t fs_canread_custom(struct fs_file *file); +u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); +int fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_read_custom(struct fs_file *file, char *buffer, int count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_CUSTOM_FILES */ + +/*-----------------------------------------------------------------------------------*/ +err_t +fs_open(struct fs_file *file, const char *name) +{ + const struct fsdata_file *f; + + if ((file == NULL) || (name == NULL)) { + return ERR_ARG; + } + +#if LWIP_HTTPD_CUSTOM_FILES + if (fs_open_custom(file, name)) { + file->is_custom_file = 1; + return ERR_OK; + } + file->is_custom_file = 0; +#endif /* LWIP_HTTPD_CUSTOM_FILES */ + + for (f = FS_ROOT; f != NULL; f = f->next) { + if (!strcmp(name, (const char *)f->name)) { + file->data = (const char *)f->data; + file->len = f->len; + file->index = f->len; + file->pextension = NULL; + file->flags = f->flags; +#if HTTPD_PRECALCULATED_CHECKSUM + file->chksum_count = f->chksum_count; + file->chksum = f->chksum; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ +#if LWIP_HTTPD_FILE_STATE + file->state = fs_state_init(file, name); +#endif /* #if LWIP_HTTPD_FILE_STATE */ + return ERR_OK; + } + } + /* file not found */ + return ERR_VAL; +} + +/*-----------------------------------------------------------------------------------*/ +void +fs_close(struct fs_file *file) +{ +#if LWIP_HTTPD_CUSTOM_FILES + if (file->is_custom_file) { + fs_close_custom(file); + } +#endif /* LWIP_HTTPD_CUSTOM_FILES */ +#if LWIP_HTTPD_FILE_STATE + fs_state_free(file, file->state); +#endif /* #if LWIP_HTTPD_FILE_STATE */ + LWIP_UNUSED_ARG(file); +} +/*-----------------------------------------------------------------------------------*/ +#if LWIP_HTTPD_DYNAMIC_FILE_READ +#if LWIP_HTTPD_FS_ASYNC_READ +int +fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg) +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int +fs_read(struct fs_file *file, char *buffer, int count) +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +{ + int read; + if(file->index == file->len) { + return FS_READ_EOF; + } +#if LWIP_HTTPD_FS_ASYNC_READ + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#if LWIP_HTTPD_CUSTOM_FILES + if (file->is_custom_file) { +#if LWIP_HTTPD_FS_ASYNC_READ + return fs_read_async_custom(file, buffer, count, callback_fn, callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ + return fs_read_custom(file, buffer, count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + } +#endif /* LWIP_HTTPD_CUSTOM_FILES */ + + read = file->len - file->index; + if(read > count) { + read = count; + } + + MEMCPY(buffer, (file->data + file->index), read); + file->index += read; + + return(read); +} +#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ +/*-----------------------------------------------------------------------------------*/ +#if LWIP_HTTPD_FS_ASYNC_READ +int +fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg) +{ + if (file != NULL) { +#if LWIP_HTTPD_FS_ASYNC_READ +#if LWIP_HTTPD_CUSTOM_FILES + if (!fs_canread_custom(file)) { + if (fs_wait_read_custom(file, callback_fn, callback_arg)) { + return 0; + } + } +#else /* LWIP_HTTPD_CUSTOM_FILES */ + LWIP_UNUSED_ARG(callback_fn); + LWIP_UNUSED_ARG(callback_arg); +#endif /* LWIP_HTTPD_CUSTOM_FILES */ +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + } + return 1; +} +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +/*-----------------------------------------------------------------------------------*/ +int +fs_bytes_left(struct fs_file *file) +{ + return file->len - file->index; +} diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/404.html b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/404.html new file mode 100644 index 0000000000..40b343a91e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/fs/404.html @@ -0,0 +1,21 @@ + +lwIP - A Lightweight TCP/IP Stack + + + + +
      + SICS logo + +

      lwIP - A Lightweight TCP/IP Stack

      +

      404 - Page not found

      +

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

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

      lwIP - A Lightweight TCP/IP Stack

      +

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

      +

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

      +

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

      +

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

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

      404: The requested file cannot be found.

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

      404: The requested file cannot be found.

      \r\n" +#endif +}; + +/* Indexes into the g_psHTTPHeaderStrings array */ +#define HTTP_HDR_OK 0 /* 200 OK */ +#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */ +#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */ +#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */ +#define HTTP_HDR_OK_11 4 /* 200 OK */ +#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */ +#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */ +#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */ +#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/ +#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */ +#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */ +#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/ +#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */ +#define DEFAULT_404_HTML 13 /* default 404 body */ +#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE +#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */ +#endif + + +#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n" +#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n" +#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n" +#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n" +#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n" +#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n" +#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n" +#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n" +#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n" +#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n" +#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n" +#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n" +#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n" +#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n" +#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n" + +#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n" + +/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES + * and http://www.iana.org/assignments/media-types for registered content types + * and subtypes) */ +static const tHTTPHeader g_psHTTPHeaders[] = +{ + { "html", HTTP_HDR_HTML}, + { "htm", HTTP_HDR_HTML}, + { "shtml",HTTP_HDR_SSI}, + { "shtm", HTTP_HDR_SSI}, + { "ssi", HTTP_HDR_SSI}, + { "gif", HTTP_HDR_GIF}, + { "png", HTTP_HDR_PNG}, + { "jpg", HTTP_HDR_JPG}, + { "bmp", HTTP_HDR_BMP}, + { "ico", HTTP_HDR_ICO}, + { "class",HTTP_HDR_APP}, + { "cls", HTTP_HDR_APP}, + { "js", HTTP_HDR_JS}, + { "ram", HTTP_HDR_RA}, + { "css", HTTP_HDR_CSS}, + { "swf", HTTP_HDR_SWF}, + { "xml", HTTP_HDR_XML}, + { "xsl", HTTP_HDR_XML}, + { "pdf", HTTP_HDR_PDF}, + { "json", HTTP_HDR_JSON} +}; + +#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader)) + +#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ + +#if LWIP_HTTPD_SSI +static const char * const g_pcSSIExtensions[] = { + ".shtml", ".shtm", ".ssi", ".xml" +}; +#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *)) +#endif /* LWIP_HTTPD_SSI */ + +#endif /* LWIP_HTTPD_STRUCTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata new file mode 100644 index 0000000000..37b4203e6e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata @@ -0,0 +1,97 @@ +#!/usr/bin/perl + +open(OUTPUT, "> fsdata.c"); + +chdir("fs"); +open(FILES, "find . -type f |"); + +while($file = ) { + + # Do not include files in CVS directories nor backup files. + if($file =~ /(CVS|~)/) { + next; + } + + chop($file); + + open(HEADER, "> /tmp/header") || die $!; + if($file =~ /404/) { + print(HEADER "HTTP/1.0 404 File not found\r\n"); + } else { + print(HEADER "HTTP/1.0 200 OK\r\n"); + } + print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"); + if($file =~ /\.html$/) { + print(HEADER "Content-type: text/html\r\n"); + } elsif($file =~ /\.gif$/) { + print(HEADER "Content-type: image/gif\r\n"); + } elsif($file =~ /\.png$/) { + print(HEADER "Content-type: image/png\r\n"); + } elsif($file =~ /\.jpg$/) { + print(HEADER "Content-type: image/jpeg\r\n"); + } elsif($file =~ /\.class$/) { + print(HEADER "Content-type: application/octet-stream\r\n"); + } elsif($file =~ /\.ram$/) { + print(HEADER "Content-type: audio/x-pn-realaudio\r\n"); + } else { + print(HEADER "Content-type: text/plain\r\n"); + } + print(HEADER "\r\n"); + close(HEADER); + + unless($file =~ /\.plain$/ || $file =~ /cgi/) { + system("cat /tmp/header $file > /tmp/file"); + } else { + system("cp $file /tmp/file"); + } + + open(FILE, "/tmp/file"); + unlink("/tmp/file"); + unlink("/tmp/header"); + + $file =~ s/\.//; + $fvar = $file; + $fvar =~ s-/-_-g; + $fvar =~ s-\.-_-g; + print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); + print(OUTPUT "\t/* $file */\n\t"); + for($j = 0; $j < length($file); $j++) { + printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); + } + printf(OUTPUT "0,\n"); + + + $i = 0; + while(read(FILE, $data, 1)) { + if($i == 0) { + print(OUTPUT "\t"); + } + printf(OUTPUT "%#02x, ", unpack("C", $data)); + $i++; + if($i == 10) { + print(OUTPUT "\n"); + $i = 0; + } + } + print(OUTPUT "};\n\n"); + close(FILE); + push(@fvars, $fvar); + push(@files, $file); +} + +for($i = 0; $i < @fvars; $i++) { + $file = $files[$i]; + $fvar = $fvars[$i]; + + if($i == 0) { + $prevfile = "NULL"; + } else { + $prevfile = "file" . $fvars[$i - 1]; + } + print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); + print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); +} + +print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); +print(OUTPUT "#define FS_NUMFILES $i\n"); diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata.c b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata.c new file mode 100644 index 0000000000..934e721948 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/makefsdata.c @@ -0,0 +1,1033 @@ +/** + * makefsdata: Converts a directory structure for use with the lwIP httpd. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jim Pettinato + * Simon Goldschmidt + * + * @todo: + * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and + * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments + */ + +#include +#include +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#else +#include +#endif +#include +#include +#include +#include + +/** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). + * Since nearly all browsers support this, this is a good way to reduce ROM size. + * To compress the files, "miniz.c" must be downloaded seperately. + */ +#ifndef MAKEFS_SUPPORT_DEFLATE +#define MAKEFS_SUPPORT_DEFLATE 0 +#endif + +#define COPY_BUFSIZE (1024*1024) /* 1 MByte */ + +#if MAKEFS_SUPPORT_DEFLATE +#include "../miniz.c" + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint; + +#define my_max(a,b) (((a) > (b)) ? (a) : (b)) +#define my_min(a,b) (((a) < (b)) ? (a) : (b)) + +/* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression. + COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */ +#define COMP_OUT_BUF_SIZE COPY_BUFSIZE + +/* OUT_BUF_SIZE is the size of the output buffer used during decompression. + OUT_BUF_SIZE must be a power of 2 >= TINFL_LZ_DICT_SIZE (because the low-level decompressor not only writes, but reads from the output buffer as it decompresses) */ +#define OUT_BUF_SIZE COPY_BUFSIZE +static uint8 s_outbuf[OUT_BUF_SIZE]; +static uint8 s_checkbuf[OUT_BUF_SIZE]; + +/* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). + This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it. */ +tdefl_compressor g_deflator; +tinfl_decompressor g_inflator; + +int deflate_level = 10; /* default compression level, can be changed via command line */ +#define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" +#else /* MAKEFS_SUPPORT_DEFLATE */ +#define USAGE_ARG_DEFLATE "" +#endif /* MAKEFS_SUPPORT_DEFLATE */ + +/* Compatibility defines Win32 vs. DOS */ +#ifdef WIN32 + +#define FIND_T WIN32_FIND_DATAA +#define FIND_T_FILENAME(fInfo) (fInfo.cFileName) +#define FIND_T_IS_DIR(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) +#define FIND_T_IS_FILE(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) +#define FIND_RET_T HANDLE +#define FINDFIRST_FILE(path, result) FindFirstFileA(path, result) +#define FINDFIRST_DIR(path, result) FindFirstFileA(path, result) +#define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) +#define FINDFIRST_SUCCEEDED(ret) (ret != INVALID_HANDLE_VALUE) +#define FINDNEXT_SUCCEEDED(ret) (ret == TRUE) + +#define GETCWD(path, len) GetCurrentDirectoryA(len, path) +#define CHDIR(path) SetCurrentDirectoryA(path) +#define CHDIR_SUCCEEDED(ret) (ret == TRUE) + +#else + +#define FIND_T struct ffblk +#define FIND_T_FILENAME(fInfo) (fInfo.ff_name) +#define FIND_T_IS_DIR(fInfo) ((fInfo.ff_attrib & FA_DIREC) == FA_DIREC) +#define FIND_T_IS_FILE(fInfo) (1) +#define FIND_RET_T int +#define FINDFIRST_FILE(path, result) findfirst(path, result, FA_ARCH) +#define FINDFIRST_DIR(path, result) findfirst(path, result, FA_DIREC) +#define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) +#define FINDFIRST_SUCCEEDED(ret) (ret == 0) +#define FINDNEXT_SUCCEEDED(ret) (ret == 0) + +#define GETCWD(path, len) getcwd(path, len) +#define CHDIR(path) chdir(path) +#define CHDIR_SUCCEEDED(ret) (ret == 0) + +#endif + +#define NEWLINE "\r\n" +#define NEWLINE_LEN 2 + +/* define this to get the header variables we use to build HTTP headers */ +#define LWIP_HTTPD_DYNAMIC_HEADERS 1 +#define LWIP_HTTPD_SSI 1 +#include "lwip/init.h" +#include "../httpd_structs.h" +#include "lwip/apps/fs.h" + +#include "../core/inet_chksum.c" +#include "../core/def.c" + +/** (Your server name here) */ +const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; +char serverIDBuffer[1024]; + +/* change this to suit your MEM_ALIGNMENT */ +#define PAYLOAD_ALIGNMENT 4 +/* set this to 0 to prevent aligning payload */ +#define ALIGN_PAYLOAD 1 +/* define this to a type that has the required alignment */ +#define PAYLOAD_ALIGN_TYPE "unsigned int" +static int payload_alingment_dummy_counter = 0; + +#define HEX_BYTES_PER_LINE 16 + +#define MAX_PATH_LEN 256 + +struct file_entry +{ + struct file_entry* next; + const char* filename_c; +}; + +int process_sub(FILE *data_file, FILE *struct_file); +int process_file(FILE *data_file, FILE *struct_file, const char *filename); +int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, + u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed); +int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); +int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); +void concat_files(const char *file1, const char *file2, const char *targetfile); +int check_path(char* path, size_t size); + +/* 5 bytes per char + 3 bytes per line */ +static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; + +char curSubdir[MAX_PATH_LEN]; +char lastFileVar[MAX_PATH_LEN]; +char hdr_buf[4096]; + +unsigned char processSubs = 1; +unsigned char includeHttpHeader = 1; +unsigned char useHttp11 = 0; +unsigned char supportSsi = 1; +unsigned char precalcChksum = 0; +unsigned char includeLastModified = 0; +#if MAKEFS_SUPPORT_DEFLATE +unsigned char deflateNonSsiFiles = 0; +size_t deflatedBytesReduced = 0; +size_t overallDataBytes = 0; +#endif + +struct file_entry* first_file = NULL; +struct file_entry* last_file = NULL; + +static void print_usage(void) +{ + printf(" Usage: htmlgen [targetdir] [-s] [-e] [-i] [-11] [-nossi] [-c] [-f:] [-m] [-svr:]" USAGE_ARG_DEFLATE NEWLINE NEWLINE); + printf(" targetdir: relative or absolute path to files to convert" NEWLINE); + printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); + printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); + printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); + printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); + printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); + printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); + printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE); + printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE); +#if MAKEFS_SUPPORT_DEFLATE + printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE); + printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE); +#endif + printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); + printf(" process files in subdirectory 'fs'" NEWLINE); +} + +int main(int argc, char *argv[]) +{ + char path[MAX_PATH_LEN]; + char appPath[MAX_PATH_LEN]; + FILE *data_file; + FILE *struct_file; + int filesProcessed; + int i; + char targetfile[MAX_PATH_LEN]; + strcpy(targetfile, "fsdata.c"); + + memset(path, 0, sizeof(path)); + memset(appPath, 0, sizeof(appPath)); + + printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); + printf(" by Jim Pettinato - circa 2003 " NEWLINE); + printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); + + strcpy(path, "fs"); + for (i = 1; i < argc; i++) { + if (argv[i] == NULL) { + continue; + } + if (argv[i][0] == '-') { + if (strstr(argv[i], "-svr:") == argv[i]) { + snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]); + serverID = serverIDBuffer; + printf("Using Server-ID: \"%s\"\n", serverID); + } else if (strstr(argv[i], "-s") == argv[i]) { + processSubs = 0; + } else if (strstr(argv[i], "-e") == argv[i]) { + includeHttpHeader = 0; + } else if (strstr(argv[i], "-11") == argv[i]) { + useHttp11 = 1; + } else if (strstr(argv[i], "-nossi") == argv[i]) { + supportSsi = 0; + } else if (strstr(argv[i], "-c") == argv[i]) { + precalcChksum = 1; + } else if (strstr(argv[i], "-f:") == argv[i]) { + strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); + targetfile[sizeof(targetfile) - 1] = 0; + printf("Writing to file \"%s\"\n", targetfile); + } else if (strstr(argv[i], "-m") == argv[i]) { + includeLastModified = 1; + } else if (strstr(argv[i], "-defl") == argv[i]) { +#if MAKEFS_SUPPORT_DEFLATE + char* colon = strstr(argv[i], ":"); + if (colon) { + if (colon[1] != 0) { + int defl_level = atoi(&colon[1]); + if ((defl_level >= 0) && (defl_level <= 10)) { + deflate_level = defl_level; + } else { + printf("ERROR: deflate level must be [0..10]" NEWLINE); + exit(0); + } + } + } + deflateNonSsiFiles = 1; + printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); +#else + printf("WARNING: Deflate support is disabled\n"); +#endif + } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { + print_usage(); + exit(0); + } + } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) { + print_usage(); + exit(0); + } else { + strncpy(path, argv[i], sizeof(path)-1); + path[sizeof(path)-1] = 0; + } + } + + if (!check_path(path, sizeof(path))) { + printf("Invalid path: \"%s\"." NEWLINE, path); + exit(-1); + } + + GETCWD(appPath, MAX_PATH_LEN); + /* if command line param or subdir named 'fs' not found spout usage verbiage */ + if (!CHDIR_SUCCEEDED(CHDIR(path))) { + /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ + printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); + print_usage(); + exit(-1); + } + CHDIR(appPath); + + printf("HTTP %sheader will %s statically included." NEWLINE, + (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), + (includeHttpHeader ? "be" : "not be")); + + sprintf(curSubdir, ""); /* start off in web page's root directory - relative paths */ + printf(" Processing all files in directory %s", path); + if (processSubs) { + printf(" and subdirectories..." NEWLINE NEWLINE); + } else { + printf("..." NEWLINE NEWLINE); + } + + data_file = fopen("fsdata.tmp", "wb"); + if (data_file == NULL) { + printf("Failed to create file \"fsdata.tmp\"\n"); + exit(-1); + } + struct_file = fopen("fshdr.tmp", "wb"); + if (struct_file == NULL) { + printf("Failed to create file \"fshdr.tmp\"\n"); + fclose(data_file); + exit(-1); + } + + CHDIR(path); + + fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); + fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE); + fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE); + + fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); + /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */ + fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE); + /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */ + fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE); + + /* define alignment defines */ +#if ALIGN_PAYLOAD + fprintf(data_file, "/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */" NEWLINE "#ifndef FSDATA_FILE_ALIGNMENT" NEWLINE "#define FSDATA_FILE_ALIGNMENT 0" NEWLINE "#endif" NEWLINE); +#endif + fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE); + fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE); +#if ALIGN_PAYLOAD + fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE); +#endif + + sprintf(lastFileVar, "NULL"); + + filesProcessed = process_sub(data_file, struct_file); + + /* data_file now contains all of the raw data.. now append linked list of + * file header structs to allow embedded app to search for a file name */ + fprintf(data_file, NEWLINE NEWLINE); + fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); + fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); + + fclose(data_file); + fclose(struct_file); + + CHDIR(appPath); + /* append struct_file to data_file */ + printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); + concat_files("fsdata.tmp", "fshdr.tmp", targetfile); + + /* if succeeded, delete the temporary files */ + if (remove("fsdata.tmp") != 0) { + printf("Warning: failed to delete fsdata.tmp\n"); + } + if (remove("fshdr.tmp") != 0) { + printf("Warning: failed to delete fshdr.tmp\n"); + } + + printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed); +#if MAKEFS_SUPPORT_DEFLATE + if (deflateNonSsiFiles) { + printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE, + (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced*100.0)/overallDataBytes)); + } +#endif + printf(NEWLINE); + + while (first_file != NULL) { + struct file_entry* fe = first_file; + first_file = fe->next; + free(fe); + } + + return 0; +} + +int check_path(char* path, size_t size) +{ + size_t slen; + if (path[0] == 0) { + /* empty */ + return 0; + } + slen = strlen(path); + if (slen >= size) { + /* not NULL-terminated */ + return 0; + } + while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { + /* path should not end with trailing backslash */ + path[slen] = 0; + slen--; + } + if (slen == 0) { + return 0; + } + return 1; +} + +static void copy_file(const char *filename_in, FILE *fout) +{ + FILE *fin; + size_t len; + void* buf; + fin = fopen(filename_in, "rb"); + if (fin == NULL) { + printf("Failed to open file \"%s\"\n", filename_in); + exit(-1); + } + buf = malloc(COPY_BUFSIZE); + while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) { + fwrite(buf, 1, len, fout); + } + free(buf); + fclose(fin); +} + +void concat_files(const char *file1, const char *file2, const char *targetfile) +{ + FILE *fout; + fout = fopen(targetfile, "wb"); + if (fout == NULL) { + printf("Failed to open file \"%s\"\n", targetfile); + exit(-1); + } + copy_file(file1, fout); + copy_file(file2, fout); + fclose(fout); +} + +int process_sub(FILE *data_file, FILE *struct_file) +{ + FIND_T fInfo; + FIND_RET_T fret; + int filesProcessed = 0; + + if (processSubs) { + /* process subs recursively */ + size_t sublen = strlen(curSubdir); + size_t freelen = sizeof(curSubdir) - sublen - 1; + LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); + fret = FINDFIRST_DIR("*", &fInfo); + if (FINDFIRST_SUCCEEDED(fret)) { + do { + const char *curName = FIND_T_FILENAME(fInfo); + if ((curName[0] == '.') || (strcmp(curName, "CVS") == 0)) { + continue; + } + if (!FIND_T_IS_DIR(fInfo)) { + continue; + } + if (freelen > 0) { + CHDIR(curName); + strncat(curSubdir, "/", freelen); + strncat(curSubdir, curName, freelen - 1); + curSubdir[sizeof(curSubdir) - 1] = 0; + printf("processing subdirectory %s/..." NEWLINE, curSubdir); + filesProcessed += process_sub(data_file, struct_file); + CHDIR(".."); + curSubdir[sublen] = 0; + } else { + printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, curName); + } + } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); + } + } + + fret = FINDFIRST_FILE("*.*", &fInfo); + if (FINDFIRST_SUCCEEDED(fret)) { + /* at least one file in directory */ + do { + if (FIND_T_IS_FILE(fInfo)) { + const char *curName = FIND_T_FILENAME(fInfo); + printf("processing %s/%s..." NEWLINE, curSubdir, curName); + if (process_file(data_file, struct_file, curName) < 0) { + printf(NEWLINE "Error... aborting" NEWLINE); + return -1; + } + filesProcessed++; + } + } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); + } + return filesProcessed; +} + +u8_t* get_file_data(const char* filename, int* file_size, int can_be_compressed, int* is_compressed) +{ + FILE *inFile; + size_t fsize = 0; + u8_t* buf; + size_t r; + int rs; + inFile = fopen(filename, "rb"); + if (inFile == NULL) { + printf("Failed to open file \"%s\"\n", filename); + exit(-1); + } + fseek(inFile, 0, SEEK_END); + rs = ftell(inFile); + if (rs < 0) { + printf("ftell failed with %d\n", errno); + exit(-1); + } + fsize = (size_t)rs; + fseek(inFile, 0, SEEK_SET); + buf = (u8_t*)malloc(fsize); + LWIP_ASSERT("buf != NULL", buf != NULL); + r = fread(buf, 1, fsize, inFile); + *file_size = fsize; + *is_compressed = 0; +#if MAKEFS_SUPPORT_DEFLATE + overallDataBytes += fsize; + if (deflateNonSsiFiles) { + if (can_be_compressed) { + if (fsize < OUT_BUF_SIZE) { + u8_t* ret_buf; + tdefl_status status; + size_t in_bytes = fsize; + size_t out_bytes = OUT_BUF_SIZE; + const void *next_in = buf; + void *next_out = s_outbuf; + /* create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). */ + mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (!deflate_level) { + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + } + status = tdefl_init(&g_deflator, NULL, NULL, comp_flags); + if (status != TDEFL_STATUS_OKAY) { + printf("tdefl_init() failed!\n"); + exit(-1); + } + memset(s_outbuf, 0, sizeof(s_outbuf)); + status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); + if (status != TDEFL_STATUS_DONE) { + printf("deflate failed: %d\n", status); + exit(-1); + } + LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); + if (out_bytes < fsize) { + ret_buf = (u8_t*)malloc(out_bytes); + LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL); + memcpy(ret_buf, s_outbuf, out_bytes); + { + /* sanity-check compression be inflating and comparing to the original */ + tinfl_status dec_status; + tinfl_decompressor inflator; + size_t dec_in_bytes = out_bytes; + size_t dec_out_bytes = OUT_BUF_SIZE; + next_out = s_checkbuf; + + tinfl_init(&inflator); + memset(s_checkbuf, 0, sizeof(s_checkbuf)); + dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); + LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); + LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); + LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); + } + /* free original buffer, use compressed data + size */ + free(buf); + buf = ret_buf; + *file_size = out_bytes; + printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes*100.0)/fsize)); + deflatedBytesReduced += (size_t)(fsize - out_bytes); + *is_compressed = 1; + } else { + printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); + } + } else { + printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); + } + } else { + printf(" - SSI file, cannot be compressed" NEWLINE); + } + } +#else + LWIP_UNUSED_ARG(can_be_compressed); +#endif + fclose(inFile); + return buf; +} + +void process_file_data(FILE* data_file, u8_t* file_data, size_t file_size) +{ + size_t written, i, src_off=0; + + size_t off = 0; + for (i = 0; i < file_size; i++) { + LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5); + sprintf(&file_buffer_c[off], "0x%02.2x,", file_data[i]); + off += 5; + if ((++src_off % HEX_BYTES_PER_LINE) == 0) { + LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN); + memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); + off += NEWLINE_LEN; + } + if (off + 20 >= sizeof(file_buffer_c)) { + written = fwrite(file_buffer_c, 1, off, data_file); + LWIP_ASSERT("written == off", written == off); + off = 0; + } + } + written = fwrite(file_buffer_c, 1, off, data_file); + LWIP_ASSERT("written == off", written == off); +} + +int write_checksums(FILE *struct_file, const char *varname, + u16_t hdr_len, u16_t hdr_chksum, const u8_t* file_data, size_t file_size) +{ + int chunk_size = TCP_MSS; + int offset, src_offset; + size_t len; + int i = 0; +#if LWIP_TCP_TIMESTAMPS + /* when timestamps are used, usable space is 12 bytes less per segment */ + chunk_size -= 12; +#endif + + fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); + fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); + + if (hdr_len > 0) { + /* add checksum for HTTP header */ + fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); + i++; + } + src_offset = 0; + for (offset = hdr_len; ; offset += len) { + unsigned short chksum; + void* data = (void*)&file_data[src_offset]; + len = LWIP_MIN(chunk_size, (int)file_size - src_offset); + if (len == 0) { + break; + } + chksum = ~inet_chksum(data, (u16_t)len); + /* add checksum for data */ + fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len); + i++; + } + fprintf(struct_file, "};" NEWLINE); + fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); + return i; +} + +static int is_valid_char_for_c_var(char x) +{ + if (((x >= 'A') && (x <= 'Z')) || + ((x >= 'a') && (x <= 'z')) || + ((x >= '0') && (x <= '9')) || + (x == '_')) { + return 1; + } + return 0; +} + +static void fix_filename_for_c(char* qualifiedName, size_t max_len) +{ + struct file_entry* f; + size_t len = strlen(qualifiedName); + char *new_name = (char*)malloc(len + 2); + int filename_ok; + int cnt = 0; + size_t i; + if (len + 3 == max_len) { + printf("File name too long: \"%s\"\n", qualifiedName); + exit(-1); + } + strcpy(new_name, qualifiedName); + for (i = 0; i < len; i++) { + if (!is_valid_char_for_c_var(new_name[i])) { + new_name[i] = '_'; + } + } + do { + filename_ok = 1; + for (f = first_file; f != NULL; f = f->next) { + if (!strcmp(f->filename_c, new_name)) { + filename_ok = 0; + cnt++; + /* try next unique file name */ + sprintf(&new_name[len], "%d", cnt); + break; + } + } + } while (!filename_ok && (cnt < 999)); + if (!filename_ok) { + printf("Failed to get unique file name: \"%s\"\n", qualifiedName); + exit(-1); + } + strcpy(qualifiedName, new_name); + free(new_name); +} + +static void register_filename(const char* qualifiedName) +{ + struct file_entry* fe = (struct file_entry*)malloc(sizeof(struct file_entry)); + fe->filename_c = strdup(qualifiedName); + fe->next = NULL; + if (first_file == NULL) { + first_file = last_file = fe; + } else { + last_file->next = fe; + last_file = fe; + } +} + +int is_ssi_file(const char* filename) +{ + size_t loop; + for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { + if (strstr(filename, g_pcSSIExtensions[loop])) { + return 1; + } + } + return 0; +} + +int process_file(FILE *data_file, FILE *struct_file, const char *filename) +{ + char varname[MAX_PATH_LEN]; + int i = 0; + char qualifiedName[MAX_PATH_LEN]; + int file_size; + u16_t http_hdr_chksum = 0; + u16_t http_hdr_len = 0; + int chksum_count = 0; + u8_t flags = 0; + const char* flags_str; + u8_t has_content_len; + u8_t* file_data; + int is_compressed = 0; + + /* create qualified name (@todo: prepend slash or not?) */ + sprintf(qualifiedName,"%s/%s", curSubdir, filename); + /* create C variable name */ + strcpy(varname, qualifiedName); + /* convert slashes & dots to underscores */ + fix_filename_for_c(varname, MAX_PATH_LEN); + register_filename(varname); +#if ALIGN_PAYLOAD + /* to force even alignment of array, type 1 */ + fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE); + fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); + fprintf(data_file, "#endif" NEWLINE); +#endif /* ALIGN_PAYLOAD */ + fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname); + /* encode source file name (used by file system, not returned to browser) */ + fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1); + file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i); +#if ALIGN_PAYLOAD + /* pad to even number of bytes to assure payload is on aligned boundary */ + while(i % PAYLOAD_ALIGNMENT != 0) { + fprintf(data_file, "0x%02.2x,", 0); + i++; + } +#endif /* ALIGN_PAYLOAD */ + fprintf(data_file, NEWLINE); + + has_content_len = !is_ssi_file(filename); + file_data = get_file_data(filename, &file_size, includeHttpHeader && has_content_len, &is_compressed); + if (includeHttpHeader) { + file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed); + flags = FS_FILE_FLAGS_HEADER_INCLUDED; + if (has_content_len) { + flags |= FS_FILE_FLAGS_HEADER_PERSISTENT; + } + } + if (precalcChksum) { + chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size); + } + + /* build declaration of struct fsdata_file in temp file */ + fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); + fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); + fprintf(struct_file, "data_%s," NEWLINE, varname); + fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); + fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); + switch(flags) + { + case(FS_FILE_FLAGS_HEADER_INCLUDED): + flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED"; + break; + case(FS_FILE_FLAGS_HEADER_PERSISTENT): + flags_str = "FS_FILE_FLAGS_HEADER_PERSISTENT"; + break; + case(FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT): + flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT"; + break; + default: + flags_str = "0"; + break; + } + fprintf(struct_file, "%s," NEWLINE, flags_str); + if (precalcChksum) { + fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); + fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); + fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); + } + fprintf(struct_file, "}};" NEWLINE NEWLINE); + strcpy(lastFileVar, varname); + + /* write actual file contents */ + i = 0; + fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); + process_file_data(data_file, file_data, file_size); + fprintf(data_file, "};" NEWLINE NEWLINE); + free(file_data); + return 0; +} + +int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, + u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed) +{ + int i = 0; + int response_type = HTTP_HDR_OK; + const char* file_type; + const char *cur_string; + size_t cur_len; + int written = 0; + size_t hdr_len = 0; + u16_t acc; + const char *file_ext; + int j; + u8_t provide_last_modified = includeLastModified; + + memset(hdr_buf, 0, sizeof(hdr_buf)); + + if (useHttp11) { + response_type = HTTP_HDR_OK_11; + } + + fprintf(data_file, NEWLINE "/* HTTP header */"); + if (strstr(filename, "404") == filename) { + response_type = HTTP_HDR_NOT_FOUND; + if (useHttp11) { + response_type = HTTP_HDR_NOT_FOUND_11; + } + } else if (strstr(filename, "400") == filename) { + response_type = HTTP_HDR_BAD_REQUEST; + if (useHttp11) { + response_type = HTTP_HDR_BAD_REQUEST_11; + } + } else if (strstr(filename, "501") == filename) { + response_type = HTTP_HDR_NOT_IMPL; + if (useHttp11) { + response_type = HTTP_HDR_NOT_IMPL_11; + } + } + cur_string = g_psHTTPHeaderStrings[response_type]; + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + i = 0; + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + } + + cur_string = serverID; + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + i = 0; + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + } + + file_ext = filename; + if (file_ext != NULL) { + while(strstr(file_ext, ".") != NULL) { + file_ext = strstr(file_ext, "."); + file_ext++; + } + } + if ((file_ext == NULL) || (*file_ext == 0)) { + printf("failed to get extension for file \"%s\", using default.\n", filename); + file_type = HTTP_HDR_DEFAULT_TYPE; + } else { + file_type = NULL; + for (j = 0; j < NUM_HTTP_HEADERS; j++) { + if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { + file_type = g_psHTTPHeaders[j].content_type; + break; + } + } + if (file_type == NULL) { + printf("failed to get file type for extension \"%s\", using default.\n", file_ext); + file_type = HTTP_HDR_DEFAULT_TYPE; + } + } + + /* Content-Length is used for persistent connections in HTTP/1.1 but also for + download progress in older versions + @todo: just use a big-enough buffer and let the HTTPD send spaces? */ + if (provide_content_len) { + char intbuf[MAX_PATH_LEN]; + int content_len = file_size; + memset(intbuf, 0, sizeof(intbuf)); + cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + } + + _itoa(content_len, intbuf, 10); + strcat(intbuf, "\r\n"); + cur_len = strlen(intbuf); + written += file_put_ascii(data_file, intbuf, cur_len, &i); + i = 0; + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], intbuf, cur_len); + hdr_len += cur_len; + } + } + if (provide_last_modified) { + char modbuf[256]; + struct stat stat_data; + struct tm* t; + memset(modbuf, 0, sizeof(modbuf)); + memset(&stat_data, 0, sizeof(stat_data)); + cur_string = modbuf; + strcpy(modbuf, "Last-Modified: "); + if (stat(filename, &stat_data) != 0) { + printf("stat(%s) failed with error %d\n", filename, errno); + exit(-1); + } + t = gmtime(&stat_data.st_mtime); + if (t == NULL) { + printf("gmtime() failed with error %d\n", errno); + exit(-1); + } + strftime(&modbuf[15], sizeof(modbuf)-15, "%a, %d %b %Y %H:%M:%S GMT", t); + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%d+ bytes) */" NEWLINE, cur_string, cur_len+2); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + } + + modbuf[0] = 0; + strcat(modbuf, "\r\n"); + cur_len = strlen(modbuf); + written += file_put_ascii(data_file, modbuf, cur_len, &i); + i = 0; + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], modbuf, cur_len); + hdr_len += cur_len; + } + } + + /* HTTP/1.1 implements persistent connections */ + if (useHttp11) { + if (provide_content_len) { + cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; + } else { + /* no Content-Length available, so a persistent connection is no possible + because the client does not know the data length */ + cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; + } + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + i = 0; + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + } + } + +#if MAKEFS_SUPPORT_DEFLATE + if (is_compressed) { + /* tell the client about the deflate encoding */ + LWIP_ASSERT("error", deflateNonSsiFiles); + cur_string = "Content-Encoding: deflate\r\n"; + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + i = 0; + } +#else + LWIP_UNUSED_ARG(is_compressed); +#endif + + /* write content-type, ATTENTION: this includes the double-CRLF! */ + cur_string = file_type; + cur_len = strlen(cur_string); + fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); + written += file_put_ascii(data_file, cur_string, cur_len, &i); + i = 0; + + /* ATTENTION: headers are done now (double-CRLF has been written!) */ + + if (precalcChksum) { + memcpy(&hdr_buf[hdr_len], cur_string, cur_len); + hdr_len += cur_len; + + LWIP_ASSERT("hdr_len <= 0xffff", hdr_len <= 0xffff); + LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); + acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); + *http_hdr_len = (u16_t)hdr_len; + *http_hdr_chksum = acc; + } + + return written; +} + +int file_put_ascii(FILE *file, const char* ascii_string, int len, int *i) +{ + int x; + for (x = 0; x < len; x++) { + unsigned char cur = ascii_string[x]; + fprintf(file, "0x%02.2x,", cur); + if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { + fprintf(file, NEWLINE); + } + } + return len; +} + +int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) +{ + int x; + int idx = 0; + for (x = 0; x < len; x++) { + unsigned char cur = ascii_string[x]; + sprintf(&buf[idx], "0x%02.2x,", cur); + idx += 5; + if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { + sprintf(&buf[idx], NEWLINE); + idx += NEWLINE_LEN; + } + } + return len; +} diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/readme.txt b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/readme.txt new file mode 100644 index 0000000000..3768585ef9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/httpd/makefsdata/readme.txt @@ -0,0 +1,13 @@ +This directory contains a script ('makefsdata') to create C code suitable for +httpd for given html pages (or other files) in a directory. + +There is also a plain C console application doing the same and extended a bit. + +Usage: htmlgen [targetdir] [-s] [-i]s + targetdir: relative or absolute path to files to convert + switch -s: toggle processing of subdirectories (default is on) + switch -e: exclude HTTP header from file (header is created at runtime, default is on) + switch -11: include HTTP 1.1 header (1.0 is default) + + if targetdir not specified, makefsdata will attempt to + process files in subdirectory 'fs'. diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/lwiperf/lwiperf.c b/Sming/third-party/lwip2/lwip2-src/src/apps/lwiperf/lwiperf.c new file mode 100644 index 0000000000..efabe478e3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/lwiperf/lwiperf.c @@ -0,0 +1,661 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/** + * @defgroup iperf Iperf server + * @ingroup apps + * + * This is a simple performance measuring server to check your bandwith using + * iPerf2 on a PC as client. + * It is currently a minimal implementation providing an IPv4 TCP server only. + * + * @todo: implement UDP mode and IPv6 + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + */ + +#include "lwip/apps/lwiperf.h" + +#include "lwip/tcp.h" +#include "lwip/sys.h" + +#include + +/* Currently, only TCP-over-IPv4 is implemented (does iperf support IPv6 anyway?) */ +#if LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API + +/** Specify the idle timeout (in seconds) after that the test fails */ +#ifndef LWIPERF_TCP_MAX_IDLE_SEC +#define LWIPERF_TCP_MAX_IDLE_SEC 10U +#endif +#if LWIPERF_TCP_MAX_IDLE_SEC > 255 +#error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t +#endif + +/* File internal memory allocation (struct lwiperf_*): this defaults to + the heap */ +#ifndef LWIPERF_ALLOC +#define LWIPERF_ALLOC(type) mem_malloc(sizeof(type)) +#define LWIPERF_FREE(type, item) mem_free(item) +#endif + +/** If this is 1, check that received data has the correct format */ +#ifndef LWIPERF_CHECK_RX_DATA +#define LWIPERF_CHECK_RX_DATA 0 +#endif + +/** This is the Iperf settings struct sent from the client */ +typedef struct _lwiperf_settings { +#define LWIPERF_FLAGS_ANSWER_TEST 0x80000000 +#define LWIPERF_FLAGS_ANSWER_NOW 0x00000001 + u32_t flags; + u32_t num_threads; /* unused for now */ + u32_t remote_port; + u32_t buffer_len; /* unused for now */ + u32_t win_band; /* TCP window / UDP rate: unused for now */ + u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */ +} lwiperf_settings_t; + +/** Basic connection handle */ +struct _lwiperf_state_base; +typedef struct _lwiperf_state_base lwiperf_state_base_t; +struct _lwiperf_state_base { + /* 1=tcp, 0=udp */ + u8_t tcp; + /* 1=server, 0=client */ + u8_t server; + lwiperf_state_base_t* next; + lwiperf_state_base_t* related_server_state; +}; + +/** Connection handle for a TCP iperf session */ +typedef struct _lwiperf_state_tcp { + lwiperf_state_base_t base; + struct tcp_pcb* server_pcb; + struct tcp_pcb* conn_pcb; + u32_t time_started; + lwiperf_report_fn report_fn; + void* report_arg; + u8_t poll_count; + u8_t next_num; + u32_t bytes_transferred; + lwiperf_settings_t settings; + u8_t have_settings_buf; +} lwiperf_state_tcp_t; + +/** List of active iperf sessions */ +static lwiperf_state_base_t* lwiperf_all_connections; +/** A const buffer to send from: we want to measure sending, not copying! */ +static const u8_t lwiperf_txbuf_const[1600] = { + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', + '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', +}; + +static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb); +static void lwiperf_tcp_err(void *arg, err_t err); + +/** Add an iperf session to the 'active' list */ +static void +lwiperf_list_add(lwiperf_state_base_t* item) +{ + if (lwiperf_all_connections == NULL) { + lwiperf_all_connections = item; + } else { + item = lwiperf_all_connections; + } +} + +/** Remove an iperf session from the 'active' list */ +static void +lwiperf_list_remove(lwiperf_state_base_t* item) +{ + lwiperf_state_base_t* prev = NULL; + lwiperf_state_base_t* iter; + for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) { + if (iter == item) { + if (prev == NULL) { + lwiperf_all_connections = iter->next; + } else { + prev->next = item; + } + /* @debug: ensure this item is listed only once */ + for (iter = iter->next; iter != NULL; iter = iter->next) { + LWIP_ASSERT("duplicate entry", iter != item); + } + break; + } + } +} + +/** Call the report function of an iperf tcp session */ +static void +lwip_tcp_conn_report(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) +{ + if ((conn != NULL) && (conn->report_fn != NULL)) { + u32_t now, duration_ms, bandwidth_kbitpsec; + now = sys_now(); + duration_ms = now - conn->time_started; + if (duration_ms == 0) { + bandwidth_kbitpsec = 0; + } else { + bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U; + } + conn->report_fn(conn->report_arg, report_type, + &conn->conn_pcb->local_ip, conn->conn_pcb->local_port, + &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port, + conn->bytes_transferred, duration_ms, bandwidth_kbitpsec); + } +} + +/** Close an iperf tcp session */ +static void +lwiperf_tcp_close(lwiperf_state_tcp_t* conn, enum lwiperf_report_type report_type) +{ + err_t err; + + lwip_tcp_conn_report(conn, report_type); + lwiperf_list_remove(&conn->base); + if (conn->conn_pcb != NULL) { + tcp_arg(conn->conn_pcb, NULL); + tcp_poll(conn->conn_pcb, NULL, 0); + tcp_sent(conn->conn_pcb, NULL); + tcp_recv(conn->conn_pcb, NULL); + tcp_err(conn->conn_pcb, NULL); + err = tcp_close(conn->conn_pcb); + if (err != ERR_OK) { + /* don't want to wait for free memory here... */ + tcp_abort(conn->conn_pcb); + } + } else { + /* no conn pcb, this is the server pcb */ + err = tcp_close(conn->server_pcb); + LWIP_ASSERT("error", err != ERR_OK); + } + LWIPERF_FREE(lwiperf_state_tcp_t, conn); +} + +/** Try to send more data on an iperf tcp session */ +static err_t +lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn) +{ + int send_more; + err_t err; + u16_t txlen; + u16_t txlen_max; + void* txptr; + u8_t apiflags; + + LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0)); + + do { + send_more = 0; + if (conn->settings.amount & PP_HTONL(0x80000000)) { + /* this session is time-limited */ + u32_t now = sys_now(); + u32_t diff_ms = now - conn->time_started; + u32_t time = (u32_t)-(s32_t)lwip_htonl(conn->settings.amount); + u32_t time_ms = time * 10; + if (diff_ms >= time_ms) { + /* time specified by the client is over -> close the connection */ + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); + return ERR_OK; + } + } else { + /* this session is byte-limited */ + u32_t amount_bytes = lwip_htonl(conn->settings.amount); + /* @todo: this can send up to 1*MSS more than requested... */ + if (amount_bytes >= conn->bytes_transferred) { + /* all requested bytes transferred -> close the connection */ + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); + return ERR_OK; + } + } + + if (conn->bytes_transferred < 24) { + /* transmit the settings a first time */ + txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred]; + txlen_max = (u16_t)(24 - conn->bytes_transferred); + apiflags = TCP_WRITE_FLAG_COPY; + } else if (conn->bytes_transferred < 48) { + /* transmit the settings a second time */ + txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24]; + txlen_max = (u16_t)(48 - conn->bytes_transferred); + apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE; + send_more = 1; + } else { + /* transmit data */ + /* @todo: every x bytes, transmit the settings again */ + txptr = LWIP_CONST_CAST(void*, &lwiperf_txbuf_const[conn->bytes_transferred % 10]); + txlen_max = TCP_MSS; + if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */ + txlen_max = TCP_MSS - 24; + } + apiflags = 0; /* no copying needed */ + send_more = 1; + } + txlen = txlen_max; + do { + err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags); + if (err == ERR_MEM) { + txlen /= 2; + } + } while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2))); + + if (err == ERR_OK) { + conn->bytes_transferred += txlen; + } else { + send_more = 0; + } + } while(send_more); + + tcp_output(conn->conn_pcb); + return ERR_OK; +} + +/** TCP sent callback, try to send more data */ +static err_t +lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; + /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */ + LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + LWIP_UNUSED_ARG(len); + + conn->poll_count = 0; + + return lwiperf_tcp_client_send_more(conn); +} + +/** TCP connected callback (active connection), send data now */ +static err_t +lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; + LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + if (err != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); + return ERR_OK; + } + conn->poll_count = 0; + conn->time_started = sys_now(); + return lwiperf_tcp_client_send_more(conn); +} + +/** Start TCP connection back to the client (either parallel or after the + * receive test has finished. + */ +static err_t +lwiperf_tx_start(lwiperf_state_tcp_t* conn) +{ + err_t err; + lwiperf_state_tcp_t* client_conn; + struct tcp_pcb* newpcb; + ip_addr_t remote_addr; + u16_t remote_port; + + client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (client_conn == NULL) { + return ERR_MEM; + } + newpcb = tcp_new(); + if (newpcb == NULL) { + LWIPERF_FREE(lwiperf_state_tcp_t, client_conn); + return ERR_MEM; + } + + MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t)); + client_conn->base.server = 0; + client_conn->server_pcb = NULL; + client_conn->conn_pcb = newpcb; + client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */ + client_conn->poll_count = 0; + client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */ + client_conn->bytes_transferred = 0; + client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */ + + tcp_arg(newpcb, client_conn); + tcp_sent(newpcb, lwiperf_tcp_client_sent); + tcp_poll(newpcb, lwiperf_tcp_poll, 2U); + tcp_err(newpcb, lwiperf_tcp_err); + + ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip); + remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port); + + err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected); + if (err != ERR_OK) { + lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL); + return err; + } + lwiperf_list_add(&client_conn->base); + return ERR_OK; +} + +/** Receive data on an iperf tcp session */ +static err_t +lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + u8_t tmp; + u16_t tot_len; + u32_t packet_idx; + struct pbuf* q; + lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; + + LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + + if (err != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); + return ERR_OK; + } + if (p == NULL) { + /* connection closed -> test done */ + if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == + PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { + /* client requested transmission after end of test */ + lwiperf_tx_start(conn); + } + lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); + return ERR_OK; + } + tot_len = p->tot_len; + + conn->poll_count = 0; + + if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) { + /* wait for 24-byte header */ + if (p->tot_len < sizeof(lwiperf_settings_t)) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_VAL; + } + if (!conn->have_settings_buf) { + if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); + pbuf_free(p); + return ERR_VAL; + } + conn->have_settings_buf = 1; + if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == + PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) { + /* client requested parallel transmission test */ + err_t err2 = lwiperf_tx_start(conn); + if (err2 != ERR_OK) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); + pbuf_free(p); + return err2; + } + } + } else { + if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_VAL; + } + } + conn->bytes_transferred += sizeof(lwiperf_settings_t); + if (conn->bytes_transferred <= 24) { + conn->time_started = sys_now(); + tcp_recved(tpcb, p->tot_len); + pbuf_free(p); + return ERR_OK; + } + conn->next_num = 4; /* 24 bytes received... */ + tmp = pbuf_header(p, -24); + LWIP_ASSERT("pbuf_header failed", tmp == 0); + } + + packet_idx = 0; + for (q = p; q != NULL; q = q->next) { +#if LWIPERF_CHECK_RX_DATA + const u8_t* payload = (const u8_t*)q->payload; + u16_t i; + for (i = 0; i < q->len; i++) { + u8_t val = payload[i]; + u8_t num = val - '0'; + if (num == conn->next_num) { + conn->next_num++; + if (conn->next_num == 10) { + conn->next_num = 0; + } + } else { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); + pbuf_free(p); + return ERR_VAL; + } + } +#endif + packet_idx += q->len; + } + LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); + conn->bytes_transferred += packet_idx; + tcp_recved(tpcb, tot_len); + pbuf_free(p); + return ERR_OK; +} + +/** Error callback, iperf tcp session aborted */ +static void +lwiperf_tcp_err(void *arg, err_t err) +{ + lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; + LWIP_UNUSED_ARG(err); + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); +} + +/** TCP poll callback, try to send more data */ +static err_t +lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb) +{ + lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; + LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); + LWIP_UNUSED_ARG(tpcb); + if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) { + lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); + return ERR_OK; /* lwiperf_tcp_close frees conn */ + } + + if (!conn->base.server) { + lwiperf_tcp_client_send_more(conn); + } + + return ERR_OK; +} + +/** This is called when a new client connects for an iperf tcp session */ +static err_t +lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + lwiperf_state_tcp_t *s, *conn; + if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) { + return ERR_VAL; + } + + s = (lwiperf_state_tcp_t*)arg; + conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (conn == NULL) { + return ERR_MEM; + } + memset(conn, 0, sizeof(lwiperf_state_tcp_t)); + conn->base.tcp = 1; + conn->base.server = 1; + conn->base.related_server_state = &s->base; + conn->server_pcb = s->server_pcb; + conn->conn_pcb = newpcb; + conn->time_started = sys_now(); + conn->report_fn = s->report_fn; + conn->report_arg = s->report_arg; + + /* setup the tcp rx connection */ + tcp_arg(newpcb, conn); + tcp_recv(newpcb, lwiperf_tcp_recv); + tcp_poll(newpcb, lwiperf_tcp_poll, 2U); + tcp_err(conn->conn_pcb, lwiperf_tcp_err); + + lwiperf_list_add(&conn->base); + return ERR_OK; +} + +/** + * @ingroup iperf + * Start a TCP iperf server on the default TCP port (5001) and listen for + * incoming connections from iperf clients. + * + * @returns a connection handle that can be used to abort the server + * by calling @ref lwiperf_abort() + */ +void* +lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg) +{ + return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT, + report_fn, report_arg); +} + +/** + * @ingroup iperf + * Start a TCP iperf server on a specific IP address and port and listen for + * incoming connections from iperf clients. + * + * @returns a connection handle that can be used to abort the server + * by calling @ref lwiperf_abort() + */ +void* +lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void* report_arg) +{ + err_t err; + struct tcp_pcb* pcb; + lwiperf_state_tcp_t* s; + + if (local_addr == NULL) { + return NULL; + } + + s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t); + if (s == NULL) { + return NULL; + } + memset(s, 0, sizeof(lwiperf_state_tcp_t)); + s->base.tcp = 1; + s->base.server = 1; + s->report_fn = report_fn; + s->report_arg = report_arg; + + pcb = tcp_new(); + if (pcb != NULL) { + err = tcp_bind(pcb, local_addr, local_port); + if (err == ERR_OK) { + s->server_pcb = tcp_listen_with_backlog(pcb, 1); + } + } + if (s->server_pcb == NULL) { + if (pcb != NULL) { + tcp_close(pcb); + } + LWIPERF_FREE(lwiperf_state_tcp_t, s); + return NULL; + } + pcb = NULL; + + tcp_arg(s->server_pcb, s); + tcp_accept(s->server_pcb, lwiperf_tcp_accept); + + lwiperf_list_add(&s->base); + return s; +} + +/** + * @ingroup iperf + * Abort an iperf session (handle returned by lwiperf_start_tcp_server*()) + */ +void +lwiperf_abort(void* lwiperf_session) +{ + lwiperf_state_base_t* i, *dealloc, *last = NULL; + + for (i = lwiperf_all_connections; i != NULL; ) { + if ((i == lwiperf_session) || (i->related_server_state == lwiperf_session)) { + dealloc = i; + i = i->next; + if (last != NULL) { + last->next = i; + } + LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */ + } else { + last = i; + i = i->next; + } + } +} + +#endif /* LWIP_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/mdns/mdns.c b/Sming/third-party/lwip2/lwip2-src/src/apps/mdns/mdns.c new file mode 100644 index 0000000000..14334fc856 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/mdns/mdns.c @@ -0,0 +1,2028 @@ +/** + * @file + * MDNS responder implementation + * + * @defgroup mdns MDNS + * @ingroup apps + * + * RFC 6762 - Multicast DNS\n + * RFC 6763 - DNS-Based Service Discovery\n + * + * @verbinclude mdns.txt + * + * Things left to implement: + * ------------------------- + * + * - Probing/conflict resolution + * - Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off... + * - Checking that source address of unicast requests are on the same network + * - Limiting multicast responses to 1 per second per resource record + * - Fragmenting replies if required + * - Subscribe to netif address/link change events and act on them (currently needs to be done manually) + * - Handling multi-packet known answers + * - Individual known answer detection for all local IPv6 addresses + * - Dynamic size of outgoing packet + */ + +/* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#include "lwip/apps/mdns.h" +#include "lwip/apps/mdns_priv.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/mem.h" +#include "lwip/prot/dns.h" + +#include + +#if LWIP_MDNS_RESPONDER + +#if (LWIP_IPV4 && !LWIP_IGMP) + #error "If you want to use MDNS with IPv4, you have to define LWIP_IGMP=1 in your lwipopts.h" +#endif +#if (LWIP_IPV6 && !LWIP_IPV6_MLD) +#error "If you want to use MDNS with IPv6, you have to define LWIP_IPV6_MLD=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP) + #error "If you want to use MDNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif + +#if LWIP_IPV4 +#include "lwip/igmp.h" +/* IPv4 multicast group 224.0.0.251 */ +static const ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT; +#endif + +#if LWIP_IPV6 +#include "lwip/mld6.h" +/* IPv6 multicast group FF02::FB */ +static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT; +#endif + +#define MDNS_PORT 5353 +#define MDNS_TTL 255 + +/* Stored offsets to beginning of domain names + * Used for compression. + */ +#define NUM_DOMAIN_OFFSETS 10 +#define DOMAIN_JUMP_SIZE 2 +#define DOMAIN_JUMP 0xc000 + +static u8_t mdns_netif_client_id; +static struct udp_pcb *mdns_pcb; + +#define NETIF_TO_HOST(netif) (struct mdns_host*)(netif_get_client_data(netif, mdns_netif_client_id)) + +#define TOPDOMAIN_LOCAL "local" + +#define REVERSE_PTR_TOPDOMAIN "arpa" +#define REVERSE_PTR_V4_DOMAIN "in-addr" +#define REVERSE_PTR_V6_DOMAIN "ip6" + +#define SRV_PRIORITY 0 +#define SRV_WEIGHT 0 + +/* Payload size allocated for each outgoing UDP packet */ +#define OUTPACKET_SIZE 500 + +/* Lookup from hostname -> IPv4 */ +#define REPLY_HOST_A 0x01 +/* Lookup from IPv4/v6 -> hostname */ +#define REPLY_HOST_PTR_V4 0x02 +/* Lookup from hostname -> IPv6 */ +#define REPLY_HOST_AAAA 0x04 +/* Lookup from hostname -> IPv6 */ +#define REPLY_HOST_PTR_V6 0x08 + +/* Lookup for service types */ +#define REPLY_SERVICE_TYPE_PTR 0x10 +/* Lookup for instances of service */ +#define REPLY_SERVICE_NAME_PTR 0x20 +/* Lookup for location of service instance */ +#define REPLY_SERVICE_SRV 0x40 +/* Lookup for text info on service instance */ +#define REPLY_SERVICE_TXT 0x80 + +static const char *dnssd_protos[] = { + "_udp", /* DNSSD_PROTO_UDP */ + "_tcp", /* DNSSD_PROTO_TCP */ +}; + +/** Description of a service */ +struct mdns_service { + /** TXT record to answer with */ + struct mdns_domain txtdata; + /** Name of service, like 'myweb' */ + char name[MDNS_LABEL_MAXLEN + 1]; + /** Type of service, like '_http' */ + char service[MDNS_LABEL_MAXLEN + 1]; + /** Callback function and userdata + * to update txtdata buffer */ + service_get_txt_fn_t txt_fn; + void *txt_userdata; + /** TTL in seconds of SRV/TXT replies */ + u32_t dns_ttl; + /** Protocol, TCP or UDP */ + u16_t proto; + /** Port of the service */ + u16_t port; +}; + +/** Description of a host/netif */ +struct mdns_host { + /** Hostname */ + char name[MDNS_LABEL_MAXLEN + 1]; + /** Pointer to services */ + struct mdns_service *services[MDNS_MAX_SERVICES]; + /** TTL in seconds of A/AAAA/PTR replies */ + u32_t dns_ttl; +}; + +/** Information about received packet */ +struct mdns_packet { + /** Sender IP/port */ + ip_addr_t source_addr; + u16_t source_port; + /** If packet was received unicast */ + u16_t recv_unicast; + /** Netif that received the packet */ + struct netif *netif; + /** Packet data */ + struct pbuf *pbuf; + /** Current parsing offset in packet */ + u16_t parse_offset; + /** Identifier. Used in legacy queries */ + u16_t tx_id; + /** Number of questions in packet, + * read from packet header */ + u16_t questions; + /** Number of unparsed questions */ + u16_t questions_left; + /** Number of answers in packet, + * (sum of normal, authorative and additional answers) + * read from packet header */ + u16_t answers; + /** Number of unparsed answers */ + u16_t answers_left; +}; + +/** Information about outgoing packet */ +struct mdns_outpacket { + /** Netif to send the packet on */ + struct netif *netif; + /** Packet data */ + struct pbuf *pbuf; + /** Current write offset in packet */ + u16_t write_offset; + /** Identifier. Used in legacy queries */ + u16_t tx_id; + /** Destination IP/port if sent unicast */ + ip_addr_t dest_addr; + u16_t dest_port; + /** Number of questions written */ + u16_t questions; + /** Number of normal answers written */ + u16_t answers; + /** Number of additional answers written */ + u16_t additional; + /** Offsets for written domain names in packet. + * Used for compression */ + u16_t domain_offsets[NUM_DOMAIN_OFFSETS]; + /** If all answers in packet should set cache_flush bit */ + u8_t cache_flush; + /** If reply should be sent unicast */ + u8_t unicast_reply; + /** If legacy query. (tx_id needed, and write + * question again in reply before answer) */ + u8_t legacy_query; + /* Reply bitmask for host information */ + u8_t host_replies; + /* Bitmask for which reverse IPv6 hosts to answer */ + u8_t host_reverse_v6_replies; + /* Reply bitmask per service */ + u8_t serv_replies[MDNS_MAX_SERVICES]; +}; + +/** Domain, type and class. + * Shared between questions and answers */ +struct mdns_rr_info { + struct mdns_domain domain; + u16_t type; + u16_t klass; +}; + +struct mdns_question { + struct mdns_rr_info info; + /** unicast reply requested */ + u16_t unicast; +}; + +struct mdns_answer { + struct mdns_rr_info info; + /** cache flush command bit */ + u16_t cache_flush; + /* Validity time in seconds */ + u32_t ttl; + /** Length of variable answer */ + u16_t rd_length; + /** Offset of start of variable answer in packet */ + u16_t rd_offset; +}; + +/** + * Add a label part to a domain + * @param domain The domain to add a label to + * @param label The label to add, like <hostname>, 'local', 'com' or '' + * @param len The length of the label + * @return ERR_OK on success, an err_t otherwise if label too long + */ +err_t +mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len) +{ + if (len > MDNS_LABEL_MAXLEN) { + return ERR_VAL; + } + if (len > 0 && (1 + len + domain->length >= MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + /* Allow only zero marker on last byte */ + if (len == 0 && (1 + domain->length > MDNS_DOMAIN_MAXLEN)) { + return ERR_VAL; + } + domain->name[domain->length] = len; + domain->length++; + if (len) { + MEMCPY(&domain->name[domain->length], label, len); + domain->length += len; + } + return ERR_OK; +} + +/** + * Internal readname function with max 6 levels of recursion following jumps + * while decompressing name + */ +static u16_t +mdns_readname_loop(struct pbuf *p, u16_t offset, struct mdns_domain *domain, unsigned depth) +{ + u8_t c; + + do { + if (depth > 5) { + /* Too many jumps */ + return MDNS_READNAME_ERROR; + } + + c = pbuf_get_at(p, offset); + offset++; + + /* is this a compressed label? */ + if((c & 0xc0) == 0xc0) { + u16_t jumpaddr; + if (offset >= p->tot_len) { + /* Make sure both jump bytes fit in the packet */ + return MDNS_READNAME_ERROR; + } + jumpaddr = (((c & 0x3f) << 8) | (pbuf_get_at(p, offset) & 0xff)); + offset++; + if (jumpaddr >= SIZEOF_DNS_HDR && jumpaddr < p->tot_len) { + u16_t res; + /* Recursive call, maximum depth will be checked */ + res = mdns_readname_loop(p, jumpaddr, domain, depth + 1); + /* Dont return offset since new bytes were not read (jumped to somewhere in packet) */ + if (res == MDNS_READNAME_ERROR) { + return res; + } + } else { + return MDNS_READNAME_ERROR; + } + break; + } + + /* normal label */ + if (c <= MDNS_LABEL_MAXLEN) { + u8_t label[MDNS_LABEL_MAXLEN]; + err_t res; + + if (c + domain->length >= MDNS_DOMAIN_MAXLEN) { + return MDNS_READNAME_ERROR; + } + if (c != 0) { + if (pbuf_copy_partial(p, label, c, offset) != c) { + return MDNS_READNAME_ERROR; + } + offset += c; + } + res = mdns_domain_add_label(domain, (char *) label, c); + if (res != ERR_OK) { + return MDNS_READNAME_ERROR; + } + } else { + /* bad length byte */ + return MDNS_READNAME_ERROR; + } + } while (c != 0); + + return offset; +} + +/** + * Read possibly compressed domain name from packet buffer + * @param p The packet + * @param offset start position of domain name in packet + * @param domain The domain name destination + * @return The new offset after the domain, or MDNS_READNAME_ERROR + * if reading failed + */ +u16_t +mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain) +{ + memset(domain, 0, sizeof(struct mdns_domain)); + return mdns_readname_loop(p, offset, domain, 0); +} + +/** + * Print domain name to debug output + * @param domain The domain name + */ +static void +mdns_domain_debug_print(struct mdns_domain *domain) +{ + u8_t *src = domain->name; + u8_t i; + + while (*src) { + u8_t label_len = *src; + src++; + for (i = 0; i < label_len; i++) { + LWIP_DEBUGF(MDNS_DEBUG, ("%c", src[i])); + } + src += label_len; + LWIP_DEBUGF(MDNS_DEBUG, (".")); + } +} + +/** + * Return 1 if contents of domains match (case-insensitive) + * @param a Domain name to compare 1 + * @param b Domain name to compare 2 + * @return 1 if domains are equal ignoring case, 0 otherwise + */ +int +mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b) +{ + u8_t *ptra, *ptrb; + u8_t len; + int res; + + if (a->length != b->length) { + return 0; + } + + ptra = a->name; + ptrb = b->name; + while (*ptra && *ptrb && ptra < &a->name[a->length]) { + if (*ptra != *ptrb) { + return 0; + } + len = *ptra; + ptra++; + ptrb++; + res = lwip_strnicmp((char *) ptra, (char *) ptrb, len); + if (res != 0) { + return 0; + } + ptra += len; + ptrb += len; + } + if (*ptra != *ptrb && ptra < &a->name[a->length]) { + return 0; + } + return 1; +} + +/** + * Call user supplied function to setup TXT data + * @param service The service to build TXT record for + */ +static void +mdns_prepare_txtdata(struct mdns_service *service) +{ + memset(&service->txtdata, 0, sizeof(struct mdns_domain)); + if (service->txt_fn) { + service->txt_fn(service, service->txt_userdata); + } +} + +#if LWIP_IPV4 +/** + * Build domain for reverse lookup of IPv4 address + * like 12.0.168.192.in-addr.arpa. for 192.168.0.12 + * @param domain Where to write the domain name + * @param addr Pointer to an IPv4 address to encode + * @return ERR_OK if domain was written, an err_t otherwise + */ +static err_t +mdns_build_reverse_v4_domain(struct mdns_domain *domain, const ip4_addr_t *addr) +{ + int i; + err_t res; + const u8_t *ptr; + if (!domain || !addr) { + return ERR_ARG; + } + memset(domain, 0, sizeof(struct mdns_domain)); + ptr = (const u8_t *) addr; + for (i = sizeof(ip4_addr_t) - 1; i >= 0; i--) { + char buf[4]; + u8_t val = ptr[i]; + + lwip_itoa(buf, sizeof(buf), val); + res = mdns_domain_add_label(domain, buf, (u8_t)strlen(buf)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + } + res = mdns_domain_add_label(domain, REVERSE_PTR_V4_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V4_DOMAIN)-1)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN)-1)); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, NULL, 0); + LWIP_ERROR("mdns_build_reverse_v4_domain: Failed to add label", (res == ERR_OK), return res); + + return ERR_OK; +} +#endif + +#if LWIP_IPV6 +/** + * Build domain for reverse lookup of IP address + * like b.a.9.8.7.6.5.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.ip6.arpa. for 2001:db8::567:89ab + * @param domain Where to write the domain name + * @param addr Pointer to an IPv6 address to encode + * @return ERR_OK if domain was written, an err_t otherwise + */ +static err_t +mdns_build_reverse_v6_domain(struct mdns_domain *domain, const ip6_addr_t *addr) +{ + int i; + err_t res; + const u8_t *ptr; + if (!domain || !addr) { + return ERR_ARG; + } + memset(domain, 0, sizeof(struct mdns_domain)); + ptr = (const u8_t *) addr; + for (i = sizeof(ip6_addr_t) - 1; i >= 0; i--) { + char buf; + u8_t byte = ptr[i]; + int j; + for (j = 0; j < 2; j++) { + if ((byte & 0x0F) < 0xA) { + buf = '0' + (byte & 0x0F); + } else { + buf = 'a' + (byte & 0x0F) - 0xA; + } + res = mdns_domain_add_label(domain, &buf, sizeof(buf)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + byte >>= 4; + } + } + res = mdns_domain_add_label(domain, REVERSE_PTR_V6_DOMAIN, (u8_t)(sizeof(REVERSE_PTR_V6_DOMAIN)-1)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, REVERSE_PTR_TOPDOMAIN, (u8_t)(sizeof(REVERSE_PTR_TOPDOMAIN)-1)); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, NULL, 0); + LWIP_ERROR("mdns_build_reverse_v6_domain: Failed to add label", (res == ERR_OK), return res); + + return ERR_OK; +} +#endif + +/* Add .local. to domain */ +static err_t +mdns_add_dotlocal(struct mdns_domain *domain) +{ + err_t res = mdns_domain_add_label(domain, TOPDOMAIN_LOCAL, (u8_t)(sizeof(TOPDOMAIN_LOCAL)-1)); + LWIP_ERROR("mdns_add_dotlocal: Failed to add label", (res == ERR_OK), return res); + return mdns_domain_add_label(domain, NULL, 0); +} + +/** + * Build the .local. domain name + * @param domain Where to write the domain name + * @param mdns TMDNS netif descriptor. + * @return ERR_OK if domain .local. was written, an err_t otherwise + */ +static err_t +mdns_build_host_domain(struct mdns_domain *domain, struct mdns_host *mdns) +{ + err_t res; + memset(domain, 0, sizeof(struct mdns_domain)); + LWIP_ERROR("mdns_build_host_domain: mdns != NULL", (mdns != NULL), return ERR_VAL); + res = mdns_domain_add_label(domain, mdns->name, (u8_t)strlen(mdns->name)); + LWIP_ERROR("mdns_build_host_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +/** + * Build the lookup-all-services special DNS-SD domain name + * @param domain Where to write the domain name + * @return ERR_OK if domain _services._dns-sd._udp.local. was written, an err_t otherwise + */ +static err_t +mdns_build_dnssd_domain(struct mdns_domain *domain) +{ + err_t res; + memset(domain, 0, sizeof(struct mdns_domain)); + res = mdns_domain_add_label(domain, "_services", (u8_t)(sizeof("_services")-1)); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, "_dns-sd", (u8_t)(sizeof("_dns-sd")-1)); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, dnssd_protos[DNSSD_PROTO_UDP], (u8_t)strlen(dnssd_protos[DNSSD_PROTO_UDP])); + LWIP_ERROR("mdns_build_dnssd_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +/** + * Build domain name for a service + * @param domain Where to write the domain name + * @param service The service struct, containing service name, type and protocol + * @param include_name Whether to include the service name in the domain + * @return ERR_OK if domain was written. If service name is included, + * ...local. will be written, otherwise ..local. + * An err_t is returned on error. + */ +static err_t +mdns_build_service_domain(struct mdns_domain *domain, struct mdns_service *service, int include_name) +{ + err_t res; + memset(domain, 0, sizeof(struct mdns_domain)); + if (include_name) { + res = mdns_domain_add_label(domain, service->name, (u8_t)strlen(service->name)); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + } + res = mdns_domain_add_label(domain, service->service, (u8_t)strlen(service->service)); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + res = mdns_domain_add_label(domain, dnssd_protos[service->proto], (u8_t)strlen(dnssd_protos[service->proto])); + LWIP_ERROR("mdns_build_service_domain: Failed to add label", (res == ERR_OK), return res); + return mdns_add_dotlocal(domain); +} + +/** + * Check which replies we should send for a host/netif based on question + * @param netif The network interface that received the question + * @param rr Domain/type/class from a question + * @param reverse_v6_reply Bitmask of which IPv6 addresses to send reverse PTRs for + * if reply bit has REPLY_HOST_PTR_V6 set + * @return Bitmask of which replies to send + */ +static int +check_host(struct netif *netif, struct mdns_rr_info *rr, u8_t *reverse_v6_reply) +{ + err_t res; + int replies = 0; + struct mdns_domain mydomain; + + LWIP_UNUSED_ARG(reverse_v6_reply); /* if ipv6 is disabled */ + + if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) { + /* Invalid class */ + return replies; + } + + /* Handle PTR for our addresses */ + if (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY) { +#if LWIP_IPV6 + int i; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { + res = mdns_build_reverse_v6_domain(&mydomain, netif_ip6_addr(netif, i)); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) { + replies |= REPLY_HOST_PTR_V6; + /* Mark which addresses where requested */ + if (reverse_v6_reply) { + *reverse_v6_reply |= (1 << i); + } + } + } + } +#endif +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { + res = mdns_build_reverse_v4_domain(&mydomain, netif_ip4_addr(netif)); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) { + replies |= REPLY_HOST_PTR_V4; + } + } +#endif + } + + res = mdns_build_host_domain(&mydomain, NETIF_TO_HOST(netif)); + /* Handle requests for our hostname */ + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) { + /* TODO return NSEC if unsupported protocol requested */ +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) + && (rr->type == DNS_RRTYPE_A || rr->type == DNS_RRTYPE_ANY)) { + replies |= REPLY_HOST_A; + } +#endif +#if LWIP_IPV6 + if (rr->type == DNS_RRTYPE_AAAA || rr->type == DNS_RRTYPE_ANY) { + replies |= REPLY_HOST_AAAA; + } +#endif + } + + return replies; +} + +/** + * Check which replies we should send for a service based on question + * @param service A registered MDNS service + * @param rr Domain/type/class from a question + * @return Bitmask of which replies to send + */ +static int +check_service(struct mdns_service *service, struct mdns_rr_info *rr) +{ + err_t res; + int replies = 0; + struct mdns_domain mydomain; + + if (rr->klass != DNS_RRCLASS_IN && rr->klass != DNS_RRCLASS_ANY) { + /* Invalid class */ + return 0; + } + + res = mdns_build_dnssd_domain(&mydomain); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) && + (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) { + /* Request for all service types */ + replies |= REPLY_SERVICE_TYPE_PTR; + } + + res = mdns_build_service_domain(&mydomain, service, 0); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain) && + (rr->type == DNS_RRTYPE_PTR || rr->type == DNS_RRTYPE_ANY)) { + /* Request for the instance of my service */ + replies |= REPLY_SERVICE_NAME_PTR; + } + + res = mdns_build_service_domain(&mydomain, service, 1); + if (res == ERR_OK && mdns_domain_eq(&rr->domain, &mydomain)) { + /* Request for info about my service */ + if (rr->type == DNS_RRTYPE_SRV || rr->type == DNS_RRTYPE_ANY) { + replies |= REPLY_SERVICE_SRV; + } + if (rr->type == DNS_RRTYPE_TXT || rr->type == DNS_RRTYPE_ANY) { + replies |= REPLY_SERVICE_TXT; + } + } + + return replies; +} + +/** + * Return bytes needed to write before jump for best result of compressing supplied domain + * against domain in outpacket starting at specified offset. + * If a match is found, offset is updated to where to jump to + * @param pbuf Pointer to pbuf with the partially constructed DNS packet + * @param offset Start position of a domain written earlier. If this location is suitable + * for compression, the pointer is updated to where in the domain to jump to. + * @param domain The domain to write + * @return Number of bytes to write of the new domain before writing a jump to the offset. + * If compression can not be done against this previous domain name, the full new + * domain length is returned. + */ +u16_t +mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain) +{ + struct mdns_domain target; + u16_t target_end; + u8_t target_len; + u8_t writelen = 0; + u8_t *ptr; + if (pbuf == NULL) { + return domain->length; + } + target_end = mdns_readname(pbuf, *offset, &target); + if (target_end == MDNS_READNAME_ERROR) { + return domain->length; + } + target_len = (u8_t)(target_end - *offset); + ptr = domain->name; + while (writelen < domain->length) { + u8_t domainlen = (u8_t)(domain->length - writelen); + u8_t labellen; + if (domainlen <= target.length && domainlen > DOMAIN_JUMP_SIZE) { + /* Compare domains if target is long enough, and we have enough left of the domain */ + u8_t targetpos = (u8_t)(target.length - domainlen); + if ((targetpos + DOMAIN_JUMP_SIZE) >= target_len) { + /* We are checking at or beyond a jump in the original, stop looking */ + break; + } + if (target.length >= domainlen && + memcmp(&domain->name[writelen], &target.name[targetpos], domainlen) == 0) { + *offset += targetpos; + return writelen; + } + } + /* Skip to next label in domain */ + labellen = *ptr; + writelen += 1 + labellen; + ptr += 1 + labellen; + } + /* Nothing found */ + return domain->length; +} + +/** + * Write domain to outpacket. Compression will be attempted, + * unless domain->skip_compression is set. + * @param outpkt The outpacket to write to + * @param domain The domain name to write + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_write_domain(struct mdns_outpacket *outpkt, struct mdns_domain *domain) +{ + int i; + err_t res; + u16_t writelen = domain->length; + u16_t jump_offset = 0; + u16_t jump; + + if (!domain->skip_compression) { + for (i = 0; i < NUM_DOMAIN_OFFSETS; ++i) { + u16_t offset = outpkt->domain_offsets[i]; + if (offset) { + u16_t len = mdns_compress_domain(outpkt->pbuf, &offset, domain); + if (len < writelen) { + writelen = len; + jump_offset = offset; + } + } + } + } + + if (writelen) { + /* Write uncompressed part of name */ + res = pbuf_take_at(outpkt->pbuf, domain->name, writelen, outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + + /* Store offset of this new domain */ + for (i = 0; i < NUM_DOMAIN_OFFSETS; ++i) { + if (outpkt->domain_offsets[i] == 0) { + outpkt->domain_offsets[i] = outpkt->write_offset; + break; + } + } + + outpkt->write_offset += writelen; + } + if (jump_offset) { + /* Write jump */ + jump = lwip_htons(DOMAIN_JUMP | jump_offset); + res = pbuf_take_at(outpkt->pbuf, &jump, DOMAIN_JUMP_SIZE, outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += DOMAIN_JUMP_SIZE; + } + return ERR_OK; +} + +/** + * Write a question to an outpacket + * A question contains domain, type and class. Since an answer also starts with these fields this function is also + * called from mdns_add_answer(). + * @param outpkt The outpacket to write to + * @param domain The domain name the answer is for + * @param type The DNS type of the answer (like 'AAAA', 'SRV') + * @param klass The DNS type of the answer (like 'IN') + * @param unicast If highest bit in class should be set, to instruct the responder to + * reply with a unicast packet + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_add_question(struct mdns_outpacket *outpkt, struct mdns_domain *domain, u16_t type, u16_t klass, u16_t unicast) +{ + u16_t question_len; + u16_t field16; + err_t res; + + if (!outpkt->pbuf) { + /* If no pbuf is active, allocate one */ + outpkt->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM); + if (!outpkt->pbuf) { + return ERR_MEM; + } + outpkt->write_offset = SIZEOF_DNS_HDR; + } + + /* Worst case calculation. Domain string might be compressed */ + question_len = domain->length + sizeof(type) + sizeof(klass); + if (outpkt->write_offset + question_len > outpkt->pbuf->tot_len) { + /* No space */ + return ERR_MEM; + } + + /* Write name */ + res = mdns_write_domain(outpkt, domain); + if (res != ERR_OK) { + return res; + } + + /* Write type */ + field16 = lwip_htons(type); + res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += sizeof(field16); + + /* Write class */ + if (unicast) { + klass |= 0x8000; + } + field16 = lwip_htons(klass); + res = pbuf_take_at(outpkt->pbuf, &field16, sizeof(field16), outpkt->write_offset); + if (res != ERR_OK) { + return res; + } + outpkt->write_offset += sizeof(field16); + + return ERR_OK; +} + +/** + * Write answer to reply packet. + * buf or answer_domain can be null. The rd_length written will be buf_length + + * size of (compressed) domain. Most uses will need either buf or answer_domain, + * special case is SRV that starts with 3 u16 and then a domain name. + * @param reply The outpacket to write to + * @param domain The domain name the answer is for + * @param type The DNS type of the answer (like 'AAAA', 'SRV') + * @param klass The DNS type of the answer (like 'IN') + * @param cache_flush If highest bit in class should be set, to instruct receiver that + * this reply replaces any earlier answer for this domain/type/class + * @param ttl Validity time in seconds to send out for IP address data in DNS replies + * @param buf Pointer to buffer of answer data + * @param buf_length Length of variable data + * @param answer_domain A domain to write after any buffer data as answer + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_add_answer(struct mdns_outpacket *reply, struct mdns_domain *domain, u16_t type, u16_t klass, u16_t cache_flush, + u32_t ttl, const u8_t *buf, size_t buf_length, struct mdns_domain *answer_domain) +{ + u16_t answer_len; + u16_t field16; + u16_t rdlen_offset; + u16_t answer_offset; + u32_t field32; + err_t res; + + if (!reply->pbuf) { + /* If no pbuf is active, allocate one */ + reply->pbuf = pbuf_alloc(PBUF_TRANSPORT, OUTPACKET_SIZE, PBUF_RAM); + if (!reply->pbuf) { + return ERR_MEM; + } + reply->write_offset = SIZEOF_DNS_HDR; + } + + /* Worst case calculation. Domain strings might be compressed */ + answer_len = domain->length + sizeof(type) + sizeof(klass) + sizeof(ttl) + sizeof(field16)/*rd_length*/; + if (buf) { + answer_len += (u16_t)buf_length; + } + if (answer_domain) { + answer_len += answer_domain->length; + } + if (reply->write_offset + answer_len > reply->pbuf->tot_len) { + /* No space */ + return ERR_MEM; + } + + /* Answer starts with same data as question, then more fields */ + mdns_add_question(reply, domain, type, klass, cache_flush); + + /* Write TTL */ + field32 = lwip_htonl(ttl); + res = pbuf_take_at(reply->pbuf, &field32, sizeof(field32), reply->write_offset); + if (res != ERR_OK) { + return res; + } + reply->write_offset += sizeof(field32); + + /* Store offsets and skip forward to the data */ + rdlen_offset = reply->write_offset; + reply->write_offset += sizeof(field16); + answer_offset = reply->write_offset; + + if (buf) { + /* Write static data */ + res = pbuf_take_at(reply->pbuf, buf, (u16_t)buf_length, reply->write_offset); + if (res != ERR_OK) { + return res; + } + reply->write_offset += (u16_t)buf_length; + } + + if (answer_domain) { + /* Write name answer (compressed if possible) */ + res = mdns_write_domain(reply, answer_domain); + if (res != ERR_OK) { + return res; + } + } + + /* Write rd_length after when we know the answer size */ + field16 = lwip_htons(reply->write_offset - answer_offset); + res = pbuf_take_at(reply->pbuf, &field16, sizeof(field16), rdlen_offset); + + return res; +} + +/** + * Helper function for mdns_read_question/mdns_read_answer + * Reads a domain, type and class from the packet + * @param pkt The MDNS packet to read from. The parse_offset field will be + * incremented to point to the next unparsed byte. + * @param info The struct to fill with domain, type and class + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_read_rr_info(struct mdns_packet *pkt, struct mdns_rr_info *info) +{ + u16_t field16, copied; + pkt->parse_offset = mdns_readname(pkt->pbuf, pkt->parse_offset, &info->domain); + if (pkt->parse_offset == MDNS_READNAME_ERROR) { + return ERR_VAL; + } + + copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); + if (copied != sizeof(field16)) { + return ERR_VAL; + } + pkt->parse_offset += copied; + info->type = lwip_ntohs(field16); + + copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); + if (copied != sizeof(field16)) { + return ERR_VAL; + } + pkt->parse_offset += copied; + info->klass = lwip_ntohs(field16); + + return ERR_OK; +} + +/** + * Read a question from the packet. + * All questions have to be read before the answers. + * @param pkt The MDNS packet to read from. The questions_left field will be decremented + * and the parse_offset will be updated. + * @param question The struct to fill with question data + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_read_question(struct mdns_packet *pkt, struct mdns_question *question) +{ + /* Safety check */ + if (pkt->pbuf->tot_len < pkt->parse_offset) { + return ERR_VAL; + } + + if (pkt->questions_left) { + err_t res; + pkt->questions_left--; + + memset(question, 0, sizeof(struct mdns_question)); + res = mdns_read_rr_info(pkt, &question->info); + if (res != ERR_OK) { + return res; + } + + /* Extract unicast flag from class field */ + question->unicast = question->info.klass & 0x8000; + question->info.klass &= 0x7FFF; + + return ERR_OK; + } + return ERR_VAL; +} + +/** + * Read an answer from the packet + * The variable length reply is not copied, its pbuf offset and length is stored instead. + * @param pkt The MDNS packet to read. The answers_left field will be decremented and + * the parse_offset will be updated. + * @param answer The struct to fill with answer data + * @return ERR_OK on success, an err_t otherwise + */ +static err_t +mdns_read_answer(struct mdns_packet *pkt, struct mdns_answer *answer) +{ + /* Read questions first */ + if (pkt->questions_left) { + return ERR_VAL; + } + + /* Safety check */ + if (pkt->pbuf->tot_len < pkt->parse_offset) { + return ERR_VAL; + } + + if (pkt->answers_left) { + u16_t copied, field16; + u32_t ttl; + err_t res; + pkt->answers_left--; + + memset(answer, 0, sizeof(struct mdns_answer)); + res = mdns_read_rr_info(pkt, &answer->info); + if (res != ERR_OK) { + return res; + } + + /* Extract cache_flush flag from class field */ + answer->cache_flush = answer->info.klass & 0x8000; + answer->info.klass &= 0x7FFF; + + copied = pbuf_copy_partial(pkt->pbuf, &ttl, sizeof(ttl), pkt->parse_offset); + if (copied != sizeof(ttl)) { + return ERR_VAL; + } + pkt->parse_offset += copied; + answer->ttl = lwip_ntohl(ttl); + + copied = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), pkt->parse_offset); + if (copied != sizeof(field16)) { + return ERR_VAL; + } + pkt->parse_offset += copied; + answer->rd_length = lwip_ntohs(field16); + + answer->rd_offset = pkt->parse_offset; + pkt->parse_offset += answer->rd_length; + + return ERR_OK; + } + return ERR_VAL; +} + +#if LWIP_IPV4 +/** Write an IPv4 address (A) RR to outpacket */ +static err_t +mdns_add_a_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif) +{ + struct mdns_domain host; + mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with A record\n")); + return mdns_add_answer(reply, &host, DNS_RRTYPE_A, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, (const u8_t *) netif_ip4_addr(netif), sizeof(ip4_addr_t), NULL); +} + +/** Write a 4.3.2.1.in-addr.arpa -> hostname.local PTR RR to outpacket */ +static err_t +mdns_add_hostv4_ptr_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif) +{ + struct mdns_domain host, revhost; + mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); + mdns_build_reverse_v4_domain(&revhost, netif_ip4_addr(netif)); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v4 PTR record\n")); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, NULL, 0, &host); +} +#endif + +#if LWIP_IPV6 +/** Write an IPv6 address (AAAA) RR to outpacket */ +static err_t +mdns_add_aaaa_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif, int addrindex) +{ + struct mdns_domain host; + mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with AAAA record\n")); + return mdns_add_answer(reply, &host, DNS_RRTYPE_AAAA, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, (const u8_t *) netif_ip6_addr(netif, addrindex), sizeof(ip6_addr_t), NULL); +} + +/** Write a x.y.z.ip6.arpa -> hostname.local PTR RR to outpacket */ +static err_t +mdns_add_hostv6_ptr_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct netif *netif, int addrindex) +{ + struct mdns_domain host, revhost; + mdns_build_host_domain(&host, NETIF_TO_HOST(netif)); + mdns_build_reverse_v6_domain(&revhost, netif_ip6_addr(netif, addrindex)); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with v6 PTR record\n")); + return mdns_add_answer(reply, &revhost, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, cache_flush, (NETIF_TO_HOST(netif))->dns_ttl, NULL, 0, &host); +} +#endif + +/** Write an all-services -> servicetype PTR RR to outpacket */ +static err_t +mdns_add_servicetype_ptr_answer(struct mdns_outpacket *reply, struct mdns_service *service) +{ + struct mdns_domain service_type, service_dnssd; + mdns_build_service_domain(&service_type, service, 0); + mdns_build_dnssd_domain(&service_dnssd); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service type PTR record\n")); + return mdns_add_answer(reply, &service_dnssd, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0, service->dns_ttl, NULL, 0, &service_type); +} + +/** Write a servicetype -> servicename PTR RR to outpacket */ +static err_t +mdns_add_servicename_ptr_answer(struct mdns_outpacket *reply, struct mdns_service *service) +{ + struct mdns_domain service_type, service_instance; + mdns_build_service_domain(&service_type, service, 0); + mdns_build_service_domain(&service_instance, service, 1); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with service name PTR record\n")); + return mdns_add_answer(reply, &service_type, DNS_RRTYPE_PTR, DNS_RRCLASS_IN, 0, service->dns_ttl, NULL, 0, &service_instance); +} + +/** Write a SRV RR to outpacket */ +static err_t +mdns_add_srv_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct mdns_host *mdns, struct mdns_service *service) +{ + struct mdns_domain service_instance, srvhost; + u16_t srvdata[3]; + mdns_build_service_domain(&service_instance, service, 1); + mdns_build_host_domain(&srvhost, mdns); + if (reply->legacy_query) { + /* RFC 6762 section 18.14: + * In legacy unicast responses generated to answer legacy queries, + * name compression MUST NOT be performed on SRV records. + */ + srvhost.skip_compression = 1; + } + srvdata[0] = lwip_htons(SRV_PRIORITY); + srvdata[1] = lwip_htons(SRV_WEIGHT); + srvdata[2] = lwip_htons(service->port); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with SRV record\n")); + return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, cache_flush, service->dns_ttl, + (const u8_t *) &srvdata, sizeof(srvdata), &srvhost); +} + +/** Write a TXT RR to outpacket */ +static err_t +mdns_add_txt_answer(struct mdns_outpacket *reply, u16_t cache_flush, struct mdns_service *service) +{ + struct mdns_domain service_instance; + mdns_build_service_domain(&service_instance, service, 1); + mdns_prepare_txtdata(service); + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Responding with TXT record\n")); + return mdns_add_answer(reply, &service_instance, DNS_RRTYPE_TXT, DNS_RRCLASS_IN, cache_flush, service->dns_ttl, + (u8_t *) &service->txtdata.name, service->txtdata.length, NULL); +} + +/** + * Setup outpacket as a reply to the incoming packet + */ +static void +mdns_init_outpacket(struct mdns_outpacket *out, struct mdns_packet *in) +{ + memset(out, 0, sizeof(struct mdns_outpacket)); + out->cache_flush = 1; + out->netif = in->netif; + + /* Copy source IP/port to use when responding unicast, or to choose + * which pcb to use for multicast (IPv4/IPv6) + */ + SMEMCPY(&out->dest_addr, &in->source_addr, sizeof(ip_addr_t)); + out->dest_port = in->source_port; + + if (in->source_port != MDNS_PORT) { + out->unicast_reply = 1; + out->cache_flush = 0; + if (in->questions == 1) { + out->legacy_query = 1; + out->tx_id = in->tx_id; + } + } + + if (in->recv_unicast) { + out->unicast_reply = 1; + } +} + +/** + * Send chosen answers as a reply + * + * Add all selected answers (first write will allocate pbuf) + * Add additional answers based on the selected answers + * Send the packet + */ +static void +mdns_send_outpacket(struct mdns_outpacket *outpkt) +{ + struct mdns_service *service; + err_t res; + int i; + struct mdns_host* mdns = NETIF_TO_HOST(outpkt->netif); + + /* Write answers to host questions */ +#if LWIP_IPV4 + if (outpkt->host_replies & REPLY_HOST_A) { + res = mdns_add_a_answer(outpkt, outpkt->cache_flush, outpkt->netif); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + if (outpkt->host_replies & REPLY_HOST_PTR_V4) { + res = mdns_add_hostv4_ptr_answer(outpkt, outpkt->cache_flush, outpkt->netif); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } +#endif +#if LWIP_IPV6 + if (outpkt->host_replies & REPLY_HOST_AAAA) { + int addrindex; + for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; ++addrindex) { + if (ip6_addr_isvalid(netif_ip6_addr_state(outpkt->netif, addrindex))) { + res = mdns_add_aaaa_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + } + } + if (outpkt->host_replies & REPLY_HOST_PTR_V6) { + u8_t rev_addrs = outpkt->host_reverse_v6_replies; + int addrindex = 0; + while (rev_addrs) { + if (rev_addrs & 1) { + res = mdns_add_hostv6_ptr_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + addrindex++; + rev_addrs >>= 1; + } + } +#endif + + /* Write answers to service questions */ + for (i = 0; i < MDNS_MAX_SERVICES; ++i) { + service = mdns->services[i]; + if (!service) { + continue; + } + + if (outpkt->serv_replies[i] & REPLY_SERVICE_TYPE_PTR) { + res = mdns_add_servicetype_ptr_answer(outpkt, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + + if (outpkt->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { + res = mdns_add_servicename_ptr_answer(outpkt, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + + if (outpkt->serv_replies[i] & REPLY_SERVICE_SRV) { + res = mdns_add_srv_answer(outpkt, outpkt->cache_flush, mdns, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + + if (outpkt->serv_replies[i] & REPLY_SERVICE_TXT) { + res = mdns_add_txt_answer(outpkt, outpkt->cache_flush, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->answers++; + } + } + + /* All answers written, add additional RRs */ + for (i = 0; i < MDNS_MAX_SERVICES; ++i) { + service = mdns->services[i]; + if (!service) { + continue; + } + + if (outpkt->serv_replies[i] & REPLY_SERVICE_NAME_PTR) { + /* Our service instance requested, include SRV & TXT + * if they are already not requested. */ + if (!(outpkt->serv_replies[i] & REPLY_SERVICE_SRV)) { + res = mdns_add_srv_answer(outpkt, outpkt->cache_flush, mdns, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->additional++; + } + + if (!(outpkt->serv_replies[i] & REPLY_SERVICE_TXT)) { + res = mdns_add_txt_answer(outpkt, outpkt->cache_flush, service); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->additional++; + } + } + + /* If service instance, SRV, record or an IP address is requested, + * supply all addresses for the host + */ + if ((outpkt->serv_replies[i] & (REPLY_SERVICE_NAME_PTR | REPLY_SERVICE_SRV)) || + (outpkt->host_replies & (REPLY_HOST_A | REPLY_HOST_AAAA))) { +#if LWIP_IPV6 + if (!(outpkt->host_replies & REPLY_HOST_AAAA)) { + int addrindex; + for (addrindex = 0; addrindex < LWIP_IPV6_NUM_ADDRESSES; ++addrindex) { + if (ip6_addr_isvalid(netif_ip6_addr_state(outpkt->netif, addrindex))) { + res = mdns_add_aaaa_answer(outpkt, outpkt->cache_flush, outpkt->netif, addrindex); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->additional++; + } + } + } +#endif +#if LWIP_IPV4 + if (!(outpkt->host_replies & REPLY_HOST_A)) { + res = mdns_add_a_answer(outpkt, outpkt->cache_flush, outpkt->netif); + if (res != ERR_OK) { + goto cleanup; + } + outpkt->additional++; + } +#endif + } + } + + if (outpkt->pbuf) { + const ip_addr_t *mcast_destaddr; + struct dns_hdr hdr; + + /* Write header */ + memset(&hdr, 0, sizeof(hdr)); + hdr.flags1 = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; + hdr.numanswers = lwip_htons(outpkt->answers); + hdr.numextrarr = lwip_htons(outpkt->additional); + if (outpkt->legacy_query) { + hdr.numquestions = lwip_htons(1); + hdr.id = lwip_htons(outpkt->tx_id); + } + pbuf_take(outpkt->pbuf, &hdr, sizeof(hdr)); + + /* Shrink packet */ + pbuf_realloc(outpkt->pbuf, outpkt->write_offset); + + if (IP_IS_V6_VAL(outpkt->dest_addr)) { +#if LWIP_IPV6 + mcast_destaddr = &v6group; +#endif + } else { +#if LWIP_IPV4 + mcast_destaddr = &v4group; +#endif + } + /* Send created packet */ + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Sending packet, len=%d, unicast=%d\n", outpkt->write_offset, outpkt->unicast_reply)); + if (outpkt->unicast_reply) { + udp_sendto_if(mdns_pcb, outpkt->pbuf, &outpkt->dest_addr, outpkt->dest_port, outpkt->netif); + } else { + udp_sendto_if(mdns_pcb, outpkt->pbuf, mcast_destaddr, MDNS_PORT, outpkt->netif); + } + } + +cleanup: + if (outpkt->pbuf) { + pbuf_free(outpkt->pbuf); + outpkt->pbuf = NULL; + } +} + +/** + * Send unsolicited answer containing all our known data + * @param netif The network interface to send on + * @param destination The target address to send to (usually multicast address) + */ +static void +mdns_announce(struct netif *netif, const ip_addr_t *destination) +{ + struct mdns_outpacket announce; + int i; + struct mdns_host* mdns = NETIF_TO_HOST(netif); + + memset(&announce, 0, sizeof(announce)); + announce.netif = netif; + announce.cache_flush = 1; +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) + announce.host_replies = REPLY_HOST_A | REPLY_HOST_PTR_V4; +#endif +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { + announce.host_replies |= REPLY_HOST_AAAA | REPLY_HOST_PTR_V6; + announce.host_reverse_v6_replies |= (1 << i); + } + } +#endif + + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + struct mdns_service *serv = mdns->services[i]; + if (serv) { + announce.serv_replies[i] = REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR | + REPLY_SERVICE_SRV | REPLY_SERVICE_TXT; + } + } + + announce.dest_port = MDNS_PORT; + SMEMCPY(&announce.dest_addr, destination, sizeof(announce.dest_addr)); + mdns_send_outpacket(&announce); +} + +/** + * Handle question MDNS packet + * 1. Parse all questions and set bits what answers to send + * 2. Clear pending answers if known answers are supplied + * 3. Put chosen answers in new packet and send as reply + */ +static void +mdns_handle_question(struct mdns_packet *pkt) +{ + struct mdns_service *service; + struct mdns_outpacket reply; + int replies = 0; + int i; + err_t res; + struct mdns_host* mdns = NETIF_TO_HOST(pkt->netif); + + mdns_init_outpacket(&reply, pkt); + + while (pkt->questions_left) { + struct mdns_question q; + + res = mdns_read_question(pkt, &q); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping query packet\n")); + return; + } + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Query for domain ")); + mdns_domain_debug_print(&q.info.domain); + LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", q.info.type, q.info.klass)); + + if (q.unicast) { + /* Reply unicast if any question is unicast */ + reply.unicast_reply = 1; + } + + reply.host_replies |= check_host(pkt->netif, &q.info, &reply.host_reverse_v6_replies); + replies |= reply.host_replies; + + for (i = 0; i < MDNS_MAX_SERVICES; ++i) { + service = mdns->services[i]; + if (!service) { + continue; + } + reply.serv_replies[i] |= check_service(service, &q.info); + replies |= reply.serv_replies[i]; + } + + if (replies && reply.legacy_query) { + /* Add question to reply packet (legacy packet only has 1 question) */ + res = mdns_add_question(&reply, &q.info.domain, q.info.type, q.info.klass, 0); + if (res != ERR_OK) { + goto cleanup; + } + } + } + + /* Handle known answers */ + while (pkt->answers_left) { + struct mdns_answer ans; + u8_t rev_v6; + int match; + + res = mdns_read_answer(pkt, &ans); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping query packet\n")); + goto cleanup; + } + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Known answer for domain ")); + mdns_domain_debug_print(&ans.info.domain); + LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass)); + + + if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass == DNS_RRCLASS_ANY) { + /* Skip known answers for ANY type & class */ + continue; + } + + rev_v6 = 0; + match = reply.host_replies & check_host(pkt->netif, &ans.info, &rev_v6); + if (match && (ans.ttl > (mdns->dns_ttl / 2))) { + /* The RR in the known answer matches an RR we are planning to send, + * and the TTL is less than half gone. + * If the payload matches we should not send that answer. + */ + if (ans.info.type == DNS_RRTYPE_PTR) { + /* Read domain and compare */ + struct mdns_domain known_ans, my_ans; + u16_t len; + len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans); + res = mdns_build_host_domain(&my_ans, mdns); + if (len != MDNS_READNAME_ERROR && res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) { +#if LWIP_IPV4 + if (match & REPLY_HOST_PTR_V4) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v4 PTR\n")); + reply.host_replies &= ~REPLY_HOST_PTR_V4; + } +#endif +#if LWIP_IPV6 + if (match & REPLY_HOST_PTR_V6) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: v6 PTR\n")); + reply.host_reverse_v6_replies &= ~rev_v6; + if (reply.host_reverse_v6_replies == 0) { + reply.host_replies &= ~REPLY_HOST_PTR_V6; + } + } +#endif + } + } else if (match & REPLY_HOST_A) { +#if LWIP_IPV4 + if (ans.rd_length == sizeof(ip4_addr_t) && + pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(pkt->netif), ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: A\n")); + reply.host_replies &= ~REPLY_HOST_A; + } +#endif + } else if (match & REPLY_HOST_AAAA) { +#if LWIP_IPV6 + if (ans.rd_length == sizeof(ip6_addr_t) && + /* TODO this clears all AAAA responses if first addr is set as known */ + pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(pkt->netif, 0), ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: AAAA\n")); + reply.host_replies &= ~REPLY_HOST_AAAA; + } +#endif + } + } + + for (i = 0; i < MDNS_MAX_SERVICES; ++i) { + service = mdns->services[i]; + if (!service) { + continue; + } + match = reply.serv_replies[i] & check_service(service, &ans.info); + if (match && (ans.ttl > (service->dns_ttl / 2))) { + /* The RR in the known answer matches an RR we are planning to send, + * and the TTL is less than half gone. + * If the payload matches we should not send that answer. + */ + if (ans.info.type == DNS_RRTYPE_PTR) { + /* Read domain and compare */ + struct mdns_domain known_ans, my_ans; + u16_t len; + len = mdns_readname(pkt->pbuf, ans.rd_offset, &known_ans); + if (len != MDNS_READNAME_ERROR) { + if (match & REPLY_SERVICE_TYPE_PTR) { + res = mdns_build_service_domain(&my_ans, service, 0); + if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service type PTR\n")); + reply.serv_replies[i] &= ~REPLY_SERVICE_TYPE_PTR; + } + } + if (match & REPLY_SERVICE_NAME_PTR) { + res = mdns_build_service_domain(&my_ans, service, 1); + if (res == ERR_OK && mdns_domain_eq(&known_ans, &my_ans)) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: service name PTR\n")); + reply.serv_replies[i] &= ~REPLY_SERVICE_NAME_PTR; + } + } + } + } else if (match & REPLY_SERVICE_SRV) { + /* Read and compare to my SRV record */ + u16_t field16, len, read_pos; + struct mdns_domain known_ans, my_ans; + read_pos = ans.rd_offset; + do { + /* Check priority field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) { + break; + } + read_pos += len; + /* Check weight field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) { + break; + } + read_pos += len; + /* Check port field */ + len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos); + if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) { + break; + } + read_pos += len; + /* Check host field */ + len = mdns_readname(pkt->pbuf, read_pos, &known_ans); + mdns_build_host_domain(&my_ans, mdns); + if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&known_ans, &my_ans)) { + break; + } + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: SRV\n")); + reply.serv_replies[i] &= ~REPLY_SERVICE_SRV; + } while (0); + } else if (match & REPLY_SERVICE_TXT) { + mdns_prepare_txtdata(service); + if (service->txtdata.length == ans.rd_length && + pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Skipping known answer: TXT\n")); + reply.serv_replies[i] &= ~REPLY_SERVICE_TXT; + } + } + } + } + } + + mdns_send_outpacket(&reply); + +cleanup: + if (reply.pbuf) { + /* This should only happen if we fail to alloc/write question for legacy query */ + pbuf_free(reply.pbuf); + reply.pbuf = NULL; + } +} + +/** + * Handle response MDNS packet + * Only prints debug for now. Will need more code to do conflict resolution. + */ +static void +mdns_handle_response(struct mdns_packet *pkt) +{ + /* Ignore all questions */ + while (pkt->questions_left) { + struct mdns_question q; + err_t res; + + res = mdns_read_question(pkt, &q); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse question, skipping response packet\n")); + return; + } + } + + while (pkt->answers_left) { + struct mdns_answer ans; + err_t res; + + res = mdns_read_answer(pkt, &ans); + if (res != ERR_OK) { + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n")); + return; + } + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Answer for domain ")); + mdns_domain_debug_print(&ans.info.domain); + LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass)); + } +} + +/** + * Receive input function for MDNS packets. + * Handles both IPv4 and IPv6 UDP pcbs. + */ +static void +mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + struct dns_hdr hdr; + struct mdns_packet packet; + struct netif *recv_netif = ip_current_input_netif(); + u16_t offset = 0; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + + LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Received IPv%d MDNS packet, len %d\n", IP_IS_V6(addr)? 6 : 4, p->tot_len)); + + if (NETIF_TO_HOST(recv_netif) == NULL) { + /* From netif not configured for MDNS */ + goto dealloc; + } + + if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, offset) < SIZEOF_DNS_HDR) { + /* Too small */ + goto dealloc; + } + offset += SIZEOF_DNS_HDR; + + if (DNS_HDR_GET_OPCODE(&hdr)) { + /* Ignore non-standard queries in multicast packets (RFC 6762, section 18.3) */ + goto dealloc; + } + + memset(&packet, 0, sizeof(packet)); + SMEMCPY(&packet.source_addr, addr, sizeof(packet.source_addr)); + packet.source_port = port; + packet.netif = recv_netif; + packet.pbuf = p; + packet.parse_offset = offset; + packet.tx_id = lwip_ntohs(hdr.id); + packet.questions = packet.questions_left = lwip_ntohs(hdr.numquestions); + packet.answers = packet.answers_left = lwip_ntohs(hdr.numanswers) + lwip_ntohs(hdr.numauthrr) + lwip_ntohs(hdr.numextrarr); + +#if LWIP_IPV6 + if (IP_IS_V6(ip_current_dest_addr())) { + if (!ip_addr_cmp(ip_current_dest_addr(), &v6group)) { + packet.recv_unicast = 1; + } + } +#endif +#if LWIP_IPV4 + if (!IP_IS_V6(ip_current_dest_addr())) { + if (!ip_addr_cmp(ip_current_dest_addr(), &v4group)) { + packet.recv_unicast = 1; + } + } +#endif + + if (hdr.flags1 & DNS_FLAG1_RESPONSE) { + mdns_handle_response(&packet); + } else { + mdns_handle_question(&packet); + } + +dealloc: + pbuf_free(p); +} + +/** + * @ingroup mdns + * Initiate MDNS responder. Will open UDP sockets on port 5353 + */ +void +mdns_resp_init(void) +{ + err_t res; + + mdns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("Failed to allocate pcb", mdns_pcb != NULL); +#if LWIP_MULTICAST_TX_OPTIONS + udp_set_multicast_ttl(mdns_pcb, MDNS_TTL); +#else + mdns_pcb->ttl = MDNS_TTL; +#endif + res = udp_bind(mdns_pcb, IP_ANY_TYPE, MDNS_PORT); + LWIP_UNUSED_ARG(res); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("Failed to bind pcb", res == ERR_OK); + udp_recv(mdns_pcb, mdns_recv, NULL); + + mdns_netif_client_id = netif_alloc_client_data_id(); +} + +/** + * @ingroup mdns + * Announce IP settings have changed on netif. + * Call this in your callback registered by netif_set_status_callback(). + * This function may go away in the future when netif supports registering + * multiple callback functions. + * @param netif The network interface where settings have changed. + */ +void +mdns_resp_netif_settings_changed(struct netif *netif) +{ + LWIP_ERROR("mdns_resp_netif_ip_changed: netif != NULL", (netif != NULL), return); + + if (NETIF_TO_HOST(netif) == NULL) { + return; + } + + /* Announce on IPv6 and IPv4 */ +#if LWIP_IPV6 + mdns_announce(netif, IP6_ADDR_ANY); +#endif +#if LWIP_IPV4 + mdns_announce(netif, IP4_ADDR_ANY); +#endif +} + +/** + * @ingroup mdns + * Activate MDNS responder for a network interface and send announce packets. + * @param netif The network interface to activate. + * @param hostname Name to use. Queries for <hostname>.local will be answered + * with the IP addresses of the netif. The hostname will be copied, the + * given pointer can be on the stack. + * @param dns_ttl Validity time in seconds to send out for IP address data in DNS replies + * @return ERR_OK if netif was added, an err_t otherwise + */ +err_t +mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl) +{ + err_t res; + struct mdns_host* mdns; + + LWIP_ERROR("mdns_resp_add_netif: netif != NULL", (netif != NULL), return ERR_VAL); + LWIP_ERROR("mdns_resp_add_netif: Hostname too long", (strlen(hostname) <= MDNS_LABEL_MAXLEN), return ERR_VAL); + + LWIP_ASSERT("mdns_resp_add_netif: Double add", NETIF_TO_HOST(netif) == NULL); + mdns = (struct mdns_host *) mem_malloc(sizeof(struct mdns_host)); + LWIP_ERROR("mdns_resp_add_netif: Alloc failed", (mdns != NULL), return ERR_MEM); + + netif_set_client_data(netif, mdns_netif_client_id, mdns); + + memset(mdns, 0, sizeof(struct mdns_host)); + MEMCPY(&mdns->name, hostname, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(hostname))); + mdns->dns_ttl = dns_ttl; + + /* Join multicast groups */ +#if LWIP_IPV4 + res = igmp_joingroup_netif(netif, ip_2_ip4(&v4group)); + if (res != ERR_OK) { + goto cleanup; + } +#endif +#if LWIP_IPV6 + res = mld6_joingroup_netif(netif, ip_2_ip6(&v6group)); + if (res != ERR_OK) { + goto cleanup; + } +#endif + + mdns_resp_netif_settings_changed(netif); + return ERR_OK; + +cleanup: + mem_free(mdns); + netif_set_client_data(netif, mdns_netif_client_id, NULL); + return res; +} + +/** + * @ingroup mdns + * Stop responding to MDNS queries on this interface, leave multicast groups, + * and free the helper structure and any of its services. + * @param netif The network interface to remove. + * @return ERR_OK if netif was removed, an err_t otherwise + */ +err_t +mdns_resp_remove_netif(struct netif *netif) +{ + int i; + struct mdns_host* mdns; + + LWIP_ASSERT("mdns_resp_remove_netif: Null pointer", netif); + mdns = NETIF_TO_HOST(netif); + LWIP_ERROR("mdns_resp_remove_netif: Not an active netif", (mdns != NULL), return ERR_VAL); + + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + struct mdns_service *service = mdns->services[i]; + if (service) { + mem_free(service); + } + } + + /* Leave multicast groups */ +#if LWIP_IPV4 + igmp_leavegroup_netif(netif, ip_2_ip4(&v4group)); +#endif +#if LWIP_IPV6 + mld6_leavegroup_netif(netif, ip_2_ip6(&v6group)); +#endif + + mem_free(mdns); + netif_set_client_data(netif, mdns_netif_client_id, NULL); + return ERR_OK; +} + +/** + * @ingroup mdns + * Add a service to the selected network interface. + * @param netif The network interface to publish this service on + * @param name The name of the service + * @param service The service type, like "_http" + * @param proto The service protocol, DNSSD_PROTO_TCP for TCP ("_tcp") and DNSSD_PROTO_UDP + * for others ("_udp") + * @param port The port the service listens to + * @param dns_ttl Validity time in seconds to send out for service data in DNS replies + * @param txt_fn Callback to get TXT data. Will be called each time a TXT reply is created to + * allow dynamic replies. + * @param txt_data Userdata pointer for txt_fn + * @return ERR_OK if the service was added to the netif, an err_t otherwise + */ +err_t +mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_data) +{ + int i; + int slot = -1; + struct mdns_service *srv; + struct mdns_host* mdns; + + LWIP_ASSERT("mdns_resp_add_service: netif != NULL", netif); + mdns = NETIF_TO_HOST(netif); + LWIP_ERROR("mdns_resp_add_service: Not an mdns netif", (mdns != NULL), return ERR_VAL); + + LWIP_ERROR("mdns_resp_add_service: Name too long", (strlen(name) <= MDNS_LABEL_MAXLEN), return ERR_VAL); + LWIP_ERROR("mdns_resp_add_service: Service too long", (strlen(service) <= MDNS_LABEL_MAXLEN), return ERR_VAL); + LWIP_ERROR("mdns_resp_add_service: Bad proto (need TCP or UDP)", (proto == DNSSD_PROTO_TCP || proto == DNSSD_PROTO_UDP), return ERR_VAL); + + for (i = 0; i < MDNS_MAX_SERVICES; i++) { + if (mdns->services[i] == NULL) { + slot = i; + break; + } + } + LWIP_ERROR("mdns_resp_add_service: Service list full (increase MDNS_MAX_SERVICES)", (slot >= 0), return ERR_MEM); + + srv = (struct mdns_service*)mem_malloc(sizeof(struct mdns_service)); + LWIP_ERROR("mdns_resp_add_service: Alloc failed", (srv != NULL), return ERR_MEM); + + memset(srv, 0, sizeof(struct mdns_service)); + + MEMCPY(&srv->name, name, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(name))); + MEMCPY(&srv->service, service, LWIP_MIN(MDNS_LABEL_MAXLEN, strlen(service))); + srv->txt_fn = txt_fn; + srv->txt_userdata = txt_data; + srv->proto = (u16_t)proto; + srv->port = port; + srv->dns_ttl = dns_ttl; + + mdns->services[slot] = srv; + + /* Announce on IPv6 and IPv4 */ +#if LWIP_IPV6 + mdns_announce(netif, IP6_ADDR_ANY); +#endif +#if LWIP_IPV4 + mdns_announce(netif, IP4_ADDR_ANY); +#endif + + return ERR_OK; +} + +/** + * @ingroup mdns + * Call this function from inside the service_get_txt_fn_t callback to add text data. + * Buffer for TXT data is 256 bytes, and each field is prefixed with a length byte. + * @param service The service provided to the get_txt callback + * @param txt String to add to the TXT field. + * @param txt_len Length of string + * @return ERR_OK if the string was added to the reply, an err_t otherwise + */ +err_t +mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len) +{ + LWIP_ASSERT("mdns_resp_add_service_txtitem: service != NULL", service); + + /* Use a mdns_domain struct to store txt chunks since it is the same encoding */ + return mdns_domain_add_label(&service->txtdata, txt, txt_len); +} + +#endif /* LWIP_MDNS_RESPONDER */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/mqtt/mqtt.c b/Sming/third-party/lwip2/lwip2-src/src/apps/mqtt/mqtt.c new file mode 100644 index 0000000000..a0e77b9719 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/mqtt/mqtt.c @@ -0,0 +1,1341 @@ +/** + * @file + * MQTT client + * + * @defgroup mqtt MQTT client + * @ingroup apps + * @verbinclude mqtt_client.txt + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack + * + * Author: Erik Andersson + * + * + * @todo: + * - Handle large outgoing payloads for PUBLISH messages + * - Fix restriction of a single topic in each (UN)SUBSCRIBE message (protocol has support for multiple topics) + * - Add support for legacy MQTT protocol version + * + * Please coordinate changes and requests with Erik Andersson + * Erik Andersson + * + */ +#include "lwip/apps/mqtt.h" +#include "lwip/timeouts.h" +#include "lwip/ip_addr.h" +#include "lwip/mem.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/tcp.h" +#include + +#if LWIP_TCP && LWIP_CALLBACK_API + +/** + * MQTT_DEBUG: Default is off. + */ +#if !defined MQTT_DEBUG || defined __DOXYGEN__ +#define MQTT_DEBUG LWIP_DBG_OFF +#endif + +#define MQTT_DEBUG_TRACE (MQTT_DEBUG | LWIP_DBG_TRACE) +#define MQTT_DEBUG_STATE (MQTT_DEBUG | LWIP_DBG_STATE) +#define MQTT_DEBUG_WARN (MQTT_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define MQTT_DEBUG_WARN_STATE (MQTT_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) +#define MQTT_DEBUG_SERIOUS (MQTT_DEBUG | LWIP_DBG_LEVEL_SERIOUS) + +static void mqtt_cyclic_timer(void *arg); + +/** + * MQTT client connection states + */ +enum { + TCP_DISCONNECTED, + TCP_CONNECTING, + MQTT_CONNECTING, + MQTT_CONNECTED +}; + +/** + * MQTT control message types + */ +enum mqtt_message_type { + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +/** Helpers to extract control packet type and qos from first byte in fixed header */ +#define MQTT_CTL_PACKET_TYPE(fixed_hdr_byte0) ((fixed_hdr_byte0 & 0xf0) >> 4) +#define MQTT_CTL_PACKET_QOS(fixed_hdr_byte0) ((fixed_hdr_byte0 & 0x6) >> 1) + +/** + * MQTT connect flags, only used in CONNECT message + */ +enum mqtt_connect_flag { + MQTT_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT_CONNECT_FLAG_WILL = 1 << 2, + MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + + +#if defined(LWIP_DEBUG) +static const char * const mqtt_message_type_str[15] = +{ + "UNDEFINED", + "CONNECT", + "CONNACK", + "PUBLISH", + "PUBACK", + "PUBREC", + "PUBREL", + "PUBCOMP", + "SUBSCRIBE", + "SUBACK", + "UNSUBSCRIBE", + "UNSUBACK", + "PINGREQ", + "PINGRESP", + "DISCONNECT" +}; + +/** + * Message type value to string + * @param msg_type see enum mqtt_message_type + * + * @return Control message type text string + */ +static const char * +mqtt_msg_type_to_str(u8_t msg_type) +{ + if (msg_type >= LWIP_ARRAYSIZE(mqtt_message_type_str)) { + msg_type = 0; + } + return mqtt_message_type_str[msg_type]; +} + +#endif + + +/** + * Generate MQTT packet identifier + * @param client MQTT client + * @return New packet identifier, range 1 to 65535 + */ +static u16_t +msg_generate_packet_id(mqtt_client_t *client) +{ + client->pkt_id_seq++; + if (client->pkt_id_seq == 0) { + client->pkt_id_seq++; + } + return client->pkt_id_seq; +} + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Output ring buffer */ + + +#define MQTT_RINGBUF_IDX_MASK ((MQTT_OUTPUT_RINGBUF_SIZE) - 1) + +/** Add single item to ring buffer */ +#define mqtt_ringbuf_put(rb, item) ((rb)->buf)[(rb)->put++ & MQTT_RINGBUF_IDX_MASK] = (item) + +/** Return number of bytes in ring buffer */ +#define mqtt_ringbuf_len(rb) ((u16_t)((rb)->put - (rb)->get)) + +/** Return number of bytes free in ring buffer */ +#define mqtt_ringbuf_free(rb) (MQTT_OUTPUT_RINGBUF_SIZE - mqtt_ringbuf_len(rb)) + +/** Return number of bytes possible to read without wrapping around */ +#define mqtt_ringbuf_linear_read_length(rb) LWIP_MIN(mqtt_ringbuf_len(rb), (MQTT_OUTPUT_RINGBUF_SIZE - ((rb)->get & MQTT_RINGBUF_IDX_MASK))) + +/** Return pointer to ring buffer get position */ +#define mqtt_ringbuf_get_ptr(rb) (&(rb)->buf[(rb)->get & MQTT_RINGBUF_IDX_MASK]) + +#define mqtt_ringbuf_advance_get_idx(rb, len) ((rb)->get += (len)) + + +/** + * Try send as many bytes as possible from output ring buffer + * @param rb Output ring buffer + * @param tpcb TCP connection handle + */ +static void +mqtt_output_send(struct mqtt_ringbuf_t *rb, struct tcp_pcb *tpcb) +{ + err_t err; + u8_t wrap = 0; + u16_t ringbuf_lin_len = mqtt_ringbuf_linear_read_length(rb); + u16_t send_len = tcp_sndbuf(tpcb); + LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); + + if (send_len == 0 || ringbuf_lin_len == 0) { + return; + } + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_output_send: tcp_sndbuf: %d bytes, ringbuf_linear_available: %d, get %d, put %d\n", + send_len, ringbuf_lin_len, ((rb)->get & MQTT_RINGBUF_IDX_MASK), ((rb)->put & MQTT_RINGBUF_IDX_MASK))); + + if (send_len > ringbuf_lin_len) { + /* Space in TCP output buffer is larger than available in ring buffer linear portion */ + send_len = ringbuf_lin_len; + /* Wrap around if more data in ring buffer after linear portion */ + wrap = (mqtt_ringbuf_len(rb) > ringbuf_lin_len); + } + err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY | (wrap ? TCP_WRITE_FLAG_MORE : 0)); + if ((err == ERR_OK) && wrap) { + mqtt_ringbuf_advance_get_idx(rb, send_len); + /* Use the lesser one of ring buffer linear length and TCP send buffer size */ + send_len = LWIP_MIN(tcp_sndbuf(tpcb), mqtt_ringbuf_linear_read_length(rb)); + err = tcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY); + } + + if (err == ERR_OK) { + mqtt_ringbuf_advance_get_idx(rb, send_len); + /* Flush */ + tcp_output(tpcb); + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN, ("mqtt_output_send: Send failed with err %d (\"%s\")\n", err, lwip_strerr(err))); + } +} + + + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Request queue */ + +/** + * Create request item + * @param r_objs Pointer to request objects + * @param pkt_id Packet identifier of request + * @param cb Packet callback to call when requests lifetime ends + * @param arg Parameter following callback + * @return Request or NULL if failed to create + */ +static struct mqtt_request_t * +mqtt_create_request(struct mqtt_request_t *r_objs, u16_t pkt_id, mqtt_request_cb_t cb, void *arg) +{ + struct mqtt_request_t *r = NULL; + u8_t n; + LWIP_ASSERT("mqtt_create_request: r_objs != NULL", r_objs != NULL); + for (n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { + /* Item point to itself if not in use */ + if (r_objs[n].next == &r_objs[n]) { + r = &r_objs[n]; + r->next = NULL; + r->cb = cb; + r->arg = arg; + r->pkt_id = pkt_id; + break; + } + } + return r; +} + + +/** + * Append request to pending request queue + * @param tail Pointer to request queue tail pointer + * @param r Request to append + */ +static void +mqtt_append_request(struct mqtt_request_t **tail, struct mqtt_request_t *r) +{ + struct mqtt_request_t *head = NULL; + s16_t time_before = 0; + struct mqtt_request_t *iter; + + LWIP_ASSERT("mqtt_append_request: tail != NULL", tail != NULL); + + /* Iterate trough queue to find head, and count total timeout time */ + for (iter = *tail; iter != NULL; iter = iter->next) { + time_before += iter->timeout_diff; + head = iter; + } + + LWIP_ASSERT("mqtt_append_request: time_before <= MQTT_REQ_TIMEOUT", time_before <= MQTT_REQ_TIMEOUT); + r->timeout_diff = MQTT_REQ_TIMEOUT - time_before; + if (head == NULL) { + *tail = r; + } else { + head->next = r; + } +} + + +/** + * Delete request item + * @param r Request item to delete + */ +static void +mqtt_delete_request(struct mqtt_request_t *r) +{ + if (r != NULL) { + r->next = r; + } +} + +/** + * Remove a request item with a specific packet identifier from request queue + * @param tail Pointer to request queue tail pointer + * @param pkt_id Packet identifier of request to take + * @return Request item if found, NULL if not + */ +static struct mqtt_request_t * +mqtt_take_request(struct mqtt_request_t **tail, u16_t pkt_id) +{ + struct mqtt_request_t *iter = NULL, *prev = NULL; + LWIP_ASSERT("mqtt_take_request: tail != NULL", tail != NULL); + /* Search all request for pkt_id */ + for (iter = *tail; iter != NULL; iter = iter->next) { + if (iter->pkt_id == pkt_id) { + break; + } + prev = iter; + } + + /* If request was found */ + if (iter != NULL) { + /* unchain */ + if (prev == NULL) { + *tail= iter->next; + } else { + prev->next = iter->next; + } + /* If exists, add remaining timeout time for the request to next */ + if (iter->next != NULL) { + iter->next->timeout_diff += iter->timeout_diff; + } + iter->next = NULL; + } + return iter; +} + +/** + * Handle requests timeout + * @param tail Pointer to request queue tail pointer + * @param t Time since last call in seconds + */ +static void +mqtt_request_time_elapsed(struct mqtt_request_t **tail, u8_t t) +{ + struct mqtt_request_t *r = *tail; + LWIP_ASSERT("mqtt_request_time_elapsed: tail != NULL", tail != NULL); + while (t > 0 && r != NULL) { + if (t >= r->timeout_diff) { + t -= (u8_t)r->timeout_diff; + /* Unchain */ + *tail = r->next; + /* Notify upper layer about timeout */ + if (r->cb != NULL) { + r->cb(r->arg, ERR_TIMEOUT); + } + mqtt_delete_request(r); + /* Tail might be be modified in callback, so re-read it in every iteration */ + r = *(struct mqtt_request_t * const volatile *)tail; + } else { + r->timeout_diff -= t; + t = 0; + } + } +} + +/** + * Free all request items + * @param tail Pointer to request queue tail pointer + */ +static void +mqtt_clear_requests(struct mqtt_request_t **tail) +{ + struct mqtt_request_t *iter, *next; + LWIP_ASSERT("mqtt_clear_requests: tail != NULL", tail != NULL); + for (iter = *tail; iter != NULL; iter = next) { + next = iter->next; + mqtt_delete_request(iter); + } + *tail = NULL; +} +/** + * Initialize all request items + * @param r_objs Pointer to request objects + */ +static void +mqtt_init_requests(struct mqtt_request_t *r_objs) +{ + u8_t n; + LWIP_ASSERT("mqtt_init_requests: r_objs != NULL", r_objs != NULL); + for (n = 0; n < MQTT_REQ_MAX_IN_FLIGHT; n++) { + /* Item pointing to itself indicates unused */ + r_objs[n].next = &r_objs[n]; + } +} + +/*--------------------------------------------------------------------------------------------------------------------- */ +/* Output message build helpers */ + + +static void +mqtt_output_append_u8(struct mqtt_ringbuf_t *rb, u8_t value) +{ + mqtt_ringbuf_put(rb, value); +} + +static +void mqtt_output_append_u16(struct mqtt_ringbuf_t *rb, u16_t value) +{ + mqtt_ringbuf_put(rb, value >> 8); + mqtt_ringbuf_put(rb, value & 0xff); +} + +static void +mqtt_output_append_buf(struct mqtt_ringbuf_t *rb, const void *data, u16_t length) +{ + u16_t n; + for (n = 0; n < length; n++) { + mqtt_ringbuf_put(rb, ((const u8_t *)data)[n]); + } +} + +static void +mqtt_output_append_string(struct mqtt_ringbuf_t *rb, const char *str, u16_t length) +{ + u16_t n; + mqtt_ringbuf_put(rb, length >> 8); + mqtt_ringbuf_put(rb, length & 0xff); + for (n = 0; n < length; n++) { + mqtt_ringbuf_put(rb, str[n]); + } +} + +/** + * Append fixed header + * @param rb Output ring buffer + * @param msg_type see enum mqtt_message_type + * @param dup MQTT DUP flag + * @param qos MQTT QoS field + * @param retain MQTT retain flag + * @param r_length Remaining length after fixed header + */ + +static void +mqtt_output_append_fixed_header(struct mqtt_ringbuf_t *rb, u8_t msg_type, u8_t dup, + u8_t qos, u8_t retain, u16_t r_length) +{ + /* Start with control byte */ + mqtt_output_append_u8(rb, (((msg_type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1))); + /* Encode remaining length field */ + do { + mqtt_output_append_u8(rb, (r_length & 0x7f) | (r_length >= 128 ? 0x80 : 0)); + r_length >>= 7; + } while (r_length > 0); +} + + +/** + * Check output buffer space + * @param rb Output ring buffer + * @param r_length Remaining length after fixed header + * @return 1 if message will fit, 0 if not enough buffer space + */ +static u8_t +mqtt_output_check_space(struct mqtt_ringbuf_t *rb, u16_t r_length) +{ + /* Start with length of type byte + remaining length */ + u16_t total_len = 1 + r_length; + + LWIP_ASSERT("mqtt_output_check_space: rb != NULL", rb != NULL); + + /* Calculate number of required bytes to contain the remaining bytes field and add to total*/ + do { + total_len++; + r_length >>= 7; + } while (r_length > 0); + + return (total_len <= mqtt_ringbuf_free(rb)); +} + + +/** + * Close connection to server + * @param client MQTT client + * @param reason Reason for disconnection + */ +static void +mqtt_close(mqtt_client_t *client, mqtt_connection_status_t reason) +{ + LWIP_ASSERT("mqtt_close: client != NULL", client != NULL); + + /* Bring down TCP connection if not already done */ + if (client->conn != NULL) { + err_t res; + tcp_recv(client->conn, NULL); + tcp_err(client->conn, NULL); + tcp_sent(client->conn, NULL); + res = tcp_close(client->conn); + if (res != ERR_OK) { + tcp_abort(client->conn); + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_close: Close err=%s\n", lwip_strerr(res))); + } + client->conn = NULL; + } + + /* Remove all pending requests */ + mqtt_clear_requests(&client->pend_req_queue); + /* Stop cyclic timer */ + sys_untimeout(mqtt_cyclic_timer, client); + + /* Notify upper layer of disconnection if changed state */ + if (client->conn_state != TCP_DISCONNECTED) { + + client->conn_state = TCP_DISCONNECTED; + if (client->connect_cb != NULL) { + client->connect_cb(client, client->connect_arg, reason); + } + } +} + + +/** + * Interval timer, called every MQTT_CYCLIC_TIMER_INTERVAL seconds in MQTT_CONNECTING and MQTT_CONNECTED states + * @param arg MQTT client + */ +static void +mqtt_cyclic_timer(void *arg) +{ + u8_t restart_timer = 1; + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_ASSERT("mqtt_cyclic_timer: client != NULL", client != NULL); + + if (client->conn_state == MQTT_CONNECTING) { + client->cyclic_tick++; + if ((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= MQTT_CONNECT_TIMOUT) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: CONNECT attempt to server timed out\n")); + /* Disconnect TCP */ + mqtt_close(client, MQTT_CONNECT_TIMEOUT); + restart_timer = 0; + } + } else if (client->conn_state == MQTT_CONNECTED) { + /* Handle timeout for pending requests */ + mqtt_request_time_elapsed(&client->pend_req_queue, MQTT_CYCLIC_TIMER_INTERVAL); + + /* keep_alive > 0 means keep alive functionality shall be used */ + if (client->keep_alive > 0) { + + client->server_watchdog++; + /* If reception from server has been idle for 1.5*keep_alive time, server is considered unresponsive */ + if ((client->server_watchdog * MQTT_CYCLIC_TIMER_INTERVAL) > (client->keep_alive + client->keep_alive/2)) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Server incoming keep-alive timeout\n")); + mqtt_close(client, MQTT_CONNECT_TIMEOUT); + restart_timer = 0; + } + + /* If time for a keep alive message to be sent, transmission has been idle for keep_alive time */ + if ((client->cyclic_tick * MQTT_CYCLIC_TIMER_INTERVAL) >= client->keep_alive) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_cyclic_timer: Sending keep-alive message to server\n")); + if (mqtt_output_check_space(&client->output, 0) != 0) { + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0, 0); + client->cyclic_tick = 0; + } + } else { + client->cyclic_tick++; + } + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_cyclic_timer: Timer should not be running in state %d\n", client->conn_state)); + restart_timer = 0; + } + if (restart_timer) { + sys_timeout(MQTT_CYCLIC_TIMER_INTERVAL*1000, mqtt_cyclic_timer, arg); + } +} + + +/** + * Send PUBACK, PUBREC or PUBREL response message + * @param client MQTT client + * @param msg PUBACK, PUBREC or PUBREL + * @param pkt_id Packet identifier + * @param qos QoS value + * @return ERR_OK if successful, ERR_MEM if out of memory + */ +static err_t +pub_ack_rec_rel_response(mqtt_client_t *client, u8_t msg, u16_t pkt_id, u8_t qos) +{ + err_t err = ERR_OK; + if (mqtt_output_check_space(&client->output, 2)) { + mqtt_output_append_fixed_header(&client->output, msg, 0, qos, 0, 2); + mqtt_output_append_u16(&client->output, pkt_id); + mqtt_output_send(&client->output, client->conn); + } else { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("pub_ack_rec_rel_response: OOM creating response: %s with pkt_id: %d\n", + mqtt_msg_type_to_str(msg), pkt_id)); + err = ERR_MEM; + } + return err; +} + +/** + * Subscribe response from server + * @param r Matching request + * @param result Result code from server + */ +static void +mqtt_incomming_suback(struct mqtt_request_t *r, u8_t result) +{ + if (r->cb != NULL) { + r->cb(r->arg, result < 3 ? ERR_OK : ERR_ABRT); + } +} + + +/** + * Complete MQTT message received or buffer full + * @param client MQTT client + * @param fixed_hdr_idx header index + * @param length length received part + * @param remaining_length Remaining length of complete message + */ +static mqtt_connection_status_t + mqtt_message_received(mqtt_client_t *client, u8_t fixed_hdr_idx, u16_t length, u32_t remaining_length) +{ + mqtt_connection_status_t res = MQTT_CONNECT_ACCEPTED; + + u8_t *var_hdr_payload = client->rx_buffer + fixed_hdr_idx; + + /* Control packet type */ + u8_t pkt_type = MQTT_CTL_PACKET_TYPE(client->rx_buffer[0]); + u16_t pkt_id = 0; + + if (pkt_type == MQTT_MSG_TYPE_CONNACK) { + if (client->conn_state == MQTT_CONNECTING) { + /* Get result code from CONNACK */ + res = (mqtt_connection_status_t)var_hdr_payload[1]; + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: Connect response code %d\n", res)); + if (res == MQTT_CONNECT_ACCEPTED) { + /* Reset cyclic_tick when changing to connected state */ + client->cyclic_tick = 0; + client->conn_state = MQTT_CONNECTED; + /* Notify upper layer */ + if (client->connect_cb != 0) { + client->connect_cb(client, client->connect_arg, res); + } + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Received CONNACK in connected state\n")); + } + } else if (pkt_type == MQTT_MSG_TYPE_PINGRESP) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,( "mqtt_message_received: Received PINGRESP from server\n")); + + } else if (pkt_type == MQTT_MSG_TYPE_PUBLISH) { + u16_t payload_offset = 0; + u16_t payload_length = length; + u8_t qos = MQTT_CTL_PACKET_QOS(client->rx_buffer[0]); + + if (client->msg_idx <= MQTT_VAR_HEADER_BUFFER_LEN) { + /* Should have topic and pkt id*/ + uint8_t *topic; + uint16_t after_topic; + u8_t bkp; + u16_t topic_len = var_hdr_payload[0]; + topic_len = (topic_len << 8) + (u16_t)(var_hdr_payload[1]); + + topic = var_hdr_payload + 2; + after_topic = 2 + topic_len; + /* Check length, add one byte even for QoS 0 so that zero termination will fit */ + if ((after_topic + (qos? 2 : 1)) > length) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Receive buffer can not fit topic + pkt_id\n")); + goto out_disconnect; + } + + /* id for QoS 1 and 2 */ + if (qos > 0) { + client->inpub_pkt_id = ((u16_t)var_hdr_payload[after_topic] << 8) + (u16_t)var_hdr_payload[after_topic + 1]; + after_topic += 2; + } else { + client->inpub_pkt_id = 0; + } + /* Take backup of byte after topic */ + bkp = topic[topic_len]; + /* Zero terminate string */ + topic[topic_len] = 0; + /* Payload data remaining in receive buffer */ + payload_length = length - after_topic; + payload_offset = after_topic; + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Received message with QoS %d at topic: %s, payload length %d\n", + qos, topic, remaining_length + payload_length)); + if (client->pub_cb != NULL) { + client->pub_cb(client->inpub_arg, (const char *)topic, remaining_length + payload_length); + } + /* Restore byte after topic */ + topic[topic_len] = bkp; + } + if (payload_length > 0 || remaining_length == 0) { + client->data_cb(client->inpub_arg, var_hdr_payload + payload_offset, payload_length, remaining_length == 0 ? MQTT_DATA_FLAG_LAST : 0); + /* Reply if QoS > 0 */ + if (remaining_length == 0 && qos > 0) { + /* Send PUBACK for QoS 1 or PUBREC for QoS 2 */ + u8_t resp_msg = (qos == 1) ? MQTT_MSG_TYPE_PUBACK : MQTT_MSG_TYPE_PUBREC; + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_incomming_publish: Sending publish response: %s with pkt_id: %d\n", + mqtt_msg_type_to_str(resp_msg), client->inpub_pkt_id)); + pub_ack_rec_rel_response(client, resp_msg, client->inpub_pkt_id, 0); + } + } + } else { + /* Get packet identifier */ + pkt_id = (u16_t)var_hdr_payload[0] << 8; + pkt_id |= (u16_t)var_hdr_payload[1]; + if (pkt_id == 0) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: Got message with illegal packet identifier: 0\n")); + goto out_disconnect; + } + if (pkt_type == MQTT_MSG_TYPE_PUBREC) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREC, sending PUBREL with pkt_id: %d\n",pkt_id)); + pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBREL, pkt_id, 1); + + } else if (pkt_type == MQTT_MSG_TYPE_PUBREL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: PUBREL, sending PUBCOMP response with pkt_id: %d\n",pkt_id)); + pub_ack_rec_rel_response(client, MQTT_MSG_TYPE_PUBCOMP, pkt_id, 0); + + } else if (pkt_type == MQTT_MSG_TYPE_SUBACK || pkt_type == MQTT_MSG_TYPE_UNSUBACK || + pkt_type == MQTT_MSG_TYPE_PUBCOMP || pkt_type == MQTT_MSG_TYPE_PUBACK) { + struct mqtt_request_t *r = mqtt_take_request(&client->pend_req_queue, pkt_id); + if (r != NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_message_received: %s response with id %d\n", mqtt_msg_type_to_str(pkt_type), pkt_id)); + if (pkt_type == MQTT_MSG_TYPE_SUBACK) { + if (length < 3) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_message_received: To small SUBACK packet\n")); + goto out_disconnect; + } else { + mqtt_incomming_suback(r, var_hdr_payload[2]); + } + } else if (r->cb != NULL) { + r->cb(r->arg, ERR_OK); + } + mqtt_delete_request(r); + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,( "mqtt_message_received: Received %s reply, with wrong pkt_id: %d\n", mqtt_msg_type_to_str(pkt_type), pkt_id)); + } + } else { + LWIP_DEBUGF(MQTT_DEBUG_WARN,( "mqtt_message_received: Received unknown message type: %d\n", pkt_type)); + goto out_disconnect; + } + } + return res; +out_disconnect: + return MQTT_CONNECT_DISCONNECTED; +} + + +/** + * MQTT incoming message parser + * @param client MQTT client + * @param p PBUF chain of received data + * @return Connection status + */ +static mqtt_connection_status_t +mqtt_parse_incoming(mqtt_client_t *client, struct pbuf *p) +{ + u16_t in_offset = 0; + u32_t msg_rem_len = 0; + u8_t fixed_hdr_idx = 0; + u8_t b = 0; + + while (p->tot_len > in_offset) { + if ((fixed_hdr_idx < 2) || ((b & 0x80) != 0)) { + + if (fixed_hdr_idx < client->msg_idx) { + b = client->rx_buffer[fixed_hdr_idx]; + } else { + b = pbuf_get_at(p, in_offset++); + client->rx_buffer[client->msg_idx++] = b; + } + fixed_hdr_idx++; + + if (fixed_hdr_idx >= 2) { + msg_rem_len |= (u32_t)(b & 0x7f) << ((fixed_hdr_idx - 2) * 7); + if ((b & 0x80) == 0) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: Remaining length after fixed header: %d\n", msg_rem_len)); + if (msg_rem_len == 0) { + /* Complete message with no extra headers of payload received */ + mqtt_message_received(client, fixed_hdr_idx, 0, 0); + client->msg_idx = 0; + fixed_hdr_idx = 0; + } else { + /* Bytes remaining in message */ + msg_rem_len = (msg_rem_len + fixed_hdr_idx) - client->msg_idx; + } + } + } + } else { + u16_t cpy_len, cpy_start, buffer_space; + + cpy_start = (client->msg_idx - fixed_hdr_idx) % (MQTT_VAR_HEADER_BUFFER_LEN - fixed_hdr_idx) + fixed_hdr_idx; + + /* Allow to copy the lesser one of available length in input data or bytes remaining in message */ + cpy_len = (u16_t)LWIP_MIN((u16_t)(p->tot_len - in_offset), msg_rem_len); + + /* Limit to available space in buffer */ + buffer_space = MQTT_VAR_HEADER_BUFFER_LEN - cpy_start; + if (cpy_len > buffer_space) { + cpy_len = buffer_space; + } + pbuf_copy_partial(p, client->rx_buffer+cpy_start, cpy_len, in_offset); + + /* Advance get and put indexes */ + client->msg_idx += cpy_len; + in_offset += cpy_len; + msg_rem_len -= cpy_len; + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_parse_incoming: msg_idx: %d, cpy_len: %d, remaining %d\n", client->msg_idx, cpy_len, msg_rem_len)); + if (msg_rem_len == 0 || cpy_len == buffer_space) { + /* Whole message received or buffer is full */ + mqtt_connection_status_t res = mqtt_message_received(client, fixed_hdr_idx, (cpy_start + cpy_len) - fixed_hdr_idx, msg_rem_len); + if (res != MQTT_CONNECT_ACCEPTED) { + return res; + } + if (msg_rem_len == 0) { + /* Reset parser state */ + client->msg_idx = 0; + /* msg_tot_len = 0; */ + fixed_hdr_idx = 0; + } + } + } + } + return MQTT_CONNECT_ACCEPTED; +} + + +/** + * TCP received callback function. @see tcp_recv_fn + * @param arg MQTT client + * @param p PBUF chain of received data + * @param err Passed as return value if not ERR_OK + * @return ERR_OK or err passed into callback + */ +static err_t +mqtt_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_ASSERT("mqtt_tcp_recv_cb: client != NULL", client != NULL); + LWIP_ASSERT("mqtt_tcp_recv_cb: client->conn == pcb", client->conn == pcb); + + if (p == NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_recv_cb: Recv pbuf=NULL, remote has closed connection\n")); + mqtt_close(client, MQTT_CONNECT_DISCONNECTED); + } else { + mqtt_connection_status_t res; + if (err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_recv_cb: Recv err=%d\n", err)); + pbuf_free(p); + return err; + } + + /* Tell remote that data has been received */ + tcp_recved(pcb, p->tot_len); + res = mqtt_parse_incoming(client, p); + pbuf_free(p); + + if (res != MQTT_CONNECT_ACCEPTED) { + mqtt_close(client, res); + } + /* If keep alive functionality is used */ + if (client->keep_alive != 0) { + /* Reset server alive watchdog */ + client->server_watchdog = 0; + } + + } + return ERR_OK; +} + + +/** + * TCP data sent callback function. @see tcp_sent_fn + * @param arg MQTT client + * @param tpcb TCP connection handle + * @param len Number of bytes sent + * @return ERR_OK + */ +static err_t +mqtt_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + + LWIP_UNUSED_ARG(tpcb); + LWIP_UNUSED_ARG(len); + + if (client->conn_state == MQTT_CONNECTED) { + struct mqtt_request_t *r; + + /* Reset keep-alive send timer and server watchdog */ + client->cyclic_tick = 0; + client->server_watchdog = 0; + /* QoS 0 publish has no response from server, so call its callbacks here */ + while ((r = mqtt_take_request(&client->pend_req_queue, 0)) != NULL) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_sent_cb: Calling QoS 0 publish complete callback\n")); + if (r->cb != NULL) { + r->cb(r->arg, ERR_OK); + } + mqtt_delete_request(r); + } + /* Try send any remaining buffers from output queue */ + mqtt_output_send(&client->output, client->conn); + } + return ERR_OK; +} + +/** + * TCP error callback function. @see tcp_err_fn + * @param arg MQTT client + * @param err Error encountered + */ +static void +mqtt_tcp_err_cb(void *arg, err_t err) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + LWIP_UNUSED_ARG(err); /* only used for debug output */ + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_err_cb: TCP error callback: error %d, arg: %p\n", err, arg)); + LWIP_ASSERT("mqtt_tcp_err_cb: client != NULL", client != NULL); + /* Set conn to null before calling close as pcb is already deallocated*/ + client->conn = 0; + mqtt_close(client, MQTT_CONNECT_DISCONNECTED); +} + +/** + * TCP poll callback function. @see tcp_poll_fn + * @param arg MQTT client + * @param tpcb TCP connection handle + * @return err ERR_OK + */ +static err_t +mqtt_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) +{ + mqtt_client_t *client = (mqtt_client_t *)arg; + if (client->conn_state == MQTT_CONNECTED) { + /* Try send any remaining buffers from output queue */ + mqtt_output_send(&client->output, tpcb); + } + return ERR_OK; +} + +/** + * TCP connect callback function. @see tcp_connected_fn + * @param arg MQTT client + * @param err Always ERR_OK, mqtt_tcp_err_cb is called in case of error + * @return ERR_OK + */ +static err_t +mqtt_tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + mqtt_client_t* client = (mqtt_client_t *)arg; + + if (err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_tcp_connect_cb: TCP connect error %d\n", err)); + return err; + } + + /* Initiate receiver state */ + client->msg_idx = 0; + + /* Setup TCP callbacks */ + tcp_recv(tpcb, mqtt_tcp_recv_cb); + tcp_sent(tpcb, mqtt_tcp_sent_cb); + tcp_poll(tpcb, mqtt_tcp_poll_cb, 2); + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_tcp_connect_cb: TCP connection established to server\n")); + /* Enter MQTT connect state */ + client->conn_state = MQTT_CONNECTING; + + /* Start cyclic timer */ + sys_timeout(MQTT_CYCLIC_TIMER_INTERVAL*1000, mqtt_cyclic_timer, client); + client->cyclic_tick = 0; + + /* Start transmission from output queue, connect message is the first one out*/ + mqtt_output_send(&client->output, client->conn); + + return ERR_OK; +} + + + +/*---------------------------------------------------------------------------------------------------- */ +/* Public API */ + + +/** + * @ingroup mqtt + * MQTT publish function. + * @param client MQTT client + * @param topic Publish topic string + * @param payload Data to publish (NULL is allowed) + * @param payload_length: Length of payload (0 is allowed) + * @param qos Quality of service, 0 1 or 2 + * @param retain MQTT retain flag + * @param cb Callback to call when publish is complete or has timed out + * @param arg User supplied argument to publish callback + * @return ERR_OK if successful + * ERR_CONN if client is disconnected + * ERR_MEM if short on memory + */ +err_t +mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain, + mqtt_request_cb_t cb, void *arg) +{ + struct mqtt_request_t *r; + u16_t pkt_id; + size_t topic_strlen; + size_t total_len; + u16_t topic_len; + u16_t remaining_length; + + LWIP_ASSERT("mqtt_publish: client != NULL", client); + LWIP_ASSERT("mqtt_publish: topic != NULL", topic); + LWIP_ERROR("mqtt_publish: TCP disconnected", (client->conn_state != TCP_DISCONNECTED), return ERR_CONN); + + topic_strlen = strlen(topic); + LWIP_ERROR("mqtt_publish: topic length overflow", (topic_strlen <= (0xFFFF - 2)), return ERR_ARG); + topic_len = (u16_t)topic_strlen; + total_len = 2 + topic_len + payload_length; + LWIP_ERROR("mqtt_publish: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); + remaining_length = (u16_t)total_len; + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_publish: Publish with payload length %d to topic \"%s\"\n", payload_length, topic)); + + if (qos > 0) { + remaining_length += 2; + /* Generate pkt_id id for QoS1 and 2 */ + pkt_id = msg_generate_packet_id(client); + } else { + /* Use reserved value pkt_id 0 for QoS 0 in request handle */ + pkt_id = 0; + } + + r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + if (r == NULL) { + return ERR_MEM; + } + + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { + mqtt_delete_request(r); + return ERR_MEM; + } + /* Append fixed header */ + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain, remaining_length); + + /* Append Topic */ + mqtt_output_append_string(&client->output, topic, topic_len); + + /* Append packet if for QoS 1 and 2*/ + if (qos > 0) { + mqtt_output_append_u16(&client->output, pkt_id); + } + + /* Append optional publish payload */ + if ((payload != NULL) && (payload_length > 0)) { + mqtt_output_append_buf(&client->output, payload, payload_length); + } + + mqtt_append_request(&client->pend_req_queue, r); + mqtt_output_send(&client->output, client->conn); + return ERR_OK; +} + + +/** + * @ingroup mqtt + * MQTT subscribe/unsubscribe function. + * @param client MQTT client + * @param topic topic to subscribe to + * @param qos Quality of service, 0 1 or 2 (only used for subscribe) + * @param cb Callback to call when subscribe/unsubscribe reponse is received + * @param arg User supplied argument to publish callback + * @param sub 1 for subscribe, 0 for unsubscribe + * @return ERR_OK if successful, @see err_t enum for other results + */ +err_t +mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub) +{ + size_t topic_strlen; + size_t total_len; + u16_t topic_len; + u16_t remaining_length; + u16_t pkt_id; + struct mqtt_request_t *r; + + LWIP_ASSERT("mqtt_sub_unsub: client != NULL", client); + LWIP_ASSERT("mqtt_sub_unsub: topic != NULL", topic); + + topic_strlen = strlen(topic); + LWIP_ERROR("mqtt_sub_unsub: topic length overflow", (topic_strlen <= (0xFFFF - 2)), return ERR_ARG); + topic_len = (u16_t)topic_strlen; + /* Topic string, pkt_id, qos for subscribe */ + total_len = topic_len + 2 + 2 + (sub != 0); + LWIP_ERROR("mqtt_sub_unsub: total length overflow", (total_len <= 0xFFFF), return ERR_ARG); + remaining_length = (u16_t)total_len; + + LWIP_ASSERT("mqtt_sub_unsub: qos < 3", qos < 3); + if (client->conn_state == TCP_DISCONNECTED) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_sub_unsub: Can not (un)subscribe in disconnected state\n")); + return ERR_CONN; + } + + pkt_id = msg_generate_packet_id(client); + r = mqtt_create_request(client->req_list, pkt_id, cb, arg); + if (r == NULL) { + return ERR_MEM; + } + + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { + mqtt_delete_request(r); + return ERR_MEM; + } + + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_sub_unsub: Client (un)subscribe to topic \"%s\", id: %d\n", topic, pkt_id)); + + mqtt_output_append_fixed_header(&client->output, sub ? MQTT_MSG_TYPE_SUBSCRIBE : MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0, remaining_length); + /* Packet id */ + mqtt_output_append_u16(&client->output, pkt_id); + /* Topic */ + mqtt_output_append_string(&client->output, topic, topic_len); + /* QoS */ + if (sub != 0) { + mqtt_output_append_u8(&client->output, LWIP_MIN(qos, 2)); + } + + mqtt_append_request(&client->pend_req_queue, r); + mqtt_output_send(&client->output, client->conn); + return ERR_OK; +} + + +/** + * @ingroup mqtt + * Set callback to handle incoming publish requests from server + * @param client MQTT client + * @param pub_cb Callback invoked when publish starts, contain topic and total length of payload + * @param data_cb Callback for each fragment of payload that arrives + * @param arg User supplied argument to both callbacks + */ +void +mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t pub_cb, + mqtt_incoming_data_cb_t data_cb, void *arg) +{ + LWIP_ASSERT("mqtt_set_inpub_callback: client != NULL", client != NULL); + client->data_cb = data_cb; + client->pub_cb = pub_cb; + client->inpub_arg = arg; +} + +/** + * @ingroup mqtt + * Create a new MQTT client instance + * @return Pointer to instance on success, NULL otherwise + */ +mqtt_client_t * +mqtt_client_new(void) +{ + mqtt_client_t *client = (mqtt_client_t *)mem_malloc(sizeof(mqtt_client_t)); + if (client != NULL) { + memset(client, 0, sizeof(mqtt_client_t)); + } + return client; +} + + +/** + * @ingroup mqtt + * Connect to MQTT server + * @param client MQTT client + * @param ip_addr Server IP + * @param port Server port + * @param cb Connection state change callback + * @param arg User supplied argument to connection callback + * @param client_info Client identification and connection options + * @return ERR_OK if successful, @see err_t enum for other results + */ +err_t +mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ip_addr, u16_t port, mqtt_connection_cb_t cb, void *arg, + const struct mqtt_connect_client_info_t *client_info) +{ + err_t err; + size_t len; + u16_t client_id_length; + /* Length is the sum of 2+"MQTT", protocol level, flags and keep alive */ + u16_t remaining_length = 2 + 4 + 1 + 1 + 2; + u8_t flags = 0, will_topic_len = 0, will_msg_len = 0; + + LWIP_ASSERT("mqtt_client_connect: client != NULL", client != NULL); + LWIP_ASSERT("mqtt_client_connect: ip_addr != NULL", ip_addr != NULL); + LWIP_ASSERT("mqtt_client_connect: client_info != NULL", client_info != NULL); + LWIP_ASSERT("mqtt_client_connect: client_info->client_id != NULL", client_info->client_id != NULL); + + if (client->conn_state != TCP_DISCONNECTED) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Already connected\n")); + return ERR_ISCONN; + } + + /* Wipe clean */ + memset(client, 0, sizeof(mqtt_client_t)); + client->connect_arg = arg; + client->connect_cb = cb; + client->keep_alive = client_info->keep_alive; + mqtt_init_requests(client->req_list); + + /* Build connect message */ + if (client_info->will_topic != NULL && client_info->will_msg != NULL) { + flags |= MQTT_CONNECT_FLAG_WILL; + flags |= (client_info->will_qos & 3) << 3; + if (client_info->will_retain) { + flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; + } + len = strlen(client_info->will_topic); + LWIP_ERROR("mqtt_client_connect: client_info->will_topic length overflow", len <= 0xFF, return ERR_VAL); + LWIP_ERROR("mqtt_client_connect: client_info->will_topic length must be > 0", len > 0, return ERR_VAL); + will_topic_len = (u8_t)len; + len = strlen(client_info->will_msg); + LWIP_ERROR("mqtt_client_connect: client_info->will_msg length overflow", len <= 0xFF, return ERR_VAL); + will_msg_len = (u8_t)len; + len = remaining_length + 2 + will_topic_len + 2 + will_msg_len; + LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); + remaining_length = (u16_t)len; + } + + /* Don't complicate things, always connect using clean session */ + flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; + + len = strlen(client_info->client_id); + LWIP_ERROR("mqtt_client_connect: client_info->client_id length overflow", len <= 0xFFFF, return ERR_VAL); + client_id_length = (u16_t)len; + len = remaining_length + 2 + client_id_length; + LWIP_ERROR("mqtt_client_connect: remaining_length overflow", len <= 0xFFFF, return ERR_VAL); + remaining_length = (u16_t)len; + + if (mqtt_output_check_space(&client->output, remaining_length) == 0) { + return ERR_MEM; + } + + client->conn = tcp_new(); + if (client->conn == NULL) { + return ERR_MEM; + } + + /* Set arg pointer for callbacks */ + tcp_arg(client->conn, client); + /* Any local address, pick random local port number */ + err = tcp_bind(client->conn, IP_ADDR_ANY, 0); + if (err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_WARN,("mqtt_client_connect: Error binding to local ip/port, %d\n", err)); + goto tcp_fail; + } + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Connecting to host: %s at port:%"U16_F"\n", ipaddr_ntoa(ip_addr), port)); + + /* Connect to server */ + err = tcp_connect(client->conn, ip_addr, port, mqtt_tcp_connect_cb); + if (err != ERR_OK) { + LWIP_DEBUGF(MQTT_DEBUG_TRACE,("mqtt_client_connect: Error connecting to remote ip/port, %d\n", err)); + goto tcp_fail; + } + /* Set error callback */ + tcp_err(client->conn, mqtt_tcp_err_cb); + client->conn_state = TCP_CONNECTING; + + /* Append fixed header */ + mqtt_output_append_fixed_header(&client->output, MQTT_MSG_TYPE_CONNECT, 0, 0, 0, remaining_length); + /* Append Protocol string */ + mqtt_output_append_string(&client->output, "MQTT", 4); + /* Append Protocol level */ + mqtt_output_append_u8(&client->output, 4); + /* Append connect flags */ + mqtt_output_append_u8(&client->output, flags); + /* Append keep-alive */ + mqtt_output_append_u16(&client->output, client_info->keep_alive); + /* Append client id */ + mqtt_output_append_string(&client->output, client_info->client_id, client_id_length); + /* Append will message if used */ + if ((flags & MQTT_CONNECT_FLAG_WILL) != 0) { + mqtt_output_append_string(&client->output, client_info->will_topic, will_topic_len); + mqtt_output_append_string(&client->output, client_info->will_msg, will_msg_len); + } + return ERR_OK; + +tcp_fail: + tcp_abort(client->conn); + client->conn = NULL; + return err; +} + + +/** + * @ingroup mqtt + * Disconnect from MQTT server + * @param client MQTT client + */ +void +mqtt_disconnect(mqtt_client_t *client) +{ + LWIP_ASSERT("mqtt_disconnect: client != NULL", client); + /* If connection in not already closed */ + if (client->conn_state != TCP_DISCONNECTED) { + /* Set conn_state before calling mqtt_close to prevent callback from being called */ + client->conn_state = TCP_DISCONNECTED; + mqtt_close(client, (mqtt_connection_status_t)0); + } +} + +/** + * @ingroup mqtt + * Check connection with server + * @param client MQTT client + * @return 1 if connected to server, 0 otherwise + */ +u8_t +mqtt_client_is_connected(mqtt_client_t *client) +{ + LWIP_ASSERT("mqtt_client_is_connected: client != NULL", client); + return client->conn_state == MQTT_CONNECTED; +} + +#endif /* LWIP_TCP && LWIP_CALLBACK_API */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/netbiosns/netbiosns.c b/Sming/third-party/lwip2/lwip2-src/src/apps/netbiosns/netbiosns.c new file mode 100644 index 0000000000..2dfbe65901 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/netbiosns/netbiosns.c @@ -0,0 +1,367 @@ +/** + * @file + * NetBIOS name service responder + */ + +/** + * @defgroup netbiosns NETBIOS responder + * @ingroup apps + * + * This is an example implementation of a NetBIOS name server. + * It responds to name queries for a configurable name. + * Name resolving is not supported. + * + * Note that the device doesn't broadcast it's own name so can't + * detect duplicate names! + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/apps/netbiosns.h" + +#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/udp.h" +#include "lwip/netif.h" + +#include + +/** default port number for "NetBIOS Name service */ +#define NETBIOS_PORT 137 + +/** size of a NetBIOS name */ +#define NETBIOS_NAME_LEN 16 + +/** The Time-To-Live for NetBIOS name responds (in seconds) + * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ +#define NETBIOS_NAME_TTL 300000u + +/** NetBIOS header flags */ +#define NETB_HFLAG_RESPONSE 0x8000U +#define NETB_HFLAG_OPCODE 0x7800U +#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U +#define NETB_HFLAG_AUTHORATIVE 0x0400U +#define NETB_HFLAG_TRUNCATED 0x0200U +#define NETB_HFLAG_RECURS_DESIRED 0x0100U +#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U +#define NETB_HFLAG_BROADCAST 0x0010U +#define NETB_HFLAG_REPLYCODE 0x0008U +#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U + +/** NetBIOS name flags */ +#define NETB_NFLAG_UNIQUE 0x8000U +#define NETB_NFLAG_NODETYPE 0x6000U +#define NETB_NFLAG_NODETYPE_HNODE 0x6000U +#define NETB_NFLAG_NODETYPE_MNODE 0x4000U +#define NETB_NFLAG_NODETYPE_PNODE 0x2000U +#define NETB_NFLAG_NODETYPE_BNODE 0x0000U + +/** NetBIOS message header */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_hdr { + PACK_STRUCT_FIELD(u16_t trans_id); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(u16_t questions); + PACK_STRUCT_FIELD(u16_t answerRRs); + PACK_STRUCT_FIELD(u16_t authorityRRs); + PACK_STRUCT_FIELD(u16_t additionalRRs); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** NetBIOS message name part */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_name_hdr { + PACK_STRUCT_FLD_8(u8_t nametype); + PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]); + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t cls); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t datalen); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FLD_S(ip4_addr_p_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** NetBIOS message */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct netbios_resp +{ + struct netbios_hdr resp_hdr; + struct netbios_name_hdr resp_name; +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef NETBIOS_LWIP_NAME +#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME +#else +static char netbiosns_local_name[NETBIOS_NAME_LEN]; +#define NETBIOS_LOCAL_NAME netbiosns_local_name +#endif + +struct udp_pcb *netbiosns_pcb; + +/** Decode a NetBIOS name (from packet to string) */ +static int +netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len) +{ + char *pname; + char cname; + char cnbname; + int idx = 0; + + LWIP_UNUSED_ARG(name_dec_len); + + /* Start decoding netbios name. */ + pname = name_enc; + for (;;) { + /* Every two characters of the first level-encoded name + * turn into one character in the decoded name. */ + cname = *pname; + if (cname == '\0') + break; /* no more characters */ + if (cname == '.') + break; /* scope ID follows */ + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + return -1; + } + cname -= 'A'; + cnbname = cname << 4; + pname++; + + cname = *pname; + if (cname == '\0' || cname == '.') { + /* No more characters in the name - but we're in + * the middle of a pair. Not legal. */ + return -1; + } + if (cname < 'A' || cname > 'Z') { + /* Not legal. */ + return -1; + } + cname -= 'A'; + cnbname |= cname; + pname++; + + /* Do we have room to store the character? */ + if (idx < NETBIOS_NAME_LEN) { + /* Yes - store the character. */ + name_dec[idx++] = (cnbname!=' '?cnbname:'\0'); + } + } + + return 0; +} + +#if 0 /* function currently unused */ +/** Encode a NetBIOS name (from string to packet) - currently unused because + we don't ask for names. */ +static int +netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len) +{ + char *pname; + char cname; + unsigned char ucname; + int idx = 0; + + /* Start encoding netbios name. */ + pname = name_enc; + + for (;;) { + /* Every two characters of the first level-encoded name + * turn into one character in the decoded name. */ + cname = *pname; + if (cname == '\0') + break; /* no more characters */ + if (cname == '.') + break; /* scope ID follows */ + if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { + /* Not legal. */ + return -1; + } + + /* Do we have room to store the character? */ + if (idx >= name_dec_len) { + return -1; + } + + /* Yes - store the character. */ + ucname = cname; + name_dec[idx++] = ('A'+((ucname>>4) & 0x0F)); + name_dec[idx++] = ('A'+( ucname & 0x0F)); + pname++; + } + + /* Fill with "space" coding */ + for (;idx < name_dec_len - 1;) { + name_dec[idx++] = 'C'; + name_dec[idx++] = 'A'; + } + + /* Terminate string */ + name_dec[idx] = '\0'; + + return 0; +} +#endif /* 0 */ + +/** NetBIOS Name service recv callback */ +static void +netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + LWIP_UNUSED_ARG(arg); + + /* if packet is valid */ + if (p != NULL) { + char netbios_name[NETBIOS_NAME_LEN+1]; + struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload; + struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1); + + /* we only answer if we got a default interface */ + if (netif_default != NULL) { + /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ + /* if the packet is a NetBIOS name query question */ + if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && + ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && + (netbios_hdr->questions == PP_NTOHS(1))) { + /* decode the NetBIOS name */ + netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); + /* if the packet is for us */ + if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) { + struct pbuf *q; + struct netbios_resp *resp; + + q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); + if (q != NULL) { + resp = (struct netbios_resp*)q->payload; + + /* prepare NetBIOS header response */ + resp->resp_hdr.trans_id = netbios_hdr->trans_id; + resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | + NETB_HFLAG_OPCODE_NAME_QUERY | + NETB_HFLAG_AUTHORATIVE | + NETB_HFLAG_RECURS_DESIRED); + resp->resp_hdr.questions = 0; + resp->resp_hdr.answerRRs = PP_HTONS(1); + resp->resp_hdr.authorityRRs = 0; + resp->resp_hdr.additionalRRs = 0; + + /* prepare NetBIOS header datas */ + MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); + resp->resp_name.nametype = netbios_name_hdr->nametype; + resp->resp_name.type = netbios_name_hdr->type; + resp->resp_name.cls = netbios_name_hdr->cls; + resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); + resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr)); + resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); + ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default)); + + /* send the NetBIOS response */ + udp_sendto(upcb, q, addr, port); + + /* free the "reference" pbuf */ + pbuf_free(q); + } + } + } + } + /* free the pbuf */ + pbuf_free(p); + } +} + +/** + * @ingroup netbiosns + * Init netbios responder + */ +void +netbiosns_init(void) +{ +#ifdef NETBIOS_LWIP_NAME + LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); +#endif + + netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (netbiosns_pcb != NULL) { + /* we have to be allowed to send broadcast packets! */ + ip_set_option(netbiosns_pcb, SOF_BROADCAST); + udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT); + udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb); + } +} + +#ifndef NETBIOS_LWIP_NAME +/** + * @ingroup netbiosns + * Set netbios name. ATTENTION: the hostname must be less than 15 characters! + */ +void +netbiosns_set_name(const char* hostname) +{ + size_t copy_len = strlen(hostname); + LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN); + if (copy_len >= NETBIOS_NAME_LEN) { + copy_len = NETBIOS_NAME_LEN - 1; + } + MEMCPY(netbiosns_local_name, hostname, copy_len + 1); +} +#endif + +/** + * @ingroup netbiosns + * Stop netbios responder + */ +void +netbiosns_stop(void) +{ + if (netbiosns_pcb != NULL) { + udp_remove(netbiosns_pcb); + netbiosns_pcb = NULL; + } +} + +#endif /* LWIP_IPV4 && LWIP_UDP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.c new file mode 100644 index 0000000000..f35b760462 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.c @@ -0,0 +1,749 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) encoding + * + * @todo not optimised (yet), favor correctness over speed, favor speed over size + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "snmp_asn1.h" + +#define PBUF_OP_EXEC(code) \ + if ((code) != ERR_OK) { \ + return ERR_BUF; \ + } + +/** + * Encodes a TLV into a pbuf stream. + * + * @param pbuf_stream points to a pbuf stream + * @param tlv TLV to encode + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) +{ + u8_t data; + u8_t length_bytes_required; + + /* write type */ + if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { + /* extended format is not used by SNMP so we do not accept those values */ + return ERR_ARG; + } + if (tlv->type_len != 0) { + /* any other value as auto is not accepted for type (we always use one byte because extended syntax is prohibited) */ + return ERR_ARG; + } + + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, tlv->type)); + tlv->type_len = 1; + + /* write length */ + if (tlv->value_len <= 127) { + length_bytes_required = 1; + } else if (tlv->value_len <= 255) { + length_bytes_required = 2; + } else { + length_bytes_required = 3; + } + + /* check for forced min length */ + if (tlv->length_len > 0) { + if (tlv->length_len < length_bytes_required) { + /* unable to code requested length in requested number of bytes */ + return ERR_ARG; + } + + length_bytes_required = tlv->length_len; + } else { + tlv->length_len = length_bytes_required; + } + + if (length_bytes_required > 1) { + /* multi byte representation required */ + length_bytes_required--; + data = 0x80 | length_bytes_required; /* extended length definition, 1 length byte follows */ + + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); + + while (length_bytes_required > 1) { + if (length_bytes_required == 2) { + /* append high byte */ + data = (u8_t)(tlv->value_len >> 8); + } else { + /* append leading 0x00 */ + data = 0x00; + } + + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); + length_bytes_required--; + } + } + + /* append low byte */ + data = (u8_t)(tlv->value_len & 0xFF); + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, data)); + + return ERR_OK; +} + +/** + * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. + * + * @param pbuf_stream points to a pbuf stream + * @param raw_len raw data length + * @param raw points raw data + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len) +{ + PBUF_OP_EXEC(snmp_pbuf_stream_writebuf(pbuf_stream, raw, raw_len)); + + return ERR_OK; +} + +/** + * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. + * + * @param pbuf_stream points to a pbuf stream + * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) + * @param value is the host order u32_t value to be encoded + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_u32t_cnt() + */ +err_t +snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value) +{ + if (octets_needed > 5) { + return ERR_ARG; + } + if (octets_needed == 5) { + /* not enough bits in 'value' add leading 0x00 */ + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); + octets_needed--; + } + + while (octets_needed > 1) { + octets_needed--; + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); + } + + /* (only) one least significant octet */ + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); + + return ERR_OK; +} + +/** + * Encodes u64_t (counter64) into a pbuf chained ASN1 msg. + * + * @param pbuf_stream points to a pbuf stream + * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) + * @param value is the host order u32_t value to be encoded + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_u64t_cnt() + */ +err_t +snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value) +{ + if (octets_needed > 9) { + return ERR_ARG; + } + if (octets_needed == 9) { + /* not enough bits in 'value' add leading 0x00 */ + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00)); + octets_needed--; + } + + while (octets_needed > 4) { + octets_needed--; + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3)))); + } + + /* skip to low u32 */ + value++; + + while (octets_needed > 1) { + octets_needed--; + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3)))); + } + + /* always write at least one octet (also in case of value == 0) */ + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value))); + + return ERR_OK; +} + +/** + * Encodes s32_t integer into a pbuf chained ASN1 msg. + * + * @param pbuf_stream points to a pbuf stream + * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) + * @param value is the host order s32_t value to be encoded + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_s32t_cnt() + */ +err_t +snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value) +{ + while (octets_needed > 1) { + octets_needed--; + + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(value >> (octets_needed << 3)))); + } + + /* (only) one least significant octet */ + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)value)); + + return ERR_OK; +} + +/** + * Encodes object identifier into a pbuf chained ASN1 msg. + * + * @param pbuf_stream points to a pbuf stream + * @param oid points to object identifier array + * @param oid_len object identifier array length + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len) +{ + if (oid_len > 1) { + /* write compressed first two sub id's */ + u32_t compressed_byte = ((oid[0] * 40) + oid[1]); + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)compressed_byte)); + oid_len -= 2; + oid += 2; + } else { + /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ + /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ + return ERR_ARG; + } + + while (oid_len > 0) { + u32_t sub_id; + u8_t shift, tail; + + oid_len--; + sub_id = *oid; + tail = 0; + shift = 28; + while (shift > 0) { + u8_t code; + + code = (u8_t)(sub_id >> shift); + if ((code != 0) || (tail != 0)) { + tail = 1; + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, code | 0x80)); + } + shift -= 7; + } + PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)sub_id & 0x7F)); + + /* proceed to next sub-identifier */ + oid++; + } + return ERR_OK; +} + +/** + * Returns octet count for length. + * + * @param length parameter length + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) +{ + if (length < 0x80U) { + *octets_needed = 1; + } else if (length < 0x100U) { + *octets_needed = 2; + } else { + *octets_needed = 3; + } +} + +/** + * Returns octet count for an u32_t. + * + * @param value value to be encoded + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +void +snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) +{ + if (value < 0x80UL) { + *octets_needed = 1; + } else if (value < 0x8000UL) { + *octets_needed = 2; + } else if (value < 0x800000UL) { + *octets_needed = 3; + } else if (value < 0x80000000UL) { + *octets_needed = 4; + } else { + *octets_needed = 5; + } +} + +/** + * Returns octet count for an u64_t. + * + * @param value value to be encoded + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +void +snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed) +{ + /* check if high u32 is 0 */ + if (*value == 0x00) { + /* only low u32 is important */ + value++; + snmp_asn1_enc_u32t_cnt(*value, octets_needed); + } else { + /* low u32 does not matter for length determination */ + snmp_asn1_enc_u32t_cnt(*value, octets_needed); + *octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */ + } +} + +/** + * Returns octet count for an s32_t. + * + * @param value value to be encoded + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. + */ +void +snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) +{ + if (value < 0) { + value = ~value; + } + if (value < 0x80L) { + *octets_needed = 1; + } else if (value < 0x8000L) { + *octets_needed = 2; + } else if (value < 0x800000L) { + *octets_needed = 3; + } else { + *octets_needed = 4; + } +} + +/** + * Returns octet count for an object identifier. + * + * @param oid points to object identifier array + * @param oid_len object identifier array length + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed) +{ + u32_t sub_id; + + *octets_needed = 0; + if (oid_len > 1) { + /* compressed prefix in one octet */ + (*octets_needed)++; + oid_len -= 2; + oid += 2; + } + while (oid_len > 0) { + oid_len--; + sub_id = *oid; + + sub_id >>= 7; + (*octets_needed)++; + while (sub_id > 0) { + sub_id >>= 7; + (*octets_needed)++; + } + oid++; + } +} + +/** + * Decodes a TLV from a pbuf stream. + * + * @param pbuf_stream points to a pbuf stream + * @param tlv returns decoded TLV + * @return ERR_OK if successful, ERR_VAL if we can't decode + */ +err_t +snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv) +{ + u8_t data; + + /* decode type first */ + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + tlv->type = data; + + if ((tlv->type & SNMP_ASN1_DATATYPE_MASK) == SNMP_ASN1_DATATYPE_EXTENDED) { + /* extended format is not used by SNMP so we do not accept those values */ + return ERR_VAL; + } + tlv->type_len = 1; + + /* now, decode length */ + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + + if (data < 0x80) { /* short form */ + tlv->length_len = 1; + tlv->value_len = data; + } else if (data > 0x80) { /* long form */ + u8_t length_bytes = data - 0x80; + tlv->length_len = length_bytes + 1; /* this byte + defined number of length bytes following */ + tlv->value_len = 0; + + while (length_bytes > 0) { + /* we only support up to u16.maxvalue-1 (2 bytes) but have to accept leading zero bytes */ + if (tlv->value_len > 0xFF) { + return ERR_VAL; + } + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + tlv->value_len <<= 8; + tlv->value_len |= data; + + /* take care for special value used for indefinite length */ + if (tlv->value_len == 0xFFFF) { + return ERR_VAL; + } + + length_bytes--; + } + } else { /* data == 0x80 indefinite length form */ + /* (not allowed for SNMP; RFC 1157, 3.2.2) */ + return ERR_VAL; + } + + return ERR_OK; +} + +/** + * Decodes positive integer (counter, gauge, timeticks) into u32_t. + * + * @param pbuf_stream points to a pbuf stream + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +err_t +snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) +{ + u8_t data; + + if ((len > 0) && (len <= 5)) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + + /* expecting sign bit to be zero, only unsigned please! */ + if (((len == 5) && (data == 0x00)) || ((len < 5) && ((data & 0x80) == 0))) { + *value = data; + len--; + + while (len > 0) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + + *value <<= 8; + *value |= data; + } + + return ERR_OK; + } + } + + return ERR_VAL; +} + +/** + * Decodes large positive integer (counter64) into 2x u32_t. + * + * @param pbuf_stream points to a pbuf stream + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +err_t +snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value) +{ + u8_t data; + + if (len <= 4) { + /* high u32 is 0 */ + *value = 0; + /* directly skip to low u32 */ + value++; + } + + if ((len > 0) && (len <= 9)) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + + /* expecting sign bit to be zero, only unsigned please! */ + if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) { + *value = data; + len--; + + while (len > 0) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + + if (len == 4) { + /* skip to low u32 */ + value++; + *value = 0; + } else { + *value <<= 8; + } + + *value |= data; + len--; + } + + return ERR_OK; + } + } + + return ERR_VAL; +} + +/** + * Decodes integer into s32_t. + * + * @param pbuf_stream points to a pbuf stream + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed! + */ +err_t +snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + u8_t *lsb_ptr = (u8_t*)value; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; +#endif + u8_t sign; + u8_t data; + + if ((len > 0) && (len < 5)) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + + if (data & 0x80) { + /* negative, start from -1 */ + *value = -1; + sign = 1; + *lsb_ptr &= data; + } else { + /* positive, start from 0 */ + *value = 0; + sign = 0; + *lsb_ptr |= data; + } + + /* OR/AND octets with value */ + while (len > 0) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + +#if BYTE_ORDER == LITTLE_ENDIAN + *value <<= 8; +#endif +#if BYTE_ORDER == BIG_ENDIAN + *value >>= 8; +#endif + + if (sign) { + *lsb_ptr |= 255; + *lsb_ptr &= data; + } else { + *lsb_ptr |= data; + } + } + + return ERR_OK; + } + + return ERR_VAL; +} + +/** + * Decodes object identifier from incoming message into array of u32_t. + * + * @param pbuf_stream points to a pbuf stream + * @param len length of the coded object identifier + * @param oid return decoded object identifier + * @param oid_len return decoded object identifier length + * @param oid_max_len size of oid buffer + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len) +{ + u32_t *oid_ptr; + u8_t data; + + *oid_len = 0; + oid_ptr = oid; + if (len > 0) { + if (oid_max_len < 2) { + return ERR_MEM; + } + + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + + /* first compressed octet */ + if (data == 0x2B) { + /* (most) common case 1.3 (iso.org) */ + *oid_ptr = 1; + oid_ptr++; + *oid_ptr = 3; + oid_ptr++; + } else if (data < 40) { + *oid_ptr = 0; + oid_ptr++; + *oid_ptr = data; + oid_ptr++; + } else if (data < 80) { + *oid_ptr = 1; + oid_ptr++; + *oid_ptr = data - 40; + oid_ptr++; + } else { + *oid_ptr = 2; + oid_ptr++; + *oid_ptr = data - 80; + oid_ptr++; + } + *oid_len = 2; + } else { + /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */ + return ERR_OK; + } + + while ((len > 0) && (*oid_len < oid_max_len)) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + + if ((data & 0x80) == 0x00) { + /* sub-identifier uses single octet */ + *oid_ptr = data; + } else { + /* sub-identifier uses multiple octets */ + u32_t sub_id = (data & ~0x80); + while ((len > 0) && ((data & 0x80) != 0)) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data)); + len--; + + sub_id = (sub_id << 7) + (data & ~0x80); + } + + if ((data & 0x80) != 0) { + /* "more bytes following" bit still set at end of len */ + return ERR_VAL; + } + *oid_ptr = sub_id; + } + oid_ptr++; + (*oid_len)++; + } + + if (len > 0) { + /* OID to long to fit in our buffer */ + return ERR_MEM; + } + + return ERR_OK; +} + +/** + * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) + * from incoming message into array. + * + * @param pbuf_stream points to a pbuf stream + * @param len length of the coded raw data (zero is valid, e.g. empty string!) + * @param buf return raw bytes + * @param buf_len returns length of the raw return value + * @param buf_max_len buffer size + * @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len) +{ + if (len > buf_max_len) { + /* not enough dst space */ + return ERR_MEM; + } + *buf_len = len; + + while (len > 0) { + PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, buf)); + buf++; + len--; + } + + return ERR_OK; +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.h b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.h new file mode 100644 index 0000000000..ec50d8c9e3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_asn1.h @@ -0,0 +1,108 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + * Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_ASN1_H +#define LWIP_HDR_APPS_SNMP_ASN1_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP + +#include "lwip/err.h" +#include "lwip/apps/snmp_core.h" +#include "snmp_pbuf_stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_TLV_INDEFINITE_LENGTH 0x80 + +#define SNMP_ASN1_CLASS_MASK 0xC0 +#define SNMP_ASN1_CONTENTTYPE_MASK 0x20 +#define SNMP_ASN1_DATATYPE_MASK 0x1F +#define SNMP_ASN1_DATATYPE_EXTENDED 0x1F /* DataType indicating that datatype is encoded in following bytes */ + +/* context specific (SNMP) tags (from SNMP spec. RFC1157) */ +#define SNMP_ASN1_CONTEXT_PDU_GET_REQ 0 +#define SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_CONTEXT_PDU_GET_RESP 2 +#define SNMP_ASN1_CONTEXT_PDU_SET_REQ 3 +#define SNMP_ASN1_CONTEXT_PDU_TRAP 4 +#define SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ 5 + +#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT 0 +#define SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW 2 + +struct snmp_asn1_tlv +{ + u8_t type; /* only U8 because extended types are not specified by SNMP */ + u8_t type_len; /* encoded length of 'type' field (normally 1) */ + u8_t length_len; /* indicates how many bytes are required to encode the 'value_len' field */ + u16_t value_len; /* encoded length of the value */ +}; +#define SNMP_ASN1_TLV_HDR_LENGTH(tlv) ((tlv).type_len + (tlv).length_len) +#define SNMP_ASN1_TLV_LENGTH(tlv) ((tlv).type_len + (tlv).length_len + (tlv).value_len) +#define SNMP_ASN1_SET_TLV_PARAMS(tlv, type_, length_len_, value_len_) do { (tlv).type = (type_); (tlv).type_len = 0; (tlv).length_len = (length_len_); (tlv).value_len = (value_len_); } while (0); + +err_t snmp_asn1_dec_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv); +err_t snmp_asn1_dec_u32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value); +err_t snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len); +err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len); + +err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed); +err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len); +err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value); +err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value); +err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value); +err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core.c new file mode 100644 index 0000000000..c041833617 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core.c @@ -0,0 +1,1349 @@ +/** + * @file + * MIB tree access/construction functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel +*/ + +/** + * @defgroup snmp SNMPv2c agent + * @ingroup apps + * SNMPv2c compatible agent\n + * There is also a MIB compiler and a MIB viewer in lwIP contrib repository + * (lwip-contrib/apps/LwipMibCompiler).\n + * The agent implements the most important MIB2 MIBs including IPv6 support + * (interfaces, UDP, TCP, SNMP, ICMP, SYSTEM). IP MIB is an older version + * whithout IPv6 statistics (TODO).\n + * Rewritten by Martin Hentschel and + * Dirk Ziegelmeier \n + * Work on SNMPv3 has started, but is not finished.\n + * + * 0 Agent Capabilities + * ==================== + * + * Features: + * --------- + * - SNMPv2c support. + * - Low RAM usage - no memory pools, stack only. + * - MIB2 implementation is separated from SNMP stack. + * - Support for multiple MIBs (snmp_set_mibs() call) - e.g. for private MIB. + * - Simple and generic API for MIB implementation. + * - Comfortable node types and helper functions for scalar arrays and tables. + * - Counter64, bit and truthvalue datatype support. + * - Callbacks for SNMP writes e.g. to implement persistency. + * - Runs on two APIs: RAW and netconn. + * - Async API is gone - the stack now supports netconn API instead, + * so blocking operations can be done in MIB calls. + * SNMP runs in a worker thread when netconn API is used. + * - Simplified thread sync support for MIBs - useful when MIBs + * need to access variables shared with other threads where no locking is + * possible. Used in MIB2 to access lwIP stats from lwIP thread. + * + * MIB compiler (code generator): + * ------------------------------ + * - Provided in lwIP contrib repository. + * - Written in C#. MIB viewer used Windows Forms. + * - Developed on Windows with Visual Studio 2010. + * - Can be compiled and used on all platforms with http://www.monodevelop.com/. + * - Based on a heavily modified version of of SharpSnmpLib (a4bd05c6afb4) + * (https://sharpsnmplib.codeplex.com/SourceControl/network/forks/Nemo157/MIBParserUpdate). + * - MIB parser, C file generation framework and LWIP code generation are cleanly + * separated, which means the code may be useful as a base for code generation + * of other SNMP agents. + * + * Notes: + * ------ + * - Stack and MIB compiler were used to implement a Profinet device. + * Compiled/implemented MIBs: LLDP-MIB, LLDP-EXT-DOT3-MIB, LLDP-EXT-PNO-MIB. + * + * SNMPv1 per RFC1157 and SNMPv2c per RFC 3416 + * ------------------------------------------- + * Note the S in SNMP stands for "Simple". Note that "Simple" is + * relative. SNMP is simple compared to the complex ISO network + * management protocols CMIP (Common Management Information Protocol) + * and CMOT (CMip Over Tcp). + * + * MIB II + * ------ + * The standard lwIP stack management information base. + * This is a required MIB, so this is always enabled. + * The groups EGP, CMOT and transmission are disabled by default. + * + * Most mib-2 objects are not writable except: + * sysName, sysLocation, sysContact, snmpEnableAuthenTraps. + * Writing to or changing the ARP and IP address and route + * tables is not possible. + * + * Note lwIP has a very limited notion of IP routing. It currently + * doen't have a route table and doesn't have a notion of the U,G,H flags. + * Instead lwIP uses the interface list with only one default interface + * acting as a single gateway interface (G) for the default route. + * + * The agent returns a "virtual table" with the default route 0.0.0.0 + * for the default interface and network routes (no H) for each + * network interface in the netif_list. + * All routes are considered to be up (U). + * + * Loading additional MIBs + * ----------------------- + * MIBs can only be added in compile-time, not in run-time. + * + * + * 1 Building the Agent + * ==================== + * First of all you'll need to add the following define + * to your local lwipopts.h: + * \#define LWIP_SNMP 1 + * + * and add the source files your makefile. + * + * Note you'll might need to adapt you network driver to update + * the mib2 variables for your interface. + * + * 2 Running the Agent + * =================== + * The following function calls must be made in your program to + * actually get the SNMP agent running. + * + * Before starting the agent you should supply pointers + * for sysContact, sysLocation, and snmpEnableAuthenTraps. + * You can do this by calling + * + * - snmp_mib2_set_syscontact() + * - snmp_mib2_set_syslocation() + * - snmp_set_auth_traps_enabled() + * + * You can register a callback which is called on successful write access: + * snmp_set_write_callback(). + * + * Additionally you may want to set + * + * - snmp_mib2_set_sysdescr() + * - snmp_set_device_enterprise_oid() + * - snmp_mib2_set_sysname() + * + * Also before starting the agent you need to setup + * one or more trap destinations using these calls: + * + * - snmp_trap_dst_enable() + * - snmp_trap_dst_ip_set() + * + * If you need more than MIB2, set the MIBs you want to use + * by snmp_set_mibs(). + * + * Finally, enable the agent by calling snmp_init() + * + * @defgroup snmp_core Core + * @ingroup snmp + * + * @defgroup snmp_traps Traps + * @ingroup snmp + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "snmp_core_priv.h" +#include "lwip/netif.h" +#include + + +#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) + #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_SNMP) + #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif + +struct snmp_statistics snmp_stats; +static const struct snmp_obj_id snmp_device_enterprise_oid_default = {SNMP_DEVICE_ENTERPRISE_OID_LEN, SNMP_DEVICE_ENTERPRISE_OID}; +static const struct snmp_obj_id* snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; + +const u32_t snmp_zero_dot_zero_values[] = { 0, 0 }; +const struct snmp_obj_id_const_ref snmp_zero_dot_zero = { LWIP_ARRAYSIZE(snmp_zero_dot_zero_values), snmp_zero_dot_zero_values }; + + +#if SNMP_LWIP_MIB2 +#include "lwip/apps/snmp_mib2.h" +static const struct snmp_mib* const default_mibs[] = { &mib2 }; +static u8_t snmp_num_mibs = 1; +#else +static const struct snmp_mib* const default_mibs[] = { NULL }; +static u8_t snmp_num_mibs = 0; +#endif + +/* List of known mibs */ +static struct snmp_mib const * const *snmp_mibs = default_mibs; + +/** + * @ingroup snmp_core + * Sets the MIBs to use. + * Example: call snmp_set_mibs() as follows: + * static const struct snmp_mib *my_snmp_mibs[] = { + * &mib2, + * &private_mib + * }; + * snmp_set_mibs(my_snmp_mibs, LWIP_ARRAYSIZE(my_snmp_mibs)); + */ +void +snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs) +{ + LWIP_ASSERT("mibs pointer must be != NULL", (mibs != NULL)); + LWIP_ASSERT("num_mibs pointer must be != 0", (num_mibs != 0)); + snmp_mibs = mibs; + snmp_num_mibs = num_mibs; +} + +/** + * @ingroup snmp_core + * 'device enterprise oid' is used for 'device OID' field in trap PDU's (for identification of generating device) + * as well as for value returned by MIB-2 'sysObjectID' field (if internal MIB2 implementation is used). + * The 'device enterprise oid' shall point to an OID located under 'private-enterprises' branch (1.3.6.1.4.1.XXX). If a vendor + * wants to provide a custom object there, he has to get its own enterprise oid from IANA (http://www.iana.org). It + * is not allowed to use LWIP enterprise ID! + * In order to identify a specific device it is recommended to create a dedicated OID for each device type under its own + * enterprise oid. + * e.g. + * device a > 1.3.6.1.4.1.XXX(ent-oid).1(devices).1(device a) + * device b > 1.3.6.1.4.1.XXX(ent-oid).1(devices).2(device b) + * for more details see description of 'sysObjectID' field in RFC1213-MIB + */ +void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid) +{ + if (device_enterprise_oid == NULL) { + snmp_device_enterprise_oid = &snmp_device_enterprise_oid_default; + } else { + snmp_device_enterprise_oid = device_enterprise_oid; + } +} + +/** + * @ingroup snmp_core + * Get 'device enterprise oid' + */ +const struct snmp_obj_id* snmp_get_device_enterprise_oid(void) +{ + return snmp_device_enterprise_oid; +} + +#if LWIP_IPV4 +/** + * Conversion from InetAddressIPv4 oid to lwIP ip4_addr + * @param oid points to u32_t ident[4] input + * @param ip points to output struct + */ +u8_t +snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip) +{ + if ((oid[0] > 0xFF) || + (oid[1] > 0xFF) || + (oid[2] > 0xFF) || + (oid[3] > 0xFF)) { + ip4_addr_copy(*ip, *IP4_ADDR_ANY4); + return 0; + } + + IP4_ADDR(ip, oid[0], oid[1], oid[2], oid[3]); + return 1; +} + +/** + * Convert ip4_addr to InetAddressIPv4 (no InetAddressType) + * @param ip points to input struct + * @param oid points to u32_t ident[4] output + */ +void +snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid) +{ + oid[0] = ip4_addr1(ip); + oid[1] = ip4_addr2(ip); + oid[2] = ip4_addr3(ip); + oid[3] = ip4_addr4(ip); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Conversion from InetAddressIPv6 oid to lwIP ip6_addr + * @param oid points to u32_t oid[16] input + * @param ip points to output struct + */ +u8_t +snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip) +{ + if ((oid[0] > 0xFF) || + (oid[1] > 0xFF) || + (oid[2] > 0xFF) || + (oid[3] > 0xFF) || + (oid[4] > 0xFF) || + (oid[5] > 0xFF) || + (oid[6] > 0xFF) || + (oid[7] > 0xFF) || + (oid[8] > 0xFF) || + (oid[9] > 0xFF) || + (oid[10] > 0xFF) || + (oid[11] > 0xFF) || + (oid[12] > 0xFF) || + (oid[13] > 0xFF) || + (oid[14] > 0xFF) || + (oid[15] > 0xFF)) { + ip6_addr_set_any(ip); + return 0; + } + + ip->addr[0] = (oid[0] << 24) | (oid[1] << 16) | (oid[2] << 8) | (oid[3] << 0); + ip->addr[1] = (oid[4] << 24) | (oid[5] << 16) | (oid[6] << 8) | (oid[7] << 0); + ip->addr[2] = (oid[8] << 24) | (oid[9] << 16) | (oid[10] << 8) | (oid[11] << 0); + ip->addr[3] = (oid[12] << 24) | (oid[13] << 16) | (oid[14] << 8) | (oid[15] << 0); + return 1; +} + +/** + * Convert ip6_addr to InetAddressIPv6 (no InetAddressType) + * @param ip points to input struct + * @param oid points to u32_t ident[16] output + */ +void +snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid) +{ + oid[0] = (ip->addr[0] & 0xFF000000) >> 24; + oid[1] = (ip->addr[0] & 0x00FF0000) >> 16; + oid[2] = (ip->addr[0] & 0x0000FF00) >> 8; + oid[3] = (ip->addr[0] & 0x000000FF) >> 0; + oid[4] = (ip->addr[1] & 0xFF000000) >> 24; + oid[5] = (ip->addr[1] & 0x00FF0000) >> 16; + oid[6] = (ip->addr[1] & 0x0000FF00) >> 8; + oid[7] = (ip->addr[1] & 0x000000FF) >> 0; + oid[8] = (ip->addr[2] & 0xFF000000) >> 24; + oid[9] = (ip->addr[2] & 0x00FF0000) >> 16; + oid[10] = (ip->addr[2] & 0x0000FF00) >> 8; + oid[11] = (ip->addr[2] & 0x000000FF) >> 0; + oid[12] = (ip->addr[3] & 0xFF000000) >> 24; + oid[13] = (ip->addr[3] & 0x00FF0000) >> 16; + oid[14] = (ip->addr[3] & 0x0000FF00) >> 8; + oid[15] = (ip->addr[3] & 0x000000FF) >> 0; +} +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 || LWIP_IPV6 +/** + * Convert to InetAddressType+InetAddress+InetPortNumber + * @param ip IP address + * @param port Port + * @param oid OID + * @return OID length + */ +u8_t +snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid) +{ + u8_t idx; + + idx = snmp_ip_to_oid(ip, oid); + oid[idx] = port; + idx++; + + return idx; +} + +/** + * Convert to InetAddressType+InetAddress + * @param ip IP address + * @param oid OID + * @return OID length + */ +u8_t +snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid) +{ + if (IP_IS_ANY_TYPE_VAL(*ip)) { + oid[0] = 0; /* any */ + oid[1] = 0; /* no IP OIDs follow */ + return 2; + } else if (IP_IS_V6(ip)) { +#if LWIP_IPV6 + oid[0] = 2; /* ipv6 */ + oid[1] = 16; /* 16 InetAddressIPv6 OIDs follow */ + snmp_ip6_to_oid(ip_2_ip6(ip), &oid[2]); + return 18; +#else /* LWIP_IPV6 */ + return 0; +#endif /* LWIP_IPV6 */ + } else { +#if LWIP_IPV4 + oid[0] = 1; /* ipv4 */ + oid[1] = 4; /* 4 InetAddressIPv4 OIDs follow */ + snmp_ip4_to_oid(ip_2_ip4(ip), &oid[2]); + return 6; +#else /* LWIP_IPV4 */ + return 0; +#endif /* LWIP_IPV4 */ + } +} + +/** + * Convert from InetAddressType+InetAddress to ip_addr_t + * @param oid OID + * @param oid_len OID length + * @param ip IP address + * @return Parsed OID length + */ +u8_t +snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip) +{ + /* InetAddressType */ + if (oid_len < 1) { + return 0; + } + + if (oid[0] == 0) { /* any */ + /* 1x InetAddressType, 1x OID len */ + if (oid_len < 2) { + return 0; + } + if (oid[1] != 0) { + return 0; + } + + memset(ip, 0, sizeof(*ip)); + IP_SET_TYPE(ip, IPADDR_TYPE_ANY); + + return 2; + } else if (oid[0] == 1) { /* ipv4 */ +#if LWIP_IPV4 + /* 1x InetAddressType, 1x OID len, 4x InetAddressIPv4 */ + if (oid_len < 6) { + return 0; + } + + /* 4x ipv4 OID */ + if (oid[1] != 4) { + return 0; + } + + IP_SET_TYPE(ip, IPADDR_TYPE_V4); + if (!snmp_oid_to_ip4(&oid[2], ip_2_ip4(ip))) { + return 0; + } + + return 6; +#else /* LWIP_IPV4 */ + return 0; +#endif /* LWIP_IPV4 */ + } else if (oid[0] == 2) { /* ipv6 */ +#if LWIP_IPV6 + /* 1x InetAddressType, 1x OID len, 16x InetAddressIPv6 */ + if (oid_len < 18) { + return 0; + } + + /* 16x ipv6 OID */ + if (oid[1] != 16) { + return 0; + } + + IP_SET_TYPE(ip, IPADDR_TYPE_V6); + if (!snmp_oid_to_ip6(&oid[2], ip_2_ip6(ip))) { + return 0; + } + + return 18; +#else /* LWIP_IPV6 */ + return 0; +#endif /* LWIP_IPV6 */ + } else { /* unsupported InetAddressType */ + return 0; + } +} + +/** + * Convert from InetAddressType+InetAddress+InetPortNumber to ip_addr_t and u16_t + * @param oid OID + * @param oid_len OID length + * @param ip IP address + * @param port Port + * @return Parsed OID length + */ +u8_t +snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port) +{ + u8_t idx = 0; + + /* InetAddressType + InetAddress */ + idx += snmp_oid_to_ip(&oid[idx], oid_len-idx, ip); + if (idx == 0) { + return 0; + } + + /* InetPortNumber */ + if (oid_len < (idx+1)) { + return 0; + } + if (oid[idx] > 0xffff) { + return 0; + } + *port = (u16_t)oid[idx]; + idx++; + + return idx; +} + +#endif /* LWIP_IPV4 || LWIP_IPV6 */ + +/** + * Assign an OID to struct snmp_obj_id + * @param target Assignment target + * @param oid OID + * @param oid_len OID length + */ +void +snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) +{ + LWIP_ASSERT("oid_len <= LWIP_SNMP_OBJ_ID_LEN", oid_len <= SNMP_MAX_OBJ_ID_LEN); + + target->len = oid_len; + + if (oid_len > 0) { + MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); + } +} + +/** + * Prefix an OID to OID in struct snmp_obj_id + * @param target Assignment target to prefix + * @param oid OID + * @param oid_len OID length + */ +void +snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) +{ + LWIP_ASSERT("target->len + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); + + if (oid_len > 0) { + /* move existing OID to make room at the beginning for OID to insert */ + int i; + for (i = target->len-1; i>=0; i--) { + target->id[i + oid_len] = target->id[i]; + } + + /* paste oid at the beginning */ + MEMCPY(target->id, oid, oid_len * sizeof(u32_t)); + } +} + +/** + * Combine two OIDs into struct snmp_obj_id + * @param target Assignmet target + * @param oid1 OID 1 + * @param oid1_len OID 1 length + * @param oid2 OID 2 + * @param oid2_len OID 2 length + */ +void +snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) +{ + snmp_oid_assign(target, oid1, oid1_len); + snmp_oid_append(target, oid2, oid2_len); +} + +/** + * Append OIDs to struct snmp_obj_id + * @param target Assignment target to append to + * @param oid OID + * @param oid_len OID length + */ +void +snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len) +{ + LWIP_ASSERT("offset + oid_len <= LWIP_SNMP_OBJ_ID_LEN", (target->len + oid_len) <= SNMP_MAX_OBJ_ID_LEN); + + if (oid_len > 0) { + MEMCPY(&target->id[target->len], oid, oid_len * sizeof(u32_t)); + target->len += oid_len; + } +} + +/** + * Compare two OIDs + * @param oid1 OID 1 + * @param oid1_len OID 1 length + * @param oid2 OID 2 + * @param oid2_len OID 2 length + * @return -1: OID1<OID2 1: OID1 >OID2 0: equal + */ +s8_t +snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) +{ + u8_t level = 0; + LWIP_ASSERT("'oid1' param must not be NULL or 'oid1_len' param be 0!", (oid1 != NULL) || (oid1_len == 0)); + LWIP_ASSERT("'oid2' param must not be NULL or 'oid2_len' param be 0!", (oid2 != NULL) || (oid2_len == 0)); + + while ((level < oid1_len) && (level < oid2_len)) { + if (*oid1 < *oid2) { + return -1; + } + if (*oid1 > *oid2) { + return 1; + } + + level++; + oid1++; + oid2++; + } + + /* common part of both OID's is equal, compare length */ + if (oid1_len < oid2_len) { + return -1; + } + if (oid1_len > oid2_len) { + return 1; + } + + /* they are equal */ + return 0; +} + + +/** + * Check of two OIDs are equal + * @param oid1 OID 1 + * @param oid1_len OID 1 length + * @param oid2 OID 2 + * @param oid2_len OID 2 length + * @return 1: equal 0: non-equal + */ +u8_t +snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) +{ + return (snmp_oid_compare(oid1, oid1_len, oid2, oid2_len) == 0)? 1 : 0; +} + +/** + * Convert netif to interface index + * @param netif netif + * @return index + */ +u8_t +netif_to_num(const struct netif *netif) +{ + u8_t result = 0; + struct netif *netif_iterator = netif_list; + + while (netif_iterator != NULL) { + result++; + + if (netif_iterator == netif) { + return result; + } + + netif_iterator = netif_iterator->next; + } + + LWIP_ASSERT("netif not found in netif_list", 0); + return 0; +} + +static const struct snmp_mib* +snmp_get_mib_from_oid(const u32_t *oid, u8_t oid_len) +{ + const u32_t* list_oid; + const u32_t* searched_oid; + u8_t i, l; + + u8_t max_match_len = 0; + const struct snmp_mib* matched_mib = NULL; + + LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); + + if (oid_len == 0) { + return NULL; + } + + for (i = 0; i < snmp_num_mibs; i++) { + LWIP_ASSERT("MIB array not initialized correctly", (snmp_mibs[i] != NULL)); + LWIP_ASSERT("MIB array not initialized correctly - base OID is NULL", (snmp_mibs[i]->base_oid != NULL)); + + if (oid_len >= snmp_mibs[i]->base_oid_len) { + l = snmp_mibs[i]->base_oid_len; + list_oid = snmp_mibs[i]->base_oid; + searched_oid = oid; + + while (l > 0) { + if (*list_oid != *searched_oid) { + break; + } + + l--; + list_oid++; + searched_oid++; + } + + if ((l == 0) && (snmp_mibs[i]->base_oid_len > max_match_len)) { + max_match_len = snmp_mibs[i]->base_oid_len; + matched_mib = snmp_mibs[i]; + } + } + } + + return matched_mib; +} + +static const struct snmp_mib* +snmp_get_next_mib(const u32_t *oid, u8_t oid_len) +{ + u8_t i; + const struct snmp_mib* next_mib = NULL; + + LWIP_ASSERT("'oid' param must not be NULL!", (oid != NULL)); + + if (oid_len == 0) { + return NULL; + } + + for (i = 0; i < snmp_num_mibs; i++) { + if (snmp_mibs[i]->base_oid != NULL) { + /* check if mib is located behind starting point */ + if (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, oid, oid_len) > 0) { + if ((next_mib == NULL) || + (snmp_oid_compare(snmp_mibs[i]->base_oid, snmp_mibs[i]->base_oid_len, + next_mib->base_oid, next_mib->base_oid_len) < 0)) { + next_mib = snmp_mibs[i]; + } + } + } + } + + return next_mib; +} + +static const struct snmp_mib* +snmp_get_mib_between(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len) +{ + const struct snmp_mib* next_mib = snmp_get_next_mib(oid1, oid1_len); + + LWIP_ASSERT("'oid2' param must not be NULL!", (oid2 != NULL)); + LWIP_ASSERT("'oid2_len' param must be greater than 0!", (oid2_len > 0)); + + if (next_mib != NULL) { + if (snmp_oid_compare(next_mib->base_oid, next_mib->base_oid_len, oid2, oid2_len) < 0) { + return next_mib; + } + } + + return NULL; +} + +u8_t +snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance) +{ + u8_t result = SNMP_ERR_NOSUCHOBJECT; + const struct snmp_mib *mib; + const struct snmp_node *mn = NULL; + + mib = snmp_get_mib_from_oid(oid, oid_len); + if (mib != NULL) { + u8_t oid_instance_len; + + mn = snmp_mib_tree_resolve_exact(mib, oid, oid_len, &oid_instance_len); + if ((mn != NULL) && (mn->node_type != SNMP_NODE_TREE)) { + /* get instance */ + const struct snmp_leaf_node* leaf_node = (const struct snmp_leaf_node*)(const void*)mn; + + node_instance->node = mn; + snmp_oid_assign(&node_instance->instance_oid, oid + (oid_len - oid_instance_len), oid_instance_len); + + result = leaf_node->get_instance( + oid, + oid_len - oid_instance_len, + node_instance); + +#ifdef LWIP_DEBUG + if (result == SNMP_ERR_NOERROR) { + if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); + } + if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value and/or set_test function is specified\n")); + } + } +#endif + } + } + + return result; +} + +u8_t +snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance) +{ + const struct snmp_mib *mib; + const struct snmp_node *mn = NULL; + const u32_t* start_oid = NULL; + u8_t start_oid_len = 0; + + /* resolve target MIB from passed OID */ + mib = snmp_get_mib_from_oid(oid, oid_len); + if (mib == NULL) { + /* passed OID does not reference any known MIB, start at the next closest MIB */ + mib = snmp_get_next_mib(oid, oid_len); + + if (mib != NULL) { + start_oid = mib->base_oid; + start_oid_len = mib->base_oid_len; + } + } else { + start_oid = oid; + start_oid_len = oid_len; + } + + /* resolve target node from MIB, skip to next MIB if no suitable node is found in current MIB */ + while ((mib != NULL) && (mn == NULL)) { + u8_t oid_instance_len; + + /* check if OID directly references a node inside current MIB, in this case we have to ask this node for the next instance */ + mn = snmp_mib_tree_resolve_exact(mib, start_oid, start_oid_len, &oid_instance_len); + if (mn != NULL) { + snmp_oid_assign(node_oid, start_oid, start_oid_len - oid_instance_len); /* set oid to node */ + snmp_oid_assign(&node_instance->instance_oid, start_oid + (start_oid_len - oid_instance_len), oid_instance_len); /* set (relative) instance oid */ + } else { + /* OID does not reference a node, search for the next closest node inside MIB; set instance_oid.len to zero because we want the first instance of this node */ + mn = snmp_mib_tree_resolve_next(mib, start_oid, start_oid_len, node_oid); + node_instance->instance_oid.len = 0; + } + + /* validate the node; if the node has no further instance or the returned instance is invalid, search for the next in MIB and validate again */ + node_instance->node = mn; + while (mn != NULL) { + u8_t result; + + /* clear fields which may have values from previous loops */ + node_instance->asn1_type = 0; + node_instance->access = SNMP_NODE_INSTANCE_NOT_ACCESSIBLE; + node_instance->get_value = NULL; + node_instance->set_test = NULL; + node_instance->set_value = NULL; + node_instance->release_instance = NULL; + node_instance->reference.ptr = NULL; + node_instance->reference_len = 0; + + result = ((const struct snmp_leaf_node*)(const void*)mn)->get_next_instance( + node_oid->id, + node_oid->len, + node_instance); + + if (result == SNMP_ERR_NOERROR) { +#ifdef LWIP_DEBUG + if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != 0) && (node_instance->get_value == NULL)) { + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is readable but no get_value function is specified\n")); + } + if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != 0) && (node_instance->set_value == NULL)) { + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP inconsistent access: node is writable but no set_value function is specified\n")); + } +#endif + + /* validate node because the node may be not accessible for example (but let the caller decide what is valid */ + if ((validate_node_instance_method == NULL) || + (validate_node_instance_method(node_instance, validate_node_instance_arg) == SNMP_ERR_NOERROR)) { + /* node_oid "returns" the full result OID (including the instance part) */ + snmp_oid_append(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); + break; + } + + if (node_instance->release_instance != NULL) { + node_instance->release_instance(node_instance); + } + /* + the instance itself is not valid, ask for next instance from same node. + we don't have to change any variables because node_instance->instance_oid is used as input (starting point) + as well as output (resulting next OID), so we have to simply call get_next_instance method again + */ + } else { + if (node_instance->release_instance != NULL) { + node_instance->release_instance(node_instance); + } + + /* the node has no further instance, skip to next node */ + mn = snmp_mib_tree_resolve_next(mib, node_oid->id, node_oid->len, &node_instance->instance_oid); /* misuse node_instance->instance_oid as tmp buffer */ + if (mn != NULL) { + /* prepare for next loop */ + snmp_oid_assign(node_oid, node_instance->instance_oid.id, node_instance->instance_oid.len); + node_instance->instance_oid.len = 0; + node_instance->node = mn; + } + } + } + + if (mn != NULL) { + /* + we found a suitable next node, + now we have to check if a inner MIB is located between the searched OID and the resulting OID. + this is possible because MIB's may be located anywhere in the global tree, that means also in + the subtree of another MIB (e.g. if searched OID is .2 and resulting OID is .4, then another + MIB having .3 as root node may exist) + */ + const struct snmp_mib *intermediate_mib; + intermediate_mib = snmp_get_mib_between(start_oid, start_oid_len, node_oid->id, node_oid->len); + + if (intermediate_mib != NULL) { + /* search for first node inside intermediate mib in next loop */ + if (node_instance->release_instance != NULL) { + node_instance->release_instance(node_instance); + } + + mn = NULL; + mib = intermediate_mib; + start_oid = mib->base_oid; + start_oid_len = mib->base_oid_len; + } + /* else { we found out target node } */ + } else { + /* + there is no further (suitable) node inside this MIB, search for the next MIB with following priority + 1. search for inner MIB's (whose root is located inside tree of current MIB) + 2. search for surrouding MIB's (where the current MIB is the inner MIB) and continue there if any + 3. take the next closest MIB (not being related to the current MIB) + */ + const struct snmp_mib *next_mib; + next_mib = snmp_get_next_mib(start_oid, start_oid_len); /* returns MIB's related to point 1 and 3 */ + + /* is the found MIB an inner MIB? (point 1) */ + if ((next_mib != NULL) && (next_mib->base_oid_len > mib->base_oid_len) && + (snmp_oid_compare(next_mib->base_oid, mib->base_oid_len, mib->base_oid, mib->base_oid_len) == 0)) { + /* yes it is -> continue at inner MIB */ + mib = next_mib; + start_oid = mib->base_oid; + start_oid_len = mib->base_oid_len; + } else { + /* check if there is a surrounding mib where to continue (point 2) (only possible if OID length > 1) */ + if (mib->base_oid_len > 1) { + mib = snmp_get_mib_from_oid(mib->base_oid, mib->base_oid_len - 1); + + if (mib == NULL) { + /* no surrounding mib, use next mib encountered above (point 3) */ + mib = next_mib; + + if (mib != NULL) { + start_oid = mib->base_oid; + start_oid_len = mib->base_oid_len; + } + } + /* else { start_oid stays the same because we want to continue from current offset in surrounding mib (point 2) } */ + } + } + } + } + + if (mib == NULL) { + /* loop is only left when mib == null (error) or mib_node != NULL (success) */ + return SNMP_ERR_ENDOFMIBVIEW; + } + + return SNMP_ERR_NOERROR; +} + +/** + * Searches tree for the supplied object identifier. + * + */ +const struct snmp_node * +snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len) +{ + const struct snmp_node* const* node = &mib->root_node; + u8_t oid_offset = mib->base_oid_len; + + while ((oid_offset < oid_len) && ((*node)->node_type == SNMP_NODE_TREE)) { + /* search for matching sub node */ + u32_t subnode_oid = *(oid + oid_offset); + + u32_t i = (*(const struct snmp_tree_node* const*)node)->subnode_count; + node = (*(const struct snmp_tree_node* const*)node)->subnodes; + while ((i > 0) && ((*node)->oid != subnode_oid)) { + node++; + i--; + } + + if (i == 0) { + /* no matching subnode found */ + return NULL; + } + + oid_offset++; + } + + if ((*node)->node_type != SNMP_NODE_TREE) { + /* we found a leaf node */ + *oid_instance_len = oid_len - oid_offset; + return (*node); + } + + return NULL; +} + +const struct snmp_node* +snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret) +{ + u8_t oid_offset = mib->base_oid_len; + const struct snmp_node* const* node; + const struct snmp_tree_node* node_stack[SNMP_MAX_OBJ_ID_LEN]; + s32_t nsi = 0; /* NodeStackIndex */ + u32_t subnode_oid; + + if (mib->root_node->node_type != SNMP_NODE_TREE) { + /* a next operation on a mib with only a leaf node will always return NULL because there is no other node */ + return NULL; + } + + /* first build node stack related to passed oid (as far as possible), then go backwards to determine the next node */ + node_stack[nsi] = (const struct snmp_tree_node*)(const void*)mib->root_node; + while (oid_offset < oid_len) { + /* search for matching sub node */ + u32_t i = node_stack[nsi]->subnode_count; + node = node_stack[nsi]->subnodes; + + subnode_oid = *(oid + oid_offset); + + while ((i > 0) && ((*node)->oid != subnode_oid)) { + node++; + i--; + } + + if ((i == 0) || ((*node)->node_type != SNMP_NODE_TREE)) { + /* no (matching) tree-subnode found */ + break; + } + nsi++; + node_stack[nsi] = (const struct snmp_tree_node*)(const void*)(*node); + + oid_offset++; + } + + + if (oid_offset >= oid_len) { + /* passed oid references a tree node -> return first useable sub node of it */ + subnode_oid = 0; + } else { + subnode_oid = *(oid + oid_offset) + 1; + } + + while (nsi >= 0) { + const struct snmp_node* subnode = NULL; + + /* find next node on current level */ + s32_t i = node_stack[nsi]->subnode_count; + node = node_stack[nsi]->subnodes; + while (i > 0) { + if ((*node)->oid == subnode_oid) { + subnode = *node; + break; + } else if (((*node)->oid > subnode_oid) && ((subnode == NULL) || ((*node)->oid < subnode->oid))) { + subnode = *node; + } + + node++; + i--; + } + + if (subnode == NULL) { + /* no further node found on this level, go one level up and start searching with index of current node*/ + subnode_oid = node_stack[nsi]->node.oid + 1; + nsi--; + } else { + if (subnode->node_type == SNMP_NODE_TREE) { + /* next is a tree node, go into it and start searching */ + nsi++; + node_stack[nsi] = (const struct snmp_tree_node*)(const void*)subnode; + subnode_oid = 0; + } else { + /* we found a leaf node -> fill oidret and return it */ + snmp_oid_assign(oidret, mib->base_oid, mib->base_oid_len); + i = 1; + while (i <= nsi) { + oidret->id[oidret->len] = node_stack[i]->node.oid; + oidret->len++; + i++; + } + + oidret->id[oidret->len] = subnode->oid; + oidret->len++; + + return subnode; + } + } + } + + return NULL; +} + +/** initialize struct next_oid_state using this function before passing it to next_oid_check */ +void +snmp_next_oid_init(struct snmp_next_oid_state *state, + const u32_t *start_oid, u8_t start_oid_len, + u32_t *next_oid_buf, u8_t next_oid_max_len) +{ + state->start_oid = start_oid; + state->start_oid_len = start_oid_len; + state->next_oid = next_oid_buf; + state->next_oid_len = 0; + state->next_oid_max_len = next_oid_max_len; + state->status = SNMP_NEXT_OID_STATUS_NO_MATCH; +} + +/** checks if the passed incomplete OID may be a possible candidate for snmp_next_oid_check(); +this methid is intended if the complete OID is not yet known but it is very expensive to build it up, +so it is possible to test the starting part before building up the complete oid and pass it to snmp_next_oid_check()*/ +u8_t +snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len) +{ + if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { + u8_t start_oid_len = (oid_len < state->start_oid_len) ? oid_len : state->start_oid_len; + + /* check passed OID is located behind start offset */ + if (snmp_oid_compare(oid, oid_len, state->start_oid, start_oid_len) >= 0) { + /* check if new oid is located closer to start oid than current closest oid */ + if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || + (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { + return 1; + } + } + } + + return 0; +} + +/** checks the passed OID if it is a candidate to be the next one (get_next); returns !=0 if passed oid is currently closest, otherwise 0 */ +u8_t +snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference) +{ + /* do not overwrite a fail result */ + if (state->status != SNMP_NEXT_OID_STATUS_BUF_TO_SMALL) { + /* check passed OID is located behind start offset */ + if (snmp_oid_compare(oid, oid_len, state->start_oid, state->start_oid_len) > 0) { + /* check if new oid is located closer to start oid than current closest oid */ + if ((state->status == SNMP_NEXT_OID_STATUS_NO_MATCH) || + (snmp_oid_compare(oid, oid_len, state->next_oid, state->next_oid_len) < 0)) { + if (oid_len <= state->next_oid_max_len) { + MEMCPY(state->next_oid, oid, oid_len * sizeof(u32_t)); + state->next_oid_len = oid_len; + state->status = SNMP_NEXT_OID_STATUS_SUCCESS; + state->reference = reference; + return 1; + } else { + state->status = SNMP_NEXT_OID_STATUS_BUF_TO_SMALL; + } + } + } + } + + return 0; +} + +u8_t +snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len) +{ + u8_t i; + + if (oid_len != oid_ranges_len) { + return 0; + } + + for (i = 0; i < oid_ranges_len; i++) { + if ((oid_in[i] < oid_ranges[i].min) || (oid_in[i] > oid_ranges[i].max)) { + return 0; + } + } + + return 1; +} + +snmp_err_t +snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value) +{ + LWIP_UNUSED_ARG(instance); + LWIP_UNUSED_ARG(value_len); + LWIP_UNUSED_ARG(value); + + return SNMP_ERR_NOERROR; +} + +/** + * Decodes BITS pseudotype value from ASN.1 OctetString. + * + * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly + * be encoded/decoded by the agent. Instead call this function as required from + * get/test/set methods. + * + * @param buf points to a buffer holding the ASN1 octet string + * @param buf_len length of octet string + * @param bit_value decoded Bit value with Bit0 == LSB + * @return ERR_OK if successful, ERR_ARG if bit value contains more than 32 bit + */ +err_t +snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value) +{ + u8_t b; + u8_t bits_processed = 0; + *bit_value = 0; + + while (buf_len > 0) { + /* any bit set in this byte? */ + if (*buf != 0x00) { + if (bits_processed >= 32) { + /* accept more than 4 bytes, but only when no bits are set */ + return ERR_VAL; + } + + b = *buf; + do { + if (b & 0x80) { + *bit_value |= (1 << bits_processed); + } + bits_processed++; + b <<= 1; + } + while ((bits_processed & 0x07) != 0); /* &0x07 -> % 8 */ + } else { + bits_processed += 8; + } + + buf_len--; + buf++; + } + + return ERR_OK; +} + +err_t +snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value) +{ + /* defined by RFC1443: + TruthValue ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents a boolean value." + SYNTAX INTEGER { true(1), false(2) } + */ + + if ((asn1_value == NULL) || (bool_value == NULL)) { + return ERR_ARG; + } + + if (*asn1_value == 1) { + *bool_value = 1; + } else if (*asn1_value == 2) { + *bool_value = 0; + } else { + return ERR_VAL; + } + + return ERR_OK; +} + +/** + * Encodes BITS pseudotype value into ASN.1 OctetString. + * + * @note Because BITS pseudo type is encoded as OCTET STRING, it cannot directly + * be encoded/decoded by the agent. Instead call this function as required from + * get/test/set methods. + * + * @param buf points to a buffer where the resulting ASN1 octet string is stored to + * @param buf_len max length of the bufffer + * @param bit_value Bit value to encode with Bit0 == LSB + * @param bit_count Number of possible bits for the bit value (according to rfc we have to send all bits independant from their truth value) + * @return number of bytes used from buffer to store the resulting OctetString + */ +u8_t +snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count) +{ + u8_t len = 0; + u8_t min_bytes = (bit_count + 7) >> 3; /* >>3 -> / 8 */ + + while ((buf_len > 0) && (bit_value != 0x00)) { + s8_t i = 7; + *buf = 0x00; + while (i >= 0) { + if (bit_value & 0x01) { + *buf |= 0x01; + } + + if (i > 0) { + *buf <<= 1; + } + + bit_value >>= 1; + i--; + } + + buf++; + buf_len--; + len++; + } + + if (len < min_bytes) { + buf += len; + buf_len -= len; + + while ((len < min_bytes) && (buf_len > 0)) { + *buf = 0x00; + buf++; + buf_len--; + len++; + } + } + + return len; +} + +u8_t +snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value) +{ + /* defined by RFC1443: + TruthValue ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents a boolean value." + SYNTAX INTEGER { true(1), false(2) } + */ + + if (asn1_value == NULL) { + return 0; + } + + if (bool_value) { + *asn1_value = 1; /* defined by RFC1443 */ + } else { + *asn1_value = 2; /* defined by RFC1443 */ + } + + return sizeof(s32_t); +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core_priv.h b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core_priv.h new file mode 100644 index 0000000000..5552177d74 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_core_priv.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_CORE_PRIV_H +#define LWIP_HDR_APPS_SNMP_CORE_PRIV_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_core.h" +#include "snmp_asn1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* (outdated) SNMPv1 error codes + * shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request + */ +#define SNMP_ERR_NOSUCHNAME 2 +#define SNMP_ERR_BADVALUE 3 +#define SNMP_ERR_READONLY 4 +/* error codes which are internal and shall not be used by MIBS + * shall not be used by MIBS anymore, nevertheless required from core for properly answering a v1 request + */ +#define SNMP_ERR_TOOBIG 1 +#define SNMP_ERR_AUTHORIZATIONERROR 16 +#define SNMP_ERR_NOSUCHOBJECT SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_OBJECT +#define SNMP_ERR_ENDOFMIBVIEW SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW + + +const struct snmp_node* snmp_mib_tree_resolve_exact(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, u8_t* oid_instance_len); +const struct snmp_node* snmp_mib_tree_resolve_next(const struct snmp_mib *mib, const u32_t *oid, u8_t oid_len, struct snmp_obj_id* oidret); + +typedef u8_t (*snmp_validate_node_instance_method)(struct snmp_node_instance*, void*); + +u8_t snmp_get_node_instance_from_oid(const u32_t *oid, u8_t oid_len, struct snmp_node_instance* node_instance); +u8_t snmp_get_next_node_instance_from_oid(const u32_t *oid, u8_t oid_len, snmp_validate_node_instance_method validate_node_instance_method, void* validate_node_instance_arg, struct snmp_obj_id* node_oid, struct snmp_node_instance* node_instance); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_CORE_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2.c new file mode 100644 index 0000000000..9d8c43c108 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2.c @@ -0,0 +1,116 @@ +/** + * @file + * Management Information Base II (RFC1213) objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +/** + * @defgroup snmp_mib2 MIB2 + * @ingroup snmp + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP && SNMP_LWIP_MIB2 /* don't build if not configured for use in lwipopts.h */ + +#if !LWIP_STATS +#error LWIP_SNMP MIB2 needs LWIP_STATS (for MIB2) +#endif +#if !MIB2_STATS +#error LWIP_SNMP MIB2 needs MIB2_STATS (for MIB2) +#endif + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_scalar.h" + +#if SNMP_USE_NETCONN +#include "lwip/tcpip.h" +#include "lwip/priv/tcpip_priv.h" +void +snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg) +{ +#if LWIP_TCPIP_CORE_LOCKING + LOCK_TCPIP_CORE(); + fn(arg); + UNLOCK_TCPIP_CORE(); +#else + tcpip_callback(fn, arg); +#endif +} + +struct snmp_threadsync_instance snmp_mib2_lwip_locks; +#endif + +/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */ +/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */ +/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */ + +/* --- mib-2 .1.3.6.1.2.1 ----------------------------------------------------- */ +extern const struct snmp_scalar_array_node snmp_mib2_snmp_root; +extern const struct snmp_tree_node snmp_mib2_udp_root; +extern const struct snmp_tree_node snmp_mib2_tcp_root; +extern const struct snmp_scalar_array_node snmp_mib2_icmp_root; +extern const struct snmp_tree_node snmp_mib2_interface_root; +extern const struct snmp_scalar_array_node snmp_mib2_system_node; +extern const struct snmp_tree_node snmp_mib2_at_root; +extern const struct snmp_tree_node snmp_mib2_ip_root; + +static const struct snmp_node* const mib2_nodes[] = { + &snmp_mib2_system_node.node.node, + &snmp_mib2_interface_root.node, +#if LWIP_ARP && LWIP_IPV4 + &snmp_mib2_at_root.node, +#endif /* LWIP_ARP && LWIP_IPV4 */ +#if LWIP_IPV4 + &snmp_mib2_ip_root.node, +#endif /* LWIP_IPV4 */ +#if LWIP_ICMP + &snmp_mib2_icmp_root.node.node, +#endif /* LWIP_ICMP */ +#if LWIP_TCP + &snmp_mib2_tcp_root.node, +#endif /* LWIP_TCP */ +#if LWIP_UDP + &snmp_mib2_udp_root.node, +#endif /* LWIP_UDP */ + &snmp_mib2_snmp_root.node.node +}; + +static const struct snmp_tree_node mib2_root = SNMP_CREATE_TREE_NODE(1, mib2_nodes); + +static const u32_t mib2_base_oid_arr[] = { 1,3,6,1,2,1 }; +const struct snmp_mib mib2 = SNMP_MIB_CREATE(mib2_base_oid_arr, &mib2_root.node); + +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_icmp.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_icmp.c new file mode 100644 index 0000000000..995bd320a5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_icmp.c @@ -0,0 +1,182 @@ +/** + * @file + * Management Information Base II (RFC1213) ICMP objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/icmp.h" +#include "lwip/stats.h" + +#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + +/* --- icmp .1.3.6.1.2.1.5 ----------------------------------------------------- */ + +static s16_t +icmp_get_value(const struct snmp_scalar_array_node_def *node, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + + switch (node->oid) { + case 1: /* icmpInMsgs */ + *uint_ptr = STATS_GET(mib2.icmpinmsgs); + return sizeof(*uint_ptr); + case 2: /* icmpInErrors */ + *uint_ptr = STATS_GET(mib2.icmpinerrors); + return sizeof(*uint_ptr); + case 3: /* icmpInDestUnreachs */ + *uint_ptr = STATS_GET(mib2.icmpindestunreachs); + return sizeof(*uint_ptr); + case 4: /* icmpInTimeExcds */ + *uint_ptr = STATS_GET(mib2.icmpintimeexcds); + return sizeof(*uint_ptr); + case 5: /* icmpInParmProbs */ + *uint_ptr = STATS_GET(mib2.icmpinparmprobs); + return sizeof(*uint_ptr); + case 6: /* icmpInSrcQuenchs */ + *uint_ptr = STATS_GET(mib2.icmpinsrcquenchs); + return sizeof(*uint_ptr); + case 7: /* icmpInRedirects */ + *uint_ptr = STATS_GET(mib2.icmpinredirects); + return sizeof(*uint_ptr); + case 8: /* icmpInEchos */ + *uint_ptr = STATS_GET(mib2.icmpinechos); + return sizeof(*uint_ptr); + case 9: /* icmpInEchoReps */ + *uint_ptr = STATS_GET(mib2.icmpinechoreps); + return sizeof(*uint_ptr); + case 10: /* icmpInTimestamps */ + *uint_ptr = STATS_GET(mib2.icmpintimestamps); + return sizeof(*uint_ptr); + case 11: /* icmpInTimestampReps */ + *uint_ptr = STATS_GET(mib2.icmpintimestampreps); + return sizeof(*uint_ptr); + case 12: /* icmpInAddrMasks */ + *uint_ptr = STATS_GET(mib2.icmpinaddrmasks); + return sizeof(*uint_ptr); + case 13: /* icmpInAddrMaskReps */ + *uint_ptr = STATS_GET(mib2.icmpinaddrmaskreps); + return sizeof(*uint_ptr); + case 14: /* icmpOutMsgs */ + *uint_ptr = STATS_GET(mib2.icmpoutmsgs); + return sizeof(*uint_ptr); + case 15: /* icmpOutErrors */ + *uint_ptr = STATS_GET(mib2.icmpouterrors); + return sizeof(*uint_ptr); + case 16: /* icmpOutDestUnreachs */ + *uint_ptr = STATS_GET(mib2.icmpoutdestunreachs); + return sizeof(*uint_ptr); + case 17: /* icmpOutTimeExcds */ + *uint_ptr = STATS_GET(mib2.icmpouttimeexcds); + return sizeof(*uint_ptr); + case 18: /* icmpOutParmProbs: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 19: /* icmpOutSrcQuenchs: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 20: /* icmpOutRedirects: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 21: /* icmpOutEchos */ + *uint_ptr = STATS_GET(mib2.icmpoutechos); + return sizeof(*uint_ptr); + case 22: /* icmpOutEchoReps */ + *uint_ptr = STATS_GET(mib2.icmpoutechoreps); + return sizeof(*uint_ptr); + case 23: /* icmpOutTimestamps: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 24: /* icmpOutTimestampReps: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 25: /* icmpOutAddrMasks: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + case 26: /* icmpOutAddrMaskReps: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %"S32_F"\n", node->oid)); + break; + } + + return 0; +} + + +static const struct snmp_scalar_array_node_def icmp_nodes[] = { + { 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 7, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + { 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {23, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, + {26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} +}; + +const struct snmp_scalar_array_node snmp_mib2_icmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(5, icmp_nodes, icmp_get_value, NULL, NULL); + +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_ICMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_interfaces.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_interfaces.c new file mode 100644 index 0000000000..979b5073ea --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_interfaces.c @@ -0,0 +1,375 @@ +/** + * @file + * Management Information Base II (RFC1213) INTERFACES objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/netif.h" +#include "lwip/stats.h" + +#include + +#if LWIP_SNMP && SNMP_LWIP_MIB2 + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + + +/* --- interfaces .1.3.6.1.2.1.2 ----------------------------------------------------- */ + +static s16_t +interfaces_get_value(struct snmp_node_instance* instance, void* value) +{ + if (instance->node->oid == 1) { + s32_t *sint_ptr = (s32_t*)value; + s32_t num_netifs = 0; + + struct netif *netif = netif_list; + while (netif != NULL) { + num_netifs++; + netif = netif->next; + } + + *sint_ptr = num_netifs; + return sizeof(*sint_ptr); + } + + return 0; +} + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range interfaces_Table_oid_ranges[] = { + { 1, 0xff } /* netif->num is u8_t */ +}; + +static const u8_t iftable_ifOutQLen = 0; + +static const u8_t iftable_ifOperStatus_up = 1; +static const u8_t iftable_ifOperStatus_down = 2; + +static const u8_t iftable_ifAdminStatus_up = 1; +static const u8_t iftable_ifAdminStatus_lowerLayerDown = 7; +static const u8_t iftable_ifAdminStatus_down = 2; + +static snmp_err_t +interfaces_Table_get_cell_instance(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance) +{ + u32_t ifIndex; + struct netif *netif; + + LWIP_UNUSED_ARG(column); + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, interfaces_Table_oid_ranges, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get netif index from incoming OID */ + ifIndex = row_oid[0]; + + /* find netif with index */ + netif = netif_list; + while (netif != NULL) { + if (netif_to_num(netif) == ifIndex) { + /* store netif pointer for subsequent operations (get/test/set) */ + cell_instance->reference.ptr = netif; + return SNMP_ERR_NOERROR; + } + netif = netif->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance) +{ + struct netif *netif; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)]; + + LWIP_UNUSED_ARG(column); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + netif = netif_list; + while (netif != NULL) { + u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)]; + test_oid[0] = netif_to_num(netif); + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif); + + netif = netif->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* store netif pointer for subsequent operations (get/test/set) */ + cell_instance->reference.ptr = /* (struct netif*) */state.reference; + return SNMP_ERR_NOERROR; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static s16_t +interfaces_Table_get_value(struct snmp_node_instance* instance, void* value) +{ + struct netif *netif = (struct netif*)instance->reference.ptr; + u32_t* value_u32 = (u32_t*)value; + s32_t* value_s32 = (s32_t*)value; + u16_t value_len; + + switch (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id)) + { + case 1: /* ifIndex */ + *value_s32 = netif_to_num(netif); + value_len = sizeof(*value_s32); + break; + case 2: /* ifDescr */ + value_len = sizeof(netif->name); + MEMCPY(value, netif->name, value_len); + break; + case 3: /* ifType */ + *value_s32 = netif->link_type; + value_len = sizeof(*value_s32); + break; + case 4: /* ifMtu */ + *value_s32 = netif->mtu; + value_len = sizeof(*value_s32); + break; + case 5: /* ifSpeed */ + *value_u32 = netif->link_speed; + value_len = sizeof(*value_u32); + break; + case 6: /* ifPhysAddress */ + value_len = sizeof(netif->hwaddr); + MEMCPY(value, &netif->hwaddr, value_len); + break; + case 7: /* ifAdminStatus */ + if (netif_is_up(netif)) { + *value_s32 = iftable_ifOperStatus_up; + } else { + *value_s32 = iftable_ifOperStatus_down; + } + value_len = sizeof(*value_s32); + break; + case 8: /* ifOperStatus */ + if (netif_is_up(netif)) { + if (netif_is_link_up(netif)) { + *value_s32 = iftable_ifAdminStatus_up; + } else { + *value_s32 = iftable_ifAdminStatus_lowerLayerDown; + } + } else { + *value_s32 = iftable_ifAdminStatus_down; + } + value_len = sizeof(*value_s32); + break; + case 9: /* ifLastChange */ + *value_u32 = netif->ts; + value_len = sizeof(*value_u32); + break; + case 10: /* ifInOctets */ + *value_u32 = netif->mib2_counters.ifinoctets; + value_len = sizeof(*value_u32); + break; + case 11: /* ifInUcastPkts */ + *value_u32 = netif->mib2_counters.ifinucastpkts; + value_len = sizeof(*value_u32); + break; + case 12: /* ifInNUcastPkts */ + *value_u32 = netif->mib2_counters.ifinnucastpkts; + value_len = sizeof(*value_u32); + break; + case 13: /* ifInDiscards */ + *value_u32 = netif->mib2_counters.ifindiscards; + value_len = sizeof(*value_u32); + break; + case 14: /* ifInErrors */ + *value_u32 = netif->mib2_counters.ifinerrors; + value_len = sizeof(*value_u32); + break; + case 15: /* ifInUnkownProtos */ + *value_u32 = netif->mib2_counters.ifinunknownprotos; + value_len = sizeof(*value_u32); + break; + case 16: /* ifOutOctets */ + *value_u32 = netif->mib2_counters.ifoutoctets; + value_len = sizeof(*value_u32); + break; + case 17: /* ifOutUcastPkts */ + *value_u32 = netif->mib2_counters.ifoutucastpkts; + value_len = sizeof(*value_u32); + break; + case 18: /* ifOutNUcastPkts */ + *value_u32 = netif->mib2_counters.ifoutnucastpkts; + value_len = sizeof(*value_u32); + break; + case 19: /* ifOutDiscarts */ + *value_u32 = netif->mib2_counters.ifoutdiscards; + value_len = sizeof(*value_u32); + break; + case 20: /* ifOutErrors */ + *value_u32 = netif->mib2_counters.ifouterrors; + value_len = sizeof(*value_u32); + break; + case 21: /* ifOutQLen */ + *value_u32 = iftable_ifOutQLen; + value_len = sizeof(*value_u32); + break; + /** @note returning zeroDotZero (0.0) no media specific MIB support */ + case 22: /* ifSpecific */ + value_len = snmp_zero_dot_zero.len * sizeof(u32_t); + MEMCPY(value, snmp_zero_dot_zero.id, value_len); + break; + default: + return 0; + } + + return value_len; +} + +#if !SNMP_SAFE_REQUESTS + +static snmp_err_t +interfaces_Table_set_test(struct snmp_node_instance* instance, u16_t len, void *value) +{ + s32_t *sint_ptr = (s32_t*)value; + + /* stack should never call this method for another column, + because all other columns are set to readonly */ + LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7)); + LWIP_UNUSED_ARG(len); + + if (*sint_ptr == 1 || *sint_ptr == 2) { + return SNMP_ERR_NOERROR; + } + + return SNMP_ERR_WRONGVALUE; +} + +static snmp_err_t +interfaces_Table_set_value(struct snmp_node_instance* instance, u16_t len, void *value) +{ + struct netif *netif = (struct netif*)instance->reference.ptr; + s32_t *sint_ptr = (s32_t*)value; + + /* stack should never call this method for another column, + because all other columns are set to readonly */ + LWIP_ASSERT("Invalid column", (SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id) == 7)); + LWIP_UNUSED_ARG(len); + + if (*sint_ptr == 1) { + netif_set_up(netif); + } else if (*sint_ptr == 2) { + netif_set_down(netif); + } + + return SNMP_ERR_NOERROR; +} + +#endif /* SNMP_SAFE_REQUESTS */ + +static const struct snmp_scalar_node interfaces_Number = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, interfaces_get_value); + +static const struct snmp_table_col_def interfaces_Table_columns[] = { + { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifIndex */ + { 2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifDescr */ + { 3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifType */ + { 4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifMtu */ + { 5, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifSpeed */ + { 6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifPhysAddress */ +#if !SNMP_SAFE_REQUESTS + { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE }, /* ifAdminStatus */ +#else + { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifAdminStatus */ +#endif + { 8, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOperStatus */ + { 9, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifLastChange */ + { 10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInOctets */ + { 11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUcastPkts */ + { 12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInNUcastPkts */ + { 13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInDiscarts */ + { 14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInErrors */ + { 15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifInUnkownProtos */ + { 16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutOctets */ + { 17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutUcastPkts */ + { 18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutNUcastPkts */ + { 19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutDiscarts */ + { 20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutErrors */ + { 21, SNMP_ASN1_TYPE_GAUGE, SNMP_NODE_INSTANCE_READ_ONLY }, /* ifOutQLen */ + { 22, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY } /* ifSpecific */ +}; + +#if !SNMP_SAFE_REQUESTS +static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE( + 2, interfaces_Table_columns, + interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance, + interfaces_Table_get_value, interfaces_Table_set_test, interfaces_Table_set_value); +#else +static const struct snmp_table_node interfaces_Table = SNMP_TABLE_CREATE( + 2, interfaces_Table_columns, + interfaces_Table_get_cell_instance, interfaces_Table_get_next_cell_instance, + interfaces_Table_get_value, NULL, NULL); +#endif + +/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ +CREATE_LWIP_SYNC_NODE(1, interfaces_Number) +CREATE_LWIP_SYNC_NODE(2, interfaces_Table) + +static const struct snmp_node* const interface_nodes[] = { + &SYNC_NODE_NAME(interfaces_Number).node.node, + &SYNC_NODE_NAME(interfaces_Table).node.node +}; + +const struct snmp_tree_node snmp_mib2_interface_root = SNMP_CREATE_TREE_NODE(2, interface_nodes); + +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_ip.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_ip.c new file mode 100644 index 0000000000..4f05180a39 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_ip.c @@ -0,0 +1,743 @@ +/** + * @file + * Management Information Base II (RFC1213) IP objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/stats.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/etharp.h" + +#if LWIP_SNMP && SNMP_LWIP_MIB2 + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + +#if LWIP_IPV4 +/* --- ip .1.3.6.1.2.1.4 ----------------------------------------------------- */ + +static s16_t +ip_get_value(struct snmp_node_instance* instance, void* value) +{ + s32_t* sint_ptr = (s32_t*)value; + u32_t* uint_ptr = (u32_t*)value; + + switch (instance->node->oid) { + case 1: /* ipForwarding */ +#if IP_FORWARD + /* forwarding */ + *sint_ptr = 1; +#else + /* not-forwarding */ + *sint_ptr = 2; +#endif + return sizeof(*sint_ptr); + case 2: /* ipDefaultTTL */ + *sint_ptr = IP_DEFAULT_TTL; + return sizeof(*sint_ptr); + case 3: /* ipInReceives */ + *uint_ptr = STATS_GET(mib2.ipinreceives); + return sizeof(*uint_ptr); + case 4: /* ipInHdrErrors */ + *uint_ptr = STATS_GET(mib2.ipinhdrerrors); + return sizeof(*uint_ptr); + case 5: /* ipInAddrErrors */ + *uint_ptr = STATS_GET(mib2.ipinaddrerrors); + return sizeof(*uint_ptr); + case 6: /* ipForwDatagrams */ + *uint_ptr = STATS_GET(mib2.ipforwdatagrams); + return sizeof(*uint_ptr); + case 7: /* ipInUnknownProtos */ + *uint_ptr = STATS_GET(mib2.ipinunknownprotos); + return sizeof(*uint_ptr); + case 8: /* ipInDiscards */ + *uint_ptr = STATS_GET(mib2.ipindiscards); + return sizeof(*uint_ptr); + case 9: /* ipInDelivers */ + *uint_ptr = STATS_GET(mib2.ipindelivers); + return sizeof(*uint_ptr); + case 10: /* ipOutRequests */ + *uint_ptr = STATS_GET(mib2.ipoutrequests); + return sizeof(*uint_ptr); + case 11: /* ipOutDiscards */ + *uint_ptr = STATS_GET(mib2.ipoutdiscards); + return sizeof(*uint_ptr); + case 12: /* ipOutNoRoutes */ + *uint_ptr = STATS_GET(mib2.ipoutnoroutes); + return sizeof(*uint_ptr); + case 13: /* ipReasmTimeout */ +#if IP_REASSEMBLY + *sint_ptr = IP_REASS_MAXAGE; +#else + *sint_ptr = 0; +#endif + return sizeof(*sint_ptr); + case 14: /* ipReasmReqds */ + *uint_ptr = STATS_GET(mib2.ipreasmreqds); + return sizeof(*uint_ptr); + case 15: /* ipReasmOKs */ + *uint_ptr = STATS_GET(mib2.ipreasmoks); + return sizeof(*uint_ptr); + case 16: /* ipReasmFails */ + *uint_ptr = STATS_GET(mib2.ipreasmfails); + return sizeof(*uint_ptr); + case 17: /* ipFragOKs */ + *uint_ptr = STATS_GET(mib2.ipfragoks); + return sizeof(*uint_ptr); + case 18: /* ipFragFails */ + *uint_ptr = STATS_GET(mib2.ipfragfails); + return sizeof(*uint_ptr); + case 19: /* ipFragCreates */ + *uint_ptr = STATS_GET(mib2.ipfragcreates); + return sizeof(*uint_ptr); + case 23: /* ipRoutingDiscards: not supported -> always 0 */ + *uint_ptr = 0; + return sizeof(*uint_ptr); + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); + break; + } + + return 0; +} + +/** + * Test ip object value before setting. + * + * @param instance node instance + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value from. + * + * @note we allow set if the value matches the hardwired value, + * otherwise return badvalue. + */ +static snmp_err_t +ip_set_test(struct snmp_node_instance* instance, u16_t len, void *value) +{ + snmp_err_t ret = SNMP_ERR_WRONGVALUE; + s32_t *sint_ptr = (s32_t*)value; + + LWIP_UNUSED_ARG(len); + switch (instance->node->oid) { + case 1: /* ipForwarding */ +#if IP_FORWARD + /* forwarding */ + if (*sint_ptr == 1) +#else + /* not-forwarding */ + if (*sint_ptr == 2) +#endif + { + ret = SNMP_ERR_NOERROR; + } + break; + case 2: /* ipDefaultTTL */ + if (*sint_ptr == IP_DEFAULT_TTL) { + ret = SNMP_ERR_NOERROR; + } + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %"S32_F"\n", instance->node->oid)); + break; + } + + return ret; +} + +static snmp_err_t +ip_set_value(struct snmp_node_instance* instance, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(instance); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(value); + /* nothing to do here because in set_test we only accept values being the same as our own stored value -> no need to store anything */ + return SNMP_ERR_NOERROR; +} + +/* --- ipAddrTable --- */ + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range ip_AddrTable_oid_ranges[] = { + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff } /* IP D */ +}; + +static snmp_err_t +ip_AddrTable_get_cell_value_core(struct netif *netif, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) +{ + LWIP_UNUSED_ARG(value_len); + + switch (*column) { + case 1: /* ipAdEntAddr */ + value->u32 = netif_ip4_addr(netif)->addr; + break; + case 2: /* ipAdEntIfIndex */ + value->u32 = netif_to_num(netif); + break; + case 3: /* ipAdEntNetMask */ + value->u32 = netif_ip4_netmask(netif)->addr; + break; + case 4: /* ipAdEntBcastAddr */ + /* lwIP oddity, there's no broadcast + address in the netif we can rely on */ + value->u32 = IPADDR_BROADCAST & 1; + break; + case 5: /* ipAdEntReasmMaxSize */ +#if IP_REASSEMBLY + /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, + * but only if receiving one fragmented packet at a time. + * The current solution is to calculate for 2 simultaneous packets... + */ + value->u32 = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * + (PBUF_POOL_BUFSIZE - PBUF_LINK_ENCAPSULATION_HLEN - PBUF_LINK_HLEN - IP_HLEN))); +#else + /** @todo returning MTU would be a bad thing and + returning a wild guess like '576' isn't good either */ + value->u32 = 0; +#endif + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +ip_AddrTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip4_addr_t ip; + struct netif *netif; + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, ip_AddrTable_oid_ranges, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get IP from incoming OID */ + snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */ + + /* find netif with requested ip */ + netif = netif_list; + while (netif != NULL) { + if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) { + /* fill in object properties */ + return ip_AddrTable_get_cell_value_core(netif, column, value, value_len); + } + + netif = netif->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct netif *netif; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)]; + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + netif = netif_list; + while (netif != NULL) { + u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)]; + snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]); + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif); + + netif = netif->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len); + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +/* --- ipRouteTable --- */ + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range ip_RouteTable_oid_ranges[] = { + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff }, /* IP D */ +}; + +static snmp_err_t +ip_RouteTable_get_cell_value_core(struct netif *netif, u8_t default_route, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) +{ + switch (*column) { + case 1: /* ipRouteDest */ + if (default_route) { + /* default rte has 0.0.0.0 dest */ + value->u32 = IP4_ADDR_ANY4->addr; + } else { + /* netifs have netaddress dest */ + ip4_addr_t tmp; + ip4_addr_get_network(&tmp, netif_ip4_addr(netif), netif_ip4_netmask(netif)); + value->u32 = tmp.addr; + } + break; + case 2: /* ipRouteIfIndex */ + value->u32 = netif_to_num(netif); + break; + case 3: /* ipRouteMetric1 */ + if (default_route) { + value->s32 = 1; /* default */ + } else { + value->s32 = 0; /* normal */ + } + break; + case 4: /* ipRouteMetric2 */ + case 5: /* ipRouteMetric3 */ + case 6: /* ipRouteMetric4 */ + value->s32 = -1; /* none */ + break; + case 7: /* ipRouteNextHop */ + if (default_route) { + /* default rte: gateway */ + value->u32 = netif_ip4_gw(netif)->addr; + } else { + /* other rtes: netif ip_addr */ + value->u32 = netif_ip4_addr(netif)->addr; + } + break; + case 8: /* ipRouteType */ + if (default_route) { + /* default rte is indirect */ + value->u32 = 4; /* indirect */ + } else { + /* other rtes are direct */ + value->u32 = 3; /* direct */ + } + break; + case 9: /* ipRouteProto */ + /* locally defined routes */ + value->u32 = 2; /* local */ + break; + case 10: /* ipRouteAge */ + /* @todo (sysuptime - timestamp last change) / 100 */ + value->u32 = 0; + break; + case 11: /* ipRouteMask */ + if (default_route) { + /* default rte use 0.0.0.0 mask */ + value->u32 = IP4_ADDR_ANY4->addr; + } else { + /* other rtes use netmask */ + value->u32 = netif_ip4_netmask(netif)->addr; + } + break; + case 12: /* ipRouteMetric5 */ + value->s32 = -1; /* none */ + break; + case 13: /* ipRouteInfo */ + value->const_ptr = snmp_zero_dot_zero.id; + *value_len = snmp_zero_dot_zero.len * sizeof(u32_t); + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +ip_RouteTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip4_addr_t test_ip; + struct netif *netif; + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, ip_RouteTable_oid_ranges, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get IP and port from incoming OID */ + snmp_oid_to_ip4(&row_oid[0], &test_ip); /* we know it succeeds because of oid_in_range check above */ + + /* default route is on default netif */ + if (ip4_addr_isany_val(test_ip) && (netif_default != NULL)) { + /* fill in object properties */ + return ip_RouteTable_get_cell_value_core(netif_default, 1, column, value, value_len); + } + + /* find netif with requested route */ + netif = netif_list; + while (netif != NULL) { + ip4_addr_t dst; + ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif)); + + if (ip4_addr_cmp(&dst, &test_ip)) { + /* fill in object properties */ + return ip_RouteTable_get_cell_value_core(netif, 0, column, value, value_len); + } + + netif = netif->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +ip_RouteTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct netif *netif; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)]; + u32_t test_oid[LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)]; + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges)); + + /* check default route */ + if (netif_default != NULL) { + snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[0]); + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif_default); + } + + /* iterate over all possible OIDs to find the next one */ + netif = netif_list; + while (netif != NULL) { + ip4_addr_t dst; + ip4_addr_get_network(&dst, netif_ip4_addr(netif), netif_ip4_netmask(netif)); + + /* check generated OID: is it a candidate for the next one? */ + if (!ip4_addr_isany_val(dst)) { + snmp_ip4_to_oid(&dst, &test_oid[0]); + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_RouteTable_oid_ranges), netif); + } + + netif = netif->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + ip4_addr_t dst; + snmp_oid_to_ip4(&result_temp[0], &dst); + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return ip_RouteTable_get_cell_value_core((struct netif*)state.reference, ip4_addr_isany_val(dst), column, value, value_len); + } else { + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; + } +} + +#if LWIP_ARP && LWIP_IPV4 +/* --- ipNetToMediaTable --- */ + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range ip_NetToMediaTable_oid_ranges[] = { + { 1, 0xff }, /* IfIndex */ + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff } /* IP D */ +}; + +static snmp_err_t +ip_NetToMediaTable_get_cell_value_core(u8_t arp_table_index, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) +{ + ip4_addr_t *ip; + struct netif *netif; + struct eth_addr *ethaddr; + + etharp_get_entry(arp_table_index, &ip, &netif, ðaddr); + + /* value */ + switch (*column) { + case 1: /* atIfIndex / ipNetToMediaIfIndex */ + value->u32 = netif_to_num(netif); + break; + case 2: /* atPhysAddress / ipNetToMediaPhysAddress */ + value->ptr = ethaddr; + *value_len = sizeof(*ethaddr); + break; + case 3: /* atNetAddress / ipNetToMediaNetAddress */ + value->u32 = ip->addr; + break; + case 4: /* ipNetToMediaType */ + value->u32 = 3; /* dynamic*/ + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +ip_NetToMediaTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip4_addr_t ip_in; + u8_t netif_index; + u8_t i; + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, ip_NetToMediaTable_oid_ranges, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get IP from incoming OID */ + netif_index = (u8_t)row_oid[0]; + snmp_oid_to_ip4(&row_oid[1], &ip_in); /* we know it succeeds because of oid_in_range check above */ + + /* find requested entry */ + for (i=0; iid, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + for (i=0; i + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_scalar.h" + +#if LWIP_SNMP && SNMP_LWIP_MIB2 + +#define MIB2_AUTH_TRAPS_ENABLED 1 +#define MIB2_AUTH_TRAPS_DISABLED 2 + +/* --- snmp .1.3.6.1.2.1.11 ----------------------------------------------------- */ +static s16_t +snmp_get_value(const struct snmp_scalar_array_node_def *node, void *value) +{ + u32_t *uint_ptr = (u32_t*)value; + switch (node->oid) { + case 1: /* snmpInPkts */ + *uint_ptr = snmp_stats.inpkts; + break; + case 2: /* snmpOutPkts */ + *uint_ptr = snmp_stats.outpkts; + break; + case 3: /* snmpInBadVersions */ + *uint_ptr = snmp_stats.inbadversions; + break; + case 4: /* snmpInBadCommunityNames */ + *uint_ptr = snmp_stats.inbadcommunitynames; + break; + case 5: /* snmpInBadCommunityUses */ + *uint_ptr = snmp_stats.inbadcommunityuses; + break; + case 6: /* snmpInASNParseErrs */ + *uint_ptr = snmp_stats.inasnparseerrs; + break; + case 8: /* snmpInTooBigs */ + *uint_ptr = snmp_stats.intoobigs; + break; + case 9: /* snmpInNoSuchNames */ + *uint_ptr = snmp_stats.innosuchnames; + break; + case 10: /* snmpInBadValues */ + *uint_ptr = snmp_stats.inbadvalues; + break; + case 11: /* snmpInReadOnlys */ + *uint_ptr = snmp_stats.inreadonlys; + break; + case 12: /* snmpInGenErrs */ + *uint_ptr = snmp_stats.ingenerrs; + break; + case 13: /* snmpInTotalReqVars */ + *uint_ptr = snmp_stats.intotalreqvars; + break; + case 14: /* snmpInTotalSetVars */ + *uint_ptr = snmp_stats.intotalsetvars; + break; + case 15: /* snmpInGetRequests */ + *uint_ptr = snmp_stats.ingetrequests; + break; + case 16: /* snmpInGetNexts */ + *uint_ptr = snmp_stats.ingetnexts; + break; + case 17: /* snmpInSetRequests */ + *uint_ptr = snmp_stats.insetrequests; + break; + case 18: /* snmpInGetResponses */ + *uint_ptr = snmp_stats.ingetresponses; + break; + case 19: /* snmpInTraps */ + *uint_ptr = snmp_stats.intraps; + break; + case 20: /* snmpOutTooBigs */ + *uint_ptr = snmp_stats.outtoobigs; + break; + case 21: /* snmpOutNoSuchNames */ + *uint_ptr = snmp_stats.outnosuchnames; + break; + case 22: /* snmpOutBadValues */ + *uint_ptr = snmp_stats.outbadvalues; + break; + case 24: /* snmpOutGenErrs */ + *uint_ptr = snmp_stats.outgenerrs; + break; + case 25: /* snmpOutGetRequests */ + *uint_ptr = snmp_stats.outgetrequests; + break; + case 26: /* snmpOutGetNexts */ + *uint_ptr = snmp_stats.outgetnexts; + break; + case 27: /* snmpOutSetRequests */ + *uint_ptr = snmp_stats.outsetrequests; + break; + case 28: /* snmpOutGetResponses */ + *uint_ptr = snmp_stats.outgetresponses; + break; + case 29: /* snmpOutTraps */ + *uint_ptr = snmp_stats.outtraps; + break; + case 30: /* snmpEnableAuthenTraps */ + if (snmp_get_auth_traps_enabled() == SNMP_AUTH_TRAPS_DISABLED) { + *uint_ptr = MIB2_AUTH_TRAPS_DISABLED; + } else { + *uint_ptr = MIB2_AUTH_TRAPS_ENABLED; + } + break; + case 31: /* snmpSilentDrops */ + *uint_ptr = 0; /* not supported */ + break; + case 32: /* snmpProxyDrops */ + *uint_ptr = 0; /* not supported */ + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %"S32_F"\n", node->oid)); + return 0; + } + + return sizeof(*uint_ptr); +} + +static snmp_err_t +snmp_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) +{ + snmp_err_t ret = SNMP_ERR_WRONGVALUE; + LWIP_UNUSED_ARG(len); + + if (node->oid == 30) { + /* snmpEnableAuthenTraps */ + s32_t *sint_ptr = (s32_t*)value; + + /* we should have writable non-volatile mem here */ + if ((*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) || (*sint_ptr == MIB2_AUTH_TRAPS_ENABLED)) { + ret = SNMP_ERR_NOERROR; + } + } + return ret; +} + +static snmp_err_t +snmp_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) +{ + LWIP_UNUSED_ARG(len); + + if (node->oid == 30) { + /* snmpEnableAuthenTraps */ + s32_t *sint_ptr = (s32_t*)value; + if (*sint_ptr == MIB2_AUTH_TRAPS_DISABLED) { + snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED); + } else { + snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_ENABLED); + } + } + + return SNMP_ERR_NOERROR; +} + +/* the following nodes access variables in SNMP stack (snmp_stats) from SNMP worker thread -> OK, no sync needed */ +static const struct snmp_scalar_array_node_def snmp_nodes[] = { + { 1, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInPkts */ + { 2, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutPkts */ + { 3, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadVersions */ + { 4, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityNames */ + { 5, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadCommunityUses */ + { 6, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInASNParseErrs */ + { 8, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTooBigs */ + { 9, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInNoSuchNames */ + {10, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInBadValues */ + {11, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInReadOnlys */ + {12, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGenErrs */ + {13, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalReqVars */ + {14, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTotalSetVars */ + {15, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetRequests */ + {16, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetNexts */ + {17, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInSetRequests */ + {18, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInGetResponses */ + {19, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpInTraps */ + {20, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTooBigs */ + {21, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutNoSuchNames */ + {22, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutBadValues */ + {24, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGenErrs */ + {25, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetRequests */ + {26, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetNexts */ + {27, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutSetRequests */ + {28, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutGetResponses */ + {29, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpOutTraps */ + {30, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* snmpEnableAuthenTraps */ + {31, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY}, /* snmpSilentDrops */ + {32, SNMP_ASN1_TYPE_COUNTER, SNMP_NODE_INSTANCE_READ_ONLY} /* snmpProxyDrops */ +}; + +const struct snmp_scalar_array_node snmp_mib2_snmp_root = SNMP_SCALAR_CREATE_ARRAY_NODE(11, snmp_nodes, snmp_get_value, snmp_set_test, snmp_set_value); + +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_system.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_system.c new file mode 100644 index 0000000000..90e57805d2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_system.c @@ -0,0 +1,377 @@ +/** + * @file + * Management Information Base II (RFC1213) SYSTEM objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/sys.h" + +#include + +#if LWIP_SNMP && SNMP_LWIP_MIB2 + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + +/* --- system .1.3.6.1.2.1.1 ----------------------------------------------------- */ + +/** mib-2.system.sysDescr */ +static const u8_t sysdescr_default[] = SNMP_LWIP_MIB2_SYSDESC; +static const u8_t* sysdescr = sysdescr_default; +static const u16_t* sysdescr_len = NULL; /* use strlen for determining len */ + +/** mib-2.system.sysContact */ +static const u8_t syscontact_default[] = SNMP_LWIP_MIB2_SYSCONTACT; +static const u8_t* syscontact = syscontact_default; +static const u16_t* syscontact_len = NULL; /* use strlen for determining len */ +static u8_t* syscontact_wr = NULL; /* if writable, points to the same buffer as syscontact (required for correct constness) */ +static u16_t* syscontact_wr_len = NULL; /* if writable, points to the same buffer as syscontact_len (required for correct constness) */ +static u16_t syscontact_bufsize = 0; /* 0=not writable */ + +/** mib-2.system.sysName */ +static const u8_t sysname_default[] = SNMP_LWIP_MIB2_SYSNAME; +static const u8_t* sysname = sysname_default; +static const u16_t* sysname_len = NULL; /* use strlen for determining len */ +static u8_t* sysname_wr = NULL; /* if writable, points to the same buffer as sysname (required for correct constness) */ +static u16_t* sysname_wr_len = NULL; /* if writable, points to the same buffer as sysname_len (required for correct constness) */ +static u16_t sysname_bufsize = 0; /* 0=not writable */ + +/** mib-2.system.sysLocation */ +static const u8_t syslocation_default[] = SNMP_LWIP_MIB2_SYSLOCATION; +static const u8_t* syslocation = syslocation_default; +static const u16_t* syslocation_len = NULL; /* use strlen for determining len */ +static u8_t* syslocation_wr = NULL; /* if writable, points to the same buffer as syslocation (required for correct constness) */ +static u16_t* syslocation_wr_len = NULL; /* if writable, points to the same buffer as syslocation_len (required for correct constness) */ +static u16_t syslocation_bufsize = 0; /* 0=not writable */ + +/** + * @ingroup snmp_mib2 + * Initializes sysDescr pointers. + * + * @param str if non-NULL then copy str pointer + * @param len points to string length, excluding zero terminator + */ +void +snmp_mib2_set_sysdescr(const u8_t *str, const u16_t *len) +{ + if (str != NULL) { + sysdescr = str; + sysdescr_len = len; + } +} + +/** + * @ingroup snmp_mib2 + * Initializes sysContact pointers + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator. + * if set to NULL it is assumed that ocstr is NULL-terminated. + * @param bufsize size of the buffer in bytes. + * (this is required because the buffer can be overwritten by snmp-set) + * if ocstrlen is NULL buffer needs space for terminating 0 byte. + * otherwise complete buffer is used for string. + * if bufsize is set to 0, the value is regarded as read-only. + */ +void +snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) +{ + if (ocstr != NULL) { + syscontact = ocstr; + syscontact_wr = ocstr; + syscontact_len = ocstrlen; + syscontact_wr_len = ocstrlen; + syscontact_bufsize = bufsize; + } +} + +/** + * @ingroup snmp_mib2 + * see \ref snmp_mib2_set_syscontact but set pointer to readonly memory + */ +void +snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen) +{ + if (ocstr != NULL) { + syscontact = ocstr; + syscontact_len = ocstrlen; + syscontact_wr = NULL; + syscontact_wr_len = NULL; + syscontact_bufsize = 0; + } +} + + +/** + * @ingroup snmp_mib2 + * Initializes sysName pointers + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator. + * if set to NULL it is assumed that ocstr is NULL-terminated. + * @param bufsize size of the buffer in bytes. + * (this is required because the buffer can be overwritten by snmp-set) + * if ocstrlen is NULL buffer needs space for terminating 0 byte. + * otherwise complete buffer is used for string. + * if bufsize is set to 0, the value is regarded as read-only. + */ +void +snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) +{ + if (ocstr != NULL) { + sysname = ocstr; + sysname_wr = ocstr; + sysname_len = ocstrlen; + sysname_wr_len = ocstrlen; + sysname_bufsize = bufsize; + } +} + +/** + * @ingroup snmp_mib2 + * see \ref snmp_mib2_set_sysname but set pointer to readonly memory + */ +void +snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen) +{ + if (ocstr != NULL) { + sysname = ocstr; + sysname_len = ocstrlen; + sysname_wr = NULL; + sysname_wr_len = NULL; + sysname_bufsize = 0; + } +} + +/** + * @ingroup snmp_mib2 + * Initializes sysLocation pointers + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator. + * if set to NULL it is assumed that ocstr is NULL-terminated. + * @param bufsize size of the buffer in bytes. + * (this is required because the buffer can be overwritten by snmp-set) + * if ocstrlen is NULL buffer needs space for terminating 0 byte. + * otherwise complete buffer is used for string. + * if bufsize is set to 0, the value is regarded as read-only. + */ +void +snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize) +{ + if (ocstr != NULL) { + syslocation = ocstr; + syslocation_wr = ocstr; + syslocation_len = ocstrlen; + syslocation_wr_len = ocstrlen; + syslocation_bufsize = bufsize; + } +} + +/** + * @ingroup snmp_mib2 + * see \ref snmp_mib2_set_syslocation but set pointer to readonly memory + */ +void +snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen) +{ + if (ocstr != NULL) { + syslocation = ocstr; + syslocation_len = ocstrlen; + syslocation_wr = NULL; + syslocation_wr_len = NULL; + syslocation_bufsize = 0; + } +} + + +static s16_t +system_get_value(const struct snmp_scalar_array_node_def *node, void *value) +{ + const u8_t* var = NULL; + const s16_t* var_len; + u16_t result; + + switch (node->oid) { + case 1: /* sysDescr */ + var = sysdescr; + var_len = (const s16_t*)sysdescr_len; + break; + case 2: /* sysObjectID */ + { + const struct snmp_obj_id* dev_enterprise_oid = snmp_get_device_enterprise_oid(); + MEMCPY(value, dev_enterprise_oid->id, dev_enterprise_oid->len * sizeof(u32_t)); + return dev_enterprise_oid->len * sizeof(u32_t); + } + case 3: /* sysUpTime */ + MIB2_COPY_SYSUPTIME_TO((u32_t*)value); + return sizeof(u32_t); + case 4: /* sysContact */ + var = syscontact; + var_len = (const s16_t*)syscontact_len; + break; + case 5: /* sysName */ + var = sysname; + var_len = (const s16_t*)sysname_len; + break; + case 6: /* sysLocation */ + var = syslocation; + var_len = (const s16_t*)syslocation_len; + break; + case 7: /* sysServices */ + *(s32_t*)value = SNMP_SYSSERVICES; + return sizeof(s32_t); + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %"S32_F"\n", node->oid)); + return 0; + } + + /* handle string values (OID 1,4,5 and 6) */ + LWIP_ASSERT("", (value != NULL)); + if (var_len == NULL) { + result = (s16_t)strlen((const char*)var); + } else { + result = *var_len; + } + MEMCPY(value, var, result); + return result; +} + +static snmp_err_t +system_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) +{ + snmp_err_t ret = SNMP_ERR_WRONGVALUE; + const u16_t* var_bufsize = NULL; + const u16_t* var_wr_len; + + LWIP_UNUSED_ARG(value); + + switch (node->oid) { + case 4: /* sysContact */ + var_bufsize = &syscontact_bufsize; + var_wr_len = syscontact_wr_len; + break; + case 5: /* sysName */ + var_bufsize = &sysname_bufsize; + var_wr_len = sysname_wr_len; + break; + case 6: /* sysLocation */ + var_bufsize = &syslocation_bufsize; + var_wr_len = syslocation_wr_len; + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %"S32_F"\n", node->oid)); + return ret; + } + + /* check if value is writable at all */ + if (*var_bufsize > 0) { + if (var_wr_len == NULL) { + /* we have to take the terminating 0 into account */ + if (len < *var_bufsize) { + ret = SNMP_ERR_NOERROR; + } + } else { + if (len <= *var_bufsize) { + ret = SNMP_ERR_NOERROR; + } + } + } else { + ret = SNMP_ERR_NOTWRITABLE; + } + + return ret; +} + +static snmp_err_t +system_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value) +{ + u8_t* var_wr = NULL; + u16_t* var_wr_len; + + switch (node->oid) { + case 4: /* sysContact */ + var_wr = syscontact_wr; + var_wr_len = syscontact_wr_len; + break; + case 5: /* sysName */ + var_wr = sysname_wr; + var_wr_len = sysname_wr_len; + break; + case 6: /* sysLocation */ + var_wr = syslocation_wr; + var_wr_len = syslocation_wr_len; + break; + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %"S32_F"\n", node->oid)); + return SNMP_ERR_GENERROR; + } + + /* no need to check size of target buffer, this was already done in set_test method */ + LWIP_ASSERT("", var_wr != NULL); + MEMCPY(var_wr, value, len); + + if (var_wr_len == NULL) { + /* add terminating 0 */ + var_wr[len] = 0; + } else { + *var_wr_len = len; + } + + return SNMP_ERR_NOERROR; +} + +static const struct snmp_scalar_array_node_def system_nodes[] = { + {1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysDescr */ + {2, SNMP_ASN1_TYPE_OBJECT_ID, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysObjectID */ + {3, SNMP_ASN1_TYPE_TIMETICKS, SNMP_NODE_INSTANCE_READ_ONLY}, /* sysUpTime */ + {4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysContact */ + {5, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysName */ + {6, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_WRITE}, /* sysLocation */ + {7, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY} /* sysServices */ +}; + +const struct snmp_scalar_array_node snmp_mib2_system_node = SNMP_SCALAR_CREATE_ARRAY_NODE(1, system_nodes, system_get_value, system_set_test, system_set_value); + +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_tcp.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_tcp.c new file mode 100644 index 0000000000..21f6965662 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_tcp.c @@ -0,0 +1,594 @@ +/** + * @file + * Management Information Base II (RFC1213) TCP objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" + +#include + +#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + +/* --- tcp .1.3.6.1.2.1.6 ----------------------------------------------------- */ + +static s16_t +tcp_get_value(struct snmp_node_instance* instance, void* value) +{ + u32_t *uint_ptr = (u32_t*)value; + s32_t *sint_ptr = (s32_t*)value; + + switch (instance->node->oid) { + case 1: /* tcpRtoAlgorithm, vanj(4) */ + *sint_ptr = 4; + return sizeof(*sint_ptr); + case 2: /* tcpRtoMin */ + /* @todo not the actual value, a guess, + needs to be calculated */ + *sint_ptr = 1000; + return sizeof(*sint_ptr); + case 3: /* tcpRtoMax */ + /* @todo not the actual value, a guess, + needs to be calculated */ + *sint_ptr = 60000; + return sizeof(*sint_ptr); + case 4: /* tcpMaxConn */ + *sint_ptr = MEMP_NUM_TCP_PCB; + return sizeof(*sint_ptr); + case 5: /* tcpActiveOpens */ + *uint_ptr = STATS_GET(mib2.tcpactiveopens); + return sizeof(*uint_ptr); + case 6: /* tcpPassiveOpens */ + *uint_ptr = STATS_GET(mib2.tcppassiveopens); + return sizeof(*uint_ptr); + case 7: /* tcpAttemptFails */ + *uint_ptr = STATS_GET(mib2.tcpattemptfails); + return sizeof(*uint_ptr); + case 8: /* tcpEstabResets */ + *uint_ptr = STATS_GET(mib2.tcpestabresets); + return sizeof(*uint_ptr); + case 9: /* tcpCurrEstab */ + { + u16_t tcpcurrestab = 0; + struct tcp_pcb *pcb = tcp_active_pcbs; + while (pcb != NULL) { + if ((pcb->state == ESTABLISHED) || + (pcb->state == CLOSE_WAIT)) { + tcpcurrestab++; + } + pcb = pcb->next; + } + *uint_ptr = tcpcurrestab; + } + return sizeof(*uint_ptr); + case 10: /* tcpInSegs */ + *uint_ptr = STATS_GET(mib2.tcpinsegs); + return sizeof(*uint_ptr); + case 11: /* tcpOutSegs */ + *uint_ptr = STATS_GET(mib2.tcpoutsegs); + return sizeof(*uint_ptr); + case 12: /* tcpRetransSegs */ + *uint_ptr = STATS_GET(mib2.tcpretranssegs); + return sizeof(*uint_ptr); + case 14: /* tcpInErrs */ + *uint_ptr = STATS_GET(mib2.tcpinerrs); + return sizeof(*uint_ptr); + case 15: /* tcpOutRsts */ + *uint_ptr = STATS_GET(mib2.tcpoutrsts); + return sizeof(*uint_ptr); + case 17: /* tcpHCInSegs */ + memset(value, 0, 2*sizeof(u32_t)); /* not supported */ + return 2*sizeof(u32_t); + case 18: /* tcpHCOutSegs */ + memset(value, 0, 2*sizeof(u32_t)); /* not supported */ + return 2*sizeof(u32_t); + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); + break; + } + + return 0; +} + +/* --- tcpConnTable --- */ + +#if LWIP_IPV4 + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range tcp_ConnTable_oid_ranges[] = { + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff }, /* IP D */ + { 0, 0xffff }, /* Port */ + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff }, /* IP D */ + { 0, 0xffff } /* Port */ +}; + +static snmp_err_t +tcp_ConnTable_get_cell_value_core(struct tcp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) +{ + LWIP_UNUSED_ARG(value_len); + + /* value */ + switch (*column) { + case 1: /* tcpConnState */ + value->u32 = pcb->state + 1; + break; + case 2: /* tcpConnLocalAddress */ + value->u32 = ip_2_ip4(&pcb->local_ip)->addr; + break; + case 3: /* tcpConnLocalPort */ + value->u32 = pcb->local_port; + break; + case 4: /* tcpConnRemAddress */ + if (pcb->state == LISTEN) { + value->u32 = IP4_ADDR_ANY4->addr; + } else { + value->u32 = ip_2_ip4(&pcb->remote_ip)->addr; + } + break; + case 5: /* tcpConnRemPort */ + if (pcb->state == LISTEN) { + value->u32 = 0; + } else { + value->u32 = pcb->remote_port; + } + break; + default: + LWIP_ASSERT("invalid id", 0); + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +tcp_ConnTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + u8_t i; + ip4_addr_t local_ip; + ip4_addr_t remote_ip; + u16_t local_port; + u16_t remote_port; + struct tcp_pcb *pcb; + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, tcp_ConnTable_oid_ranges, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get IPs and ports from incoming OID */ + snmp_oid_to_ip4(&row_oid[0], &local_ip); /* we know it succeeds because of oid_in_range check above */ + local_port = (u16_t)row_oid[4]; + snmp_oid_to_ip4(&row_oid[5], &remote_ip); /* we know it succeeds because of oid_in_range check above */ + remote_port = (u16_t)row_oid[9]; + + /* find tcp_pcb with requested ips and ports */ + for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { + pcb = *tcp_pcb_lists[i]; + + while (pcb != NULL) { + /* do local IP and local port match? */ + if (IP_IS_V4_VAL(pcb->local_ip) && + ip4_addr_cmp(&local_ip, ip_2_ip4(&pcb->local_ip)) && (local_port == pcb->local_port)) { + + /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */ + if (pcb->state == LISTEN) { + if (ip4_addr_cmp(&remote_ip, IP4_ADDR_ANY4) && (remote_port == 0)) { + /* fill in object properties */ + return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); + } + } else { + if (IP_IS_V4_VAL(pcb->remote_ip) && + ip4_addr_cmp(&remote_ip, ip_2_ip4(&pcb->remote_ip)) && (remote_port == pcb->remote_port)) { + /* fill in object properties */ + return tcp_ConnTable_get_cell_value_core(pcb, column, value, value_len); + } + } + } + + pcb = pcb->next; + } + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + u8_t i; + struct tcp_pcb *pcb; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)]; + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { + pcb = *tcp_pcb_lists[i]; + while (pcb != NULL) { + u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)]; + + if (IP_IS_V4_VAL(pcb->local_ip)) { + snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]); + test_oid[4] = pcb->local_port; + + /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */ + if (pcb->state == LISTEN) { + snmp_ip4_to_oid(IP4_ADDR_ANY4, &test_oid[5]); + test_oid[9] = 0; + } else { + if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */ + continue; + } + snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]); + test_oid[9] = pcb->remote_port; + } + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb); + } + + pcb = pcb->next; + } + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len); + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +#endif /* LWIP_IPV4 */ + +/* --- tcpConnectionTable --- */ + +static snmp_err_t +tcp_ConnectionTable_get_cell_value_core(const u32_t* column, struct tcp_pcb *pcb, union snmp_variant_value* value) +{ + /* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */ + switch (*column) { + case 7: /* tcpConnectionState */ + value->u32 = pcb->state + 1; + break; + case 8: /* tcpConnectionProcess */ + value->u32 = 0; /* not supported */ + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +tcp_ConnectionTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip_addr_t local_ip, remote_ip; + u16_t local_port, remote_port; + struct tcp_pcb *pcb; + u8_t idx = 0; + u8_t i; + struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; + + LWIP_UNUSED_ARG(value_len); + + /* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */ + idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); + if (idx == 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */ + idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port); + if (idx == 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* find tcp_pcb with requested ip and port*/ + for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) { + pcb = *tcp_pcb_nonlisten_lists[i]; + + while (pcb != NULL) { + if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + (local_port == pcb->local_port) && + ip_addr_cmp(&remote_ip, &pcb->remote_ip) && + (remote_port == pcb->remote_port)) { + /* fill in object properties */ + return tcp_ConnectionTable_get_cell_value_core(column, pcb, value); + } + pcb = pcb->next; + } + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct tcp_pcb *pcb; + struct snmp_next_oid_state state; + /* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress + 1x tcpConnectionLocalPort + * 1x tcpConnectionRemAddressType + 1x OID len + 16x tcpConnectionRemAddress + 1x tcpConnectionRemPort */ + u32_t result_temp[38]; + u8_t i; + struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; + + LWIP_UNUSED_ARG(value_len); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); + + /* iterate over all possible OIDs to find the next one */ + for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) { + pcb = *tcp_pcb_nonlisten_lists[i]; + + while (pcb != NULL) { + u8_t idx = 0; + u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; + + /* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */ + idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); + + /* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */ + idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]); + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, idx, pcb); + + pcb = pcb->next; + } + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value); + } else { + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; + } +} + +/* --- tcpListenerTable --- */ + +static snmp_err_t +tcp_ListenerTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value) +{ + /* all items except tcpListenerProcess are declared as not-accessible */ + switch (*column) { + case 4: /* tcpListenerProcess */ + value->u32 = 0; /* not supported */ + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +tcp_ListenerTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip_addr_t local_ip; + u16_t local_port; + struct tcp_pcb_listen *pcb; + u8_t idx = 0; + + LWIP_UNUSED_ARG(value_len); + + /* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */ + idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); + if (idx == 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* find tcp_pcb with requested ip and port*/ + pcb = tcp_listen_pcbs.listen_pcbs; + while (pcb != NULL) { + if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + (local_port == pcb->local_port)) { + /* fill in object properties */ + return tcp_ListenerTable_get_cell_value_core(column, value); + } + pcb = pcb->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +tcp_ListenerTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct tcp_pcb_listen *pcb; + struct snmp_next_oid_state state; + /* 1x tcpListenerLocalAddressType + 1x OID len + 16x tcpListenerLocalAddress + 1x tcpListenerLocalPort */ + u32_t result_temp[19]; + + LWIP_UNUSED_ARG(value_len); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); + + /* iterate over all possible OIDs to find the next one */ + pcb = tcp_listen_pcbs.listen_pcbs; + while (pcb != NULL) { + u8_t idx = 0; + u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; + + /* tcpListenerLocalAddressType + tcpListenerLocalAddress + tcpListenerLocalPort */ + idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, idx, NULL); + + pcb = pcb->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return tcp_ListenerTable_get_cell_value_core(column, value); + } else { + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; + } +} + +static const struct snmp_scalar_node tcp_RtoAlgorithm = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); +static const struct snmp_scalar_node tcp_RtoMin = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); +static const struct snmp_scalar_node tcp_RtoMax = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); +static const struct snmp_scalar_node tcp_MaxConn = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_INTEGER, tcp_get_value); +static const struct snmp_scalar_node tcp_ActiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(5, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_PassiveOpens = SNMP_SCALAR_CREATE_NODE_READONLY(6, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_AttemptFails = SNMP_SCALAR_CREATE_NODE_READONLY(7, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_EstabResets = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_CurrEstab = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_GAUGE, tcp_get_value); +static const struct snmp_scalar_node tcp_InSegs = SNMP_SCALAR_CREATE_NODE_READONLY(10, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_OutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(11, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_RetransSegs = SNMP_SCALAR_CREATE_NODE_READONLY(12, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_InErrs = SNMP_SCALAR_CREATE_NODE_READONLY(14, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_OutRsts = SNMP_SCALAR_CREATE_NODE_READONLY(15, SNMP_ASN1_TYPE_COUNTER, tcp_get_value); +static const struct snmp_scalar_node tcp_HCInSegs = SNMP_SCALAR_CREATE_NODE_READONLY(17, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value); +static const struct snmp_scalar_node tcp_HCOutSegs = SNMP_SCALAR_CREATE_NODE_READONLY(18, SNMP_ASN1_TYPE_COUNTER64, tcp_get_value); + +#if LWIP_IPV4 +static const struct snmp_table_simple_col_def tcp_ConnTable_columns[] = { + { 1, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnState */ + { 2, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalAddress */ + { 3, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnLocalPort */ + { 4, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnRemAddress */ + { 5, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnRemPort */ +}; + +static const struct snmp_table_simple_node tcp_ConnTable = SNMP_TABLE_CREATE_SIMPLE(13, tcp_ConnTable_columns, tcp_ConnTable_get_cell_value, tcp_ConnTable_get_next_cell_instance_and_value); +#endif /* LWIP_IPV4 */ + +static const struct snmp_table_simple_col_def tcp_ConnectionTable_columns[] = { + /* all items except tcpConnectionState and tcpConnectionProcess are declared as not-accessible */ + { 7, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 }, /* tcpConnectionState */ + { 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpConnectionProcess */ +}; + +static const struct snmp_table_simple_node tcp_ConnectionTable = SNMP_TABLE_CREATE_SIMPLE(19, tcp_ConnectionTable_columns, tcp_ConnectionTable_get_cell_value, tcp_ConnectionTable_get_next_cell_instance_and_value); + + +static const struct snmp_table_simple_col_def tcp_ListenerTable_columns[] = { + /* all items except tcpListenerProcess are declared as not-accessible */ + { 4, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* tcpListenerProcess */ +}; + +static const struct snmp_table_simple_node tcp_ListenerTable = SNMP_TABLE_CREATE_SIMPLE(20, tcp_ListenerTable_columns, tcp_ListenerTable_get_cell_value, tcp_ListenerTable_get_next_cell_instance_and_value); + +/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ +CREATE_LWIP_SYNC_NODE( 1, tcp_RtoAlgorithm) +CREATE_LWIP_SYNC_NODE( 2, tcp_RtoMin) +CREATE_LWIP_SYNC_NODE( 3, tcp_RtoMax) +CREATE_LWIP_SYNC_NODE( 4, tcp_MaxConn) +CREATE_LWIP_SYNC_NODE( 5, tcp_ActiveOpens) +CREATE_LWIP_SYNC_NODE( 6, tcp_PassiveOpens) +CREATE_LWIP_SYNC_NODE( 7, tcp_AttemptFails) +CREATE_LWIP_SYNC_NODE( 8, tcp_EstabResets) +CREATE_LWIP_SYNC_NODE( 9, tcp_CurrEstab) +CREATE_LWIP_SYNC_NODE(10, tcp_InSegs) +CREATE_LWIP_SYNC_NODE(11, tcp_OutSegs) +CREATE_LWIP_SYNC_NODE(12, tcp_RetransSegs) +#if LWIP_IPV4 +CREATE_LWIP_SYNC_NODE(13, tcp_ConnTable) +#endif /* LWIP_IPV4 */ +CREATE_LWIP_SYNC_NODE(14, tcp_InErrs) +CREATE_LWIP_SYNC_NODE(15, tcp_OutRsts) +CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs) +CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs) +CREATE_LWIP_SYNC_NODE(19, tcp_ConnectionTable) +CREATE_LWIP_SYNC_NODE(20, tcp_ListenerTable) + +static const struct snmp_node* const tcp_nodes[] = { + &SYNC_NODE_NAME(tcp_RtoAlgorithm).node.node, + &SYNC_NODE_NAME(tcp_RtoMin).node.node, + &SYNC_NODE_NAME(tcp_RtoMax).node.node, + &SYNC_NODE_NAME(tcp_MaxConn).node.node, + &SYNC_NODE_NAME(tcp_ActiveOpens).node.node, + &SYNC_NODE_NAME(tcp_PassiveOpens).node.node, + &SYNC_NODE_NAME(tcp_AttemptFails).node.node, + &SYNC_NODE_NAME(tcp_EstabResets).node.node, + &SYNC_NODE_NAME(tcp_CurrEstab).node.node, + &SYNC_NODE_NAME(tcp_InSegs).node.node, + &SYNC_NODE_NAME(tcp_OutSegs).node.node, + &SYNC_NODE_NAME(tcp_RetransSegs).node.node, +#if LWIP_IPV4 + &SYNC_NODE_NAME(tcp_ConnTable).node.node, +#endif /* LWIP_IPV4 */ + &SYNC_NODE_NAME(tcp_InErrs).node.node, + &SYNC_NODE_NAME(tcp_OutRsts).node.node, + &SYNC_NODE_NAME(tcp_HCInSegs).node.node, + &SYNC_NODE_NAME(tcp_HCOutSegs).node.node, + &SYNC_NODE_NAME(tcp_ConnectionTable).node.node, + &SYNC_NODE_NAME(tcp_ListenerTable).node.node +}; + +const struct snmp_tree_node snmp_mib2_tcp_root = SNMP_CREATE_TREE_NODE(6, tcp_nodes); +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_TCP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_udp.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_udp.c new file mode 100644 index 0000000000..6a983df20b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_mib2_udp.c @@ -0,0 +1,357 @@ +/** + * @file + * Management Information Base II (RFC1213) UDP objects and functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + * Christiaan Simons + */ + +#include "lwip/snmp.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_mib2.h" +#include "lwip/apps/snmp_table.h" +#include "lwip/apps/snmp_scalar.h" +#include "lwip/udp.h" +#include "lwip/stats.h" + +#include + +#if LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP + +#if SNMP_USE_NETCONN +#define SYNC_NODE_NAME(node_name) node_name ## _synced +#define CREATE_LWIP_SYNC_NODE(oid, node_name) \ + static const struct snmp_threadsync_node node_name ## _synced = SNMP_CREATE_THREAD_SYNC_NODE(oid, &node_name.node, &snmp_mib2_lwip_locks); +#else +#define SYNC_NODE_NAME(node_name) node_name +#define CREATE_LWIP_SYNC_NODE(oid, node_name) +#endif + +/* --- udp .1.3.6.1.2.1.7 ----------------------------------------------------- */ + +static s16_t +udp_get_value(struct snmp_node_instance* instance, void* value) +{ + u32_t *uint_ptr = (u32_t*)value; + + switch (instance->node->oid) { + case 1: /* udpInDatagrams */ + *uint_ptr = STATS_GET(mib2.udpindatagrams); + return sizeof(*uint_ptr); + case 2: /* udpNoPorts */ + *uint_ptr = STATS_GET(mib2.udpnoports); + return sizeof(*uint_ptr); + case 3: /* udpInErrors */ + *uint_ptr = STATS_GET(mib2.udpinerrors); + return sizeof(*uint_ptr); + case 4: /* udpOutDatagrams */ + *uint_ptr = STATS_GET(mib2.udpoutdatagrams); + return sizeof(*uint_ptr); + case 8: /* udpHCInDatagrams */ + memset(value, 0, 2*sizeof(u32_t)); /* not supported */ + return 2*sizeof(u32_t); + case 9: /* udpHCOutDatagrams */ + memset(value, 0, 2*sizeof(u32_t)); /* not supported */ + return 2*sizeof(u32_t); + default: + LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid)); + break; + } + + return 0; +} + +/* --- udpEndpointTable --- */ + +static snmp_err_t +udp_endpointTable_get_cell_value_core(const u32_t* column, union snmp_variant_value* value) +{ + /* all items except udpEndpointProcess are declared as not-accessible */ + switch (*column) { + case 8: /* udpEndpointProcess */ + value->u32 = 0; /* not supported */ + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +udp_endpointTable_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip_addr_t local_ip, remote_ip; + u16_t local_port, remote_port; + struct udp_pcb *pcb; + u8_t idx = 0; + + LWIP_UNUSED_ARG(value_len); + + /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ + idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &local_ip, &local_port); + if (idx == 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ + idx += snmp_oid_to_ip_port(&row_oid[idx], row_oid_len-idx, &remote_ip, &remote_port); + if (idx == 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* udpEndpointInstance */ + if (row_oid_len < (idx+1)) { + return SNMP_ERR_NOSUCHINSTANCE; + } + if (row_oid[idx] != 0) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* find udp_pcb with requested ip and port*/ + pcb = udp_pcbs; + while (pcb != NULL) { + if (ip_addr_cmp(&local_ip, &pcb->local_ip) && + (local_port == pcb->local_port) && + ip_addr_cmp(&remote_ip, &pcb->remote_ip) && + (remote_port == pcb->remote_port)) { + /* fill in object properties */ + return udp_endpointTable_get_cell_value_core(column, value); + } + pcb = pcb->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct udp_pcb *pcb; + struct snmp_next_oid_state state; + /* 1x udpEndpointLocalAddressType + 1x OID len + 16x udpEndpointLocalAddress + 1x udpEndpointLocalPort + + * 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort + + * 1x udpEndpointInstance = 39 + */ + u32_t result_temp[39]; + + LWIP_UNUSED_ARG(value_len); + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp)); + + /* iterate over all possible OIDs to find the next one */ + pcb = udp_pcbs; + while (pcb != NULL) { + u32_t test_oid[LWIP_ARRAYSIZE(result_temp)]; + u8_t idx = 0; + + /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */ + idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]); + + /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */ + idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]); + + test_oid[idx] = 0; /* udpEndpointInstance */ + idx++; + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, idx, NULL); + + pcb = pcb->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return udp_endpointTable_get_cell_value_core(column, value); + } else { + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; + } +} + +/* --- udpTable --- */ + +#if LWIP_IPV4 + +/* list of allowed value ranges for incoming OID */ +static const struct snmp_oid_range udp_Table_oid_ranges[] = { + { 0, 0xff }, /* IP A */ + { 0, 0xff }, /* IP B */ + { 0, 0xff }, /* IP C */ + { 0, 0xff }, /* IP D */ + { 1, 0xffff } /* Port */ +}; + +static snmp_err_t +udp_Table_get_cell_value_core(struct udp_pcb *pcb, const u32_t* column, union snmp_variant_value* value, u32_t* value_len) +{ + LWIP_UNUSED_ARG(value_len); + + switch (*column) { + case 1: /* udpLocalAddress */ + /* set reference to PCB local IP and return a generic node that copies IP4 addresses */ + value->u32 = ip_2_ip4(&pcb->local_ip)->addr; + break; + case 2: /* udpLocalPort */ + /* set reference to PCB local port and return a generic node that copies u16_t values */ + value->u32 = pcb->local_port; + break; + default: + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static snmp_err_t +udp_Table_get_cell_value(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len) +{ + ip4_addr_t ip; + u16_t port; + struct udp_pcb *pcb; + + /* check if incoming OID length and if values are in plausible range */ + if (!snmp_oid_in_range(row_oid, row_oid_len, udp_Table_oid_ranges, LWIP_ARRAYSIZE(udp_Table_oid_ranges))) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + /* get IP and port from incoming OID */ + snmp_oid_to_ip4(&row_oid[0], &ip); /* we know it succeeds because of oid_in_range check above */ + port = (u16_t)row_oid[4]; + + /* find udp_pcb with requested ip and port*/ + pcb = udp_pcbs; + while (pcb != NULL) { + if (IP_IS_V4_VAL(pcb->local_ip)) { + if (ip4_addr_cmp(&ip, ip_2_ip4(&pcb->local_ip)) && (port == pcb->local_port)) { + /* fill in object properties */ + return udp_Table_get_cell_value_core(pcb, column, value, value_len); + } + } + pcb = pcb->next; + } + + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; +} + +static snmp_err_t +udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len) +{ + struct udp_pcb *pcb; + struct snmp_next_oid_state state; + u32_t result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; + + /* init struct to search next oid */ + snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges)); + + /* iterate over all possible OIDs to find the next one */ + pcb = udp_pcbs; + while (pcb != NULL) { + u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)]; + + if (IP_IS_V4_VAL(pcb->local_ip)) { + snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]); + test_oid[4] = pcb->local_port; + + /* check generated OID: is it a candidate for the next one? */ + snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb); + } + + pcb = pcb->next; + } + + /* did we find a next one? */ + if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) { + snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len); + /* fill in object properties */ + return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len); + } else { + /* not found */ + return SNMP_ERR_NOSUCHINSTANCE; + } +} + +#endif /* LWIP_IPV4 */ + +static const struct snmp_scalar_node udp_inDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(1, SNMP_ASN1_TYPE_COUNTER, udp_get_value); +static const struct snmp_scalar_node udp_noPorts = SNMP_SCALAR_CREATE_NODE_READONLY(2, SNMP_ASN1_TYPE_COUNTER, udp_get_value); +static const struct snmp_scalar_node udp_inErrors = SNMP_SCALAR_CREATE_NODE_READONLY(3, SNMP_ASN1_TYPE_COUNTER, udp_get_value); +static const struct snmp_scalar_node udp_outDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(4, SNMP_ASN1_TYPE_COUNTER, udp_get_value); +static const struct snmp_scalar_node udp_HCInDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(8, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); +static const struct snmp_scalar_node udp_HCOutDatagrams = SNMP_SCALAR_CREATE_NODE_READONLY(9, SNMP_ASN1_TYPE_COUNTER64, udp_get_value); + +#if LWIP_IPV4 +static const struct snmp_table_simple_col_def udp_Table_columns[] = { + { 1, SNMP_ASN1_TYPE_IPADDR, SNMP_VARIANT_VALUE_TYPE_U32 }, /* udpLocalAddress */ + { 2, SNMP_ASN1_TYPE_INTEGER, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpLocalPort */ +}; +static const struct snmp_table_simple_node udp_Table = SNMP_TABLE_CREATE_SIMPLE(5, udp_Table_columns, udp_Table_get_cell_value, udp_Table_get_next_cell_instance_and_value); +#endif /* LWIP_IPV4 */ + +static const struct snmp_table_simple_col_def udp_endpointTable_columns[] = { + /* all items except udpEndpointProcess are declared as not-accessible */ + { 8, SNMP_ASN1_TYPE_UNSIGNED32, SNMP_VARIANT_VALUE_TYPE_U32 } /* udpEndpointProcess */ +}; + +static const struct snmp_table_simple_node udp_endpointTable = SNMP_TABLE_CREATE_SIMPLE(7, udp_endpointTable_columns, udp_endpointTable_get_cell_value, udp_endpointTable_get_next_cell_instance_and_value); + +/* the following nodes access variables in LWIP stack from SNMP worker thread and must therefore be synced to LWIP (TCPIP) thread */ +CREATE_LWIP_SYNC_NODE(1, udp_inDatagrams) +CREATE_LWIP_SYNC_NODE(2, udp_noPorts) +CREATE_LWIP_SYNC_NODE(3, udp_inErrors) +CREATE_LWIP_SYNC_NODE(4, udp_outDatagrams) +#if LWIP_IPV4 +CREATE_LWIP_SYNC_NODE(5, udp_Table) +#endif /* LWIP_IPV4 */ +CREATE_LWIP_SYNC_NODE(7, udp_endpointTable) +CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams) +CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams) + +static const struct snmp_node* const udp_nodes[] = { + &SYNC_NODE_NAME(udp_inDatagrams).node.node, + &SYNC_NODE_NAME(udp_noPorts).node.node, + &SYNC_NODE_NAME(udp_inErrors).node.node, + &SYNC_NODE_NAME(udp_outDatagrams).node.node, +#if LWIP_IPV4 + &SYNC_NODE_NAME(udp_Table).node.node, +#endif /* LWIP_IPV4 */ + &SYNC_NODE_NAME(udp_endpointTable).node.node, + &SYNC_NODE_NAME(udp_HCInDatagrams).node.node, + &SYNC_NODE_NAME(udp_HCOutDatagrams).node.node +}; + +const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes); +#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.c new file mode 100644 index 0000000000..0cb7ca997c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.c @@ -0,0 +1,1668 @@ +/** + * @file + * SNMP message processing (RFC1157). + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + * Elias Oenal + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "snmp_msg.h" +#include "snmp_asn1.h" +#include "snmp_core_priv.h" +#include "lwip/ip_addr.h" +#include "lwip/stats.h" + +#if LWIP_SNMP_V3 +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" +#ifdef LWIP_SNMPV3_INCLUDE_ENGINE +#include LWIP_SNMPV3_INCLUDE_ENGINE +#endif +#endif + +#include + +/* public (non-static) constants */ +/** SNMP community string */ +const char *snmp_community = SNMP_COMMUNITY; +/** SNMP community string for write access */ +const char *snmp_community_write = SNMP_COMMUNITY_WRITE; +/** SNMP community string for sending traps */ +const char *snmp_community_trap = SNMP_COMMUNITY_TRAP; + +snmp_write_callback_fct snmp_write_callback = NULL; +void* snmp_write_callback_arg = NULL; + +/** + * @ingroup snmp_core + * Returns current SNMP community string. + * @return current SNMP community string + */ +const char * +snmp_get_community(void) +{ + return snmp_community; +} + +/** + * @ingroup snmp_core + * Sets SNMP community string. + * The string itself (its storage) must be valid throughout the whole life of + * program (or until it is changed to sth else). + * + * @param community is a pointer to new community string + */ +void +snmp_set_community(const char * const community) +{ + LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); + snmp_community = community; +} + +/** + * @ingroup snmp_core + * Returns current SNMP write-access community string. + * @return current SNMP write-access community string + */ +const char * +snmp_get_community_write(void) +{ + return snmp_community_write; +} + +/** + * @ingroup snmp_traps + * Returns current SNMP community string used for sending traps. + * @return current SNMP community string used for sending traps + */ +const char * +snmp_get_community_trap(void) +{ + return snmp_community_trap; +} + +/** + * @ingroup snmp_core + * Sets SNMP community string for write-access. + * The string itself (its storage) must be valid throughout the whole life of + * program (or until it is changed to sth else). + * + * @param community is a pointer to new write-access community string + */ +void +snmp_set_community_write(const char * const community) +{ + LWIP_ASSERT("community string must not be NULL", community != NULL); + LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); + snmp_community_write = community; +} + +/** + * @ingroup snmp_traps + * Sets SNMP community string used for sending traps. + * The string itself (its storage) must be valid throughout the whole life of + * program (or until it is changed to sth else). + * + * @param community is a pointer to new trap community string + */ +void +snmp_set_community_trap(const char * const community) +{ + LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); + snmp_community_trap = community; +} + +/** + * @ingroup snmp_core + * Callback fired on every successful write access + */ +void +snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg) +{ + snmp_write_callback = write_callback; + snmp_write_callback_arg = callback_arg; +} + +/* ----------------------------------------------------------------------- */ +/* forward declarations */ +/* ----------------------------------------------------------------------- */ + +static err_t snmp_process_get_request(struct snmp_request *request); +static err_t snmp_process_getnext_request(struct snmp_request *request); +static err_t snmp_process_getbulk_request(struct snmp_request *request); +static err_t snmp_process_set_request(struct snmp_request *request); + +static err_t snmp_parse_inbound_frame(struct snmp_request *request); +static err_t snmp_prepare_outbound_frame(struct snmp_request *request); +static err_t snmp_complete_outbound_frame(struct snmp_request *request); +static void snmp_execute_write_callbacks(struct snmp_request *request); + + +/* ----------------------------------------------------------------------- */ +/* implementation */ +/* ----------------------------------------------------------------------- */ + +void +snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port) +{ + err_t err; + struct snmp_request request; + + memset(&request, 0, sizeof(request)); + request.handle = handle; + request.source_ip = source_ip; + request.source_port = port; + request.inbound_pbuf = p; + + snmp_stats.inpkts++; + + err = snmp_parse_inbound_frame(&request); + if (err == ERR_OK) { + err = snmp_prepare_outbound_frame(&request); + if (err == ERR_OK) { + + if (request.error_status == SNMP_ERR_NOERROR) { + /* only process frame if we do not already have an error to return (e.g. all readonly) */ + if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) { + err = snmp_process_get_request(&request); + } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) { + err = snmp_process_getnext_request(&request); + } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { + err = snmp_process_getbulk_request(&request); + } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { + err = snmp_process_set_request(&request); + } + } + + if (err == ERR_OK) { + err = snmp_complete_outbound_frame(&request); + + if (err == ERR_OK) { + err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port); + + if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) + && (request.error_status == SNMP_ERR_NOERROR) + && (snmp_write_callback != NULL)) { + /* raise write notification for all written objects */ + snmp_execute_write_callbacks(&request); + } + } + } + } + + if (request.outbound_pbuf != NULL) { + pbuf_free(request.outbound_pbuf); + } + } +} + +static u8_t +snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg) +{ + if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) { + /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */ + return SNMP_ERR_NOSUCHINSTANCE; + } + + return SNMP_ERR_NOERROR; +} + +static void +snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next) +{ + err_t err; + struct snmp_node_instance node_instance; + memset(&node_instance, 0, sizeof(node_instance)); + + if (get_next) { + struct snmp_obj_id result_oid; + request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance); + + if (request->error_status == SNMP_ERR_NOERROR) { + snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len); + } + } else { + request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance); + + if (request->error_status == SNMP_ERR_NOERROR) { + /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */ + request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request); + + if (request->error_status != SNMP_ERR_NOERROR) { + if (node_instance.release_instance != NULL) { + node_instance.release_instance(&node_instance); + } + } + } + } + + if (request->error_status != SNMP_ERR_NOERROR) { + if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { + if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) { + /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */ + vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK)); + vb->value_len = 0; + + err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb); + if (err == ERR_OK) { + /* we stored the exception in varbind -> go on */ + request->error_status = SNMP_ERR_NOERROR; + } else if (err == ERR_BUF) { + request->error_status = SNMP_ERR_TOOBIG; + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } + } else { + /* according to RFC 1157/1905, all other errors only return genError */ + request->error_status = SNMP_ERR_GENERROR; + } + } else { + s16_t len = node_instance.get_value(&node_instance, vb->value); + vb->type = node_instance.asn1_type; + + if(len >= 0) { + vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */ + + LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE); + err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb); + + if (err == ERR_BUF) { + request->error_status = SNMP_ERR_TOOBIG; + } else if (err != ERR_OK) { + request->error_status = SNMP_ERR_GENERROR; + } + } else { + request->error_status = SNMP_ERR_GENERROR; + } + + if (node_instance.release_instance != NULL) { + node_instance.release_instance(&node_instance); + } + } +} + + +/** + * Service an internal or external event for SNMP GET. + * + * @param request points to the associated message process state + */ +static err_t +snmp_process_get_request(struct snmp_request *request) +{ + snmp_vb_enumerator_err_t err; + struct snmp_varbind vb; + vb.value = request->value_buffer; + + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n")); + + while (request->error_status == SNMP_ERR_NOERROR) { + err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_OK) { + if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { + snmp_process_varbind(request, &vb, 0); + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { + /* malformed ASN.1, don't answer */ + return ERR_ARG; + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } + + return ERR_OK; +} + +/** + * Service an internal or external event for SNMP GET. + * + * @param request points to the associated message process state + */ +static err_t +snmp_process_getnext_request(struct snmp_request *request) +{ + snmp_vb_enumerator_err_t err; + struct snmp_varbind vb; + vb.value = request->value_buffer; + + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n")); + + while (request->error_status == SNMP_ERR_NOERROR) { + err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_OK) { + if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { + snmp_process_varbind(request, &vb, 1); + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { + /* malformed ASN.1, don't answer */ + return ERR_ARG; + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } + + return ERR_OK; +} + +/** + * Service an internal or external event for SNMP GETBULKT. + * + * @param request points to the associated message process state + */ +static err_t +snmp_process_getbulk_request(struct snmp_request *request) +{ + snmp_vb_enumerator_err_t err; + s32_t non_repeaters = request->non_repeaters; + s32_t repetitions; + u16_t repetition_offset = 0; + struct snmp_varbind_enumerator repetition_varbind_enumerator; + struct snmp_varbind vb; + vb.value = request->value_buffer; + + if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) { + repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS); + } else { + repetitions = request->max_repetitions; + } + + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n")); + + /* process non repeaters and first repetition */ + while (request->error_status == SNMP_ERR_NOERROR) { + if (non_repeaters == 0) { + repetition_offset = request->outbound_pbuf_stream.offset; + + if (repetitions == 0) { + /* do not resolve repeaters when repetitions is set to 0 */ + break; + } + repetitions--; + } + + err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { + /* malformed ASN.1, don't answer */ + return ERR_ARG; + } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) { + request->error_status = SNMP_ERR_GENERROR; + } else { + snmp_process_varbind(request, &vb, 1); + non_repeaters--; + } + } + + /* process repetitions > 1 */ + while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) { + + u8_t all_endofmibview = 1; + + snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset); + repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */ + + while (request->error_status == SNMP_ERR_NOERROR) { + vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */ + err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_OK) { + vb.value = request->value_buffer; + snmp_process_varbind(request, &vb, 1); + + if (request->error_status != SNMP_ERR_NOERROR) { + /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */ + request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; + } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) { + all_endofmibview = 0; + } + } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else { + LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!")); + request->error_status = SNMP_ERR_GENERROR; + request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; + } + } + + if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) { + /* stop when all varbinds in a loop return EndOfMibView */ + break; + } + + repetitions--; + } + + if (request->error_status == SNMP_ERR_TOOBIG) { + /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */ + request->error_status = SNMP_ERR_NOERROR; + } + + return ERR_OK; +} + +/** + * Service an internal or external event for SNMP SET. + * + * @param request points to the associated message process state + */ +static err_t +snmp_process_set_request(struct snmp_request *request) +{ + snmp_vb_enumerator_err_t err; + struct snmp_varbind vb; + vb.value = request->value_buffer; + + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n")); + + /* perform set test on all objects */ + while (request->error_status == SNMP_ERR_NOERROR) { + err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_OK) { + struct snmp_node_instance node_instance; + memset(&node_instance, 0, sizeof(node_instance)); + + request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); + if (request->error_status == SNMP_ERR_NOERROR) { + if (node_instance.asn1_type != vb.type) { + request->error_status = SNMP_ERR_WRONGTYPE; + } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) { + request->error_status = SNMP_ERR_NOTWRITABLE; + } else { + if (node_instance.set_test != NULL) { + request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value); + } + } + + if (node_instance.release_instance != NULL) { + node_instance.release_instance(&node_instance); + } + } + } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) { + request->error_status = SNMP_ERR_WRONGLENGTH; + } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { + /* malformed ASN.1, don't answer */ + return ERR_ARG; + } else { + request->error_status = SNMP_ERR_GENERROR; + } + } + + /* perform real set operation on all objects */ + if (request->error_status == SNMP_ERR_NOERROR) { + snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); + while (request->error_status == SNMP_ERR_NOERROR) { + err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); + if (err == SNMP_VB_ENUMERATOR_ERR_OK) { + struct snmp_node_instance node_instance; + memset(&node_instance, 0, sizeof(node_instance)); + request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); + if (request->error_status == SNMP_ERR_NOERROR) { + if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) { + if (request->inbound_varbind_enumerator.varbind_count == 1) { + request->error_status = SNMP_ERR_COMMITFAILED; + } else { + /* we cannot undo the set operations done so far */ + request->error_status = SNMP_ERR_UNDOFAILED; + } + } + + if (node_instance.release_instance != NULL) { + node_instance.release_instance(&node_instance); + } + } + } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { + /* no more varbinds in request */ + break; + } else { + /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */ + request->error_status = SNMP_ERR_GENERROR; + } + } + } + + return ERR_OK; +} + +#define PARSE_EXEC(code, retValue) \ + if ((code) != ERR_OK) { \ + LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \ + snmp_stats.inasnparseerrs++; \ + return retValue; \ + } + +#define PARSE_ASSERT(cond, retValue) \ + if (!(cond)) { \ + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ + snmp_stats.inasnparseerrs++; \ + return retValue; \ + } + +#define BUILD_EXEC(code, retValue) \ + if ((code) != ERR_OK) { \ + LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ + return retValue; \ + } + +#define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG) +#define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG) + +/** + * Checks and decodes incoming SNMP message header, logs header errors. + * + * @param request points to the current message request state return + * @return + * - ERR_OK SNMP header is sane and accepted + * - ERR_VAL SNMP header is either malformed or rejected + */ +static err_t +snmp_parse_inbound_frame(struct snmp_request *request) +{ + struct snmp_pbuf_stream pbuf_stream; + struct snmp_asn1_tlv tlv; + s32_t parent_tlv_value_len; + s32_t s32_value; + err_t err; + + IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); + + /* decode main container consisting of version, community and PDU */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length)); + parent_tlv_value_len = tlv.value_len; + + /* decode version */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + if ((s32_value != SNMP_VERSION_1) && + (s32_value != SNMP_VERSION_2c) +#if LWIP_SNMP_V3 + && (s32_value != SNMP_VERSION_3) +#endif + ) + { + /* unsupported SNMP version */ + snmp_stats.inbadversions++; + return ERR_ARG; + } + request->version = (u8_t)s32_value; + +#if LWIP_SNMP_V3 + if (request->version == SNMP_VERSION_3) { + u16_t u16_value; + u16_t inbound_msgAuthenticationParameters_offset; + + /* SNMPv3 doesn't use communities */ + /* @todo: Differentiate read/write access */ + strcpy((char*)request->community, snmp_community); + request->community_strlen = (u16_t)strlen(snmp_community); + + /* RFC3414 globalData */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); + parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + /* decode msgID */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + request->msg_id = s32_value; + + /* decode msgMaxSize */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + request->msg_max_size = s32_value; + + /* decode msgFlags */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + request->msg_flags = (u8_t)s32_value; + + /* decode msgSecurityModel */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + request->msg_security_model = s32_value; + + /* RFC3414 msgSecurityParameters + * The User-based Security Model defines the contents of the OCTET + * STRING as a SEQUENCE. + * + * We skip the protective dummy OCTET STRING header + * to access the SEQUENCE header. + */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + /* msgSecurityParameters SEQUENCE header */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); + parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + /* decode msgAuthoritativeEngineID */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id, + &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); + request->msg_authoritative_engine_id_len = (u8_t)u16_value; + + /* msgAuthoritativeEngineBoots */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots)); + + /* msgAuthoritativeEngineTime */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time)); + /* @todo: Implement time window checking */ + + /* msgUserName */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name, + &u16_value, SNMP_V3_MAX_USER_LENGTH)); + request->msg_user_name_len = (u8_t)u16_value; + /* @todo: Implement unknown user error response */ + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, NULL, NULL)); + + /* msgAuthenticationParameters */ + memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + /* Remember position */ + inbound_msgAuthenticationParameters_offset = pbuf_stream.offset; + LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset); + /* Read auth parameters */ + IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, + &u16_value, tlv.value_len)); + +#if LWIP_SNMP_V3_CRYPTO + if (request->msg_flags & SNMP_V3_AUTH_FLAG) { + const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 }; + u8_t key[20]; + u8_t algo; + u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; + struct snmp_pbuf_stream auth_stream; + + /* Rewind stream */ + IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); + IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset)); + /* Set auth parameters to zero for verification */ + IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len)); + + /* Verify authentication */ + IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); + + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); + IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac)); + /* @todo: Implement error response */ + IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); + } +#else + /* Ungraceful exit if we encounter cryptography and don't support it. + * @todo: Implement error response + */ + IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG))); +#endif + + /* msgPrivacyParameters */ + memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, + &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); + +#if LWIP_SNMP_V3_CRYPTO + /* Decrypt message */ + if (request->msg_flags & SNMP_V3_PRIV_FLAG) { + u8_t key[20]; + u8_t algo; + + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); + IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key, + request->msg_privacy_parameters, request->msg_authoritative_engine_boots, + request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT)); + } +#endif + + /* Scoped PDU + * Encryption context + */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); + parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + /* contextEngineID */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id, + &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); + request->context_engine_id_len = (u8_t)u16_value; + + /* contextName */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name, + &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); + request->context_name_len = (u8_t)u16_value; + } else +#endif + { + /* decode community */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN); + if (err == ERR_MEM) { + /* community string does not fit in our buffer -> its too long -> its invalid */ + request->community_strlen = 0; + snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len); + } else { + IF_PARSE_ASSERT(err == ERR_OK); + } + /* add zero terminator */ + request->community[request->community_strlen] = 0; + } + + /* decode PDU type (next container level) */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length); + request->inbound_padding_len = pbuf_stream.length - tlv.value_len; + parent_tlv_value_len = tlv.value_len; + + /* validate PDU type */ + switch(tlv.type) { + case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ): + /* GetRequest PDU */ + snmp_stats.ingetrequests++; + break; + case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ): + /* GetNextRequest PDU */ + snmp_stats.ingetnexts++; + break; + case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ): + /* GetBulkRequest PDU */ + if (request->version < SNMP_VERSION_2c) { + /* RFC2089: invalid, drop packet */ + return ERR_ARG; + } + break; + case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ): + /* SetRequest PDU */ + snmp_stats.insetrequests++; + break; + default: + /* unsupported input PDU for this agent (no parse error) */ + LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ + return ERR_ARG; + break; + } + request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; + + /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */ + if (request->community_strlen == 0) { + /* community string was too long or really empty*/ + snmp_stats.inbadcommunitynames++; + snmp_authfail_trap(); + return ERR_ARG; + } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { + if (snmp_community_write[0] == 0) { + /* our write community is empty, that means all our objects are readonly */ + request->error_status = SNMP_ERR_NOTWRITABLE; + request->error_index = 1; + } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { + /* community name does not match */ + snmp_stats.inbadcommunitynames++; + snmp_authfail_trap(); + return ERR_ARG; + } + } else { + if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { + /* community name does not match */ + snmp_stats.inbadcommunitynames++; + snmp_authfail_trap(); + return ERR_ARG; + } + } + + /* decode request ID */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id)); + + /* decode error status / non-repeaters */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters)); + if (request->non_repeaters < 0) { + /* RFC 1905, 4.2.3 */ + request->non_repeaters = 0; + } + } else { + /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */ + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); + IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR); + } + + /* decode error index / max-repetitions */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); + parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); + IF_PARSE_ASSERT(parent_tlv_value_len > 0); + + if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions)); + if (request->max_repetitions < 0) { + /* RFC 1905, 4.2.3 */ + request->max_repetitions = 0; + } + } else { + IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index)); + IF_PARSE_ASSERT(s32_value == 0); + } + + /* decode varbind-list type (next container level) */ + IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); + IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length)); + + request->inbound_varbind_offset = pbuf_stream.offset; + request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len; + snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); + + return ERR_OK; +} + +#define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) + +static err_t +snmp_prepare_outbound_frame(struct snmp_request *request) +{ + struct snmp_asn1_tlv tlv; + struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream); + + /* try allocating pbuf(s) for maximum response size */ + request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); + if (request->outbound_pbuf == NULL) { + return ERR_MEM; + } + + snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); + + /* 'Message' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + + /* version */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); + +#if LWIP_SNMP_V3 + if (request->version < SNMP_VERSION_3) { +#endif + /* community */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); +#if LWIP_SNMP_V3 + } else { + const char* id; + + /* globalData */ + request->outbound_msg_global_data_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + /* msgID */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); + snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id)); + + /* msgMaxSize */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); + snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size)); + + /* msgFlags */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1)); + + /* msgSecurityModel */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); + snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model)); + + /* end of msgGlobalData */ + request->outbound_msg_global_data_end = pbuf_stream->offset; + + /* msgSecurityParameters */ + request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + /* msgAuthoritativeEngineID */ + snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); + MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); + + request->msg_authoritative_engine_time = snmpv3_get_engine_time(); + request->msg_authoritative_engine_boots = snmpv3_get_engine_boots(); + + /* msgAuthoritativeEngineBoots */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots)); + + /* msgAuthoritativeEngineTime */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time)); + + /* msgUserName */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); + +#if LWIP_SNMP_V3_CRYPTO + /* msgAuthenticationParameters */ + if (request->msg_flags & SNMP_V3_AUTH_FLAG) { + memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); + request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); + } else +#endif + { + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + } + +#if LWIP_SNMP_V3_CRYPTO + /* msgPrivacyParameters */ + if (request->msg_flags & SNMP_V3_PRIV_FLAG) { + snmpv3_build_priv_param(request->msg_privacy_parameters); + + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); + } else +#endif + { + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + } + + /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ + request->outbound_msg_security_parameters_end = pbuf_stream->offset; + +#if LWIP_SNMP_V3_CRYPTO + /* For encryption we have to encapsulate the payload in an octet string */ + if (request->msg_flags & SNMP_V3_PRIV_FLAG) { + request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + } +#endif + /* Scoped PDU + * Encryption context + */ + request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + /* contextEngineID */ + snmpv3_get_engine_id(&id, &request->context_engine_id_len); + MEMCPY(request->context_engine_id, id, request->context_engine_id_len); + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); + + /* contextName */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len)); + } +#endif + + /* 'PDU' sequence */ + request->outbound_pdu_offset = pbuf_stream->offset; + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + + /* request ID */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); + + /* error status */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + request->outbound_error_status_offset = pbuf_stream->offset; + OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); + + /* error index */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + request->outbound_error_index_offset = pbuf_stream->offset; + OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); + + /* 'VarBindList' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); + + request->outbound_varbind_offset = pbuf_stream->offset; + + return ERR_OK; +} + +/** Calculate the length of a varbind list */ +err_t +snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) +{ + /* calculate required lengths */ + snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len); + snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len); + + if (varbind->value_len == 0) { + len->value_value_len = 0; + } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { + len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); + } else { + switch (varbind->type) { + case SNMP_ASN1_TYPE_INTEGER: + if (varbind->value_len != sizeof (s32_t)) { + return ERR_VAL; + } + snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len); + break; + case SNMP_ASN1_TYPE_COUNTER: + case SNMP_ASN1_TYPE_GAUGE: + case SNMP_ASN1_TYPE_TIMETICKS: + if (varbind->value_len != sizeof (u32_t)) { + return ERR_VAL; + } + snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len); + break; + case SNMP_ASN1_TYPE_OCTET_STRING: + case SNMP_ASN1_TYPE_IPADDR: + case SNMP_ASN1_TYPE_OPAQUE: + len->value_value_len = varbind->value_len; + break; + case SNMP_ASN1_TYPE_NULL: + if (varbind->value_len != 0) { + return ERR_VAL; + } + len->value_value_len = 0; + break; + case SNMP_ASN1_TYPE_OBJECT_ID: + if ((varbind->value_len & 0x03) != 0) { + return ERR_VAL; + } + snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len); + break; + case SNMP_ASN1_TYPE_COUNTER64: + if (varbind->value_len != (2 * sizeof (u32_t))) { + return ERR_VAL; + } + snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len); + break; + default: + /* unsupported type */ + return ERR_VAL; + } + } + snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len); + + len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len; + snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len); + + return ERR_OK; +} + +#define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) + +err_t +snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind) +{ + struct snmp_asn1_tlv tlv; + struct snmp_varbind_len len; + err_t err; + + err = snmp_varbind_length(varbind, &len); + + if (err != ERR_OK) { + return err; + } + + /* check length already before adding first data because in case of GetBulk, + * data added so far is returned and therefore no partial data shall be added + */ + if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) { + return ERR_BUF; + } + + /* 'VarBind' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len); + OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + /* VarBind OID */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len); + OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len)); + + /* VarBind value */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len); + OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); + + if (len.value_value_len > 0) { + if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { + OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); + } else { + switch (varbind->type) { + case SNMP_ASN1_TYPE_INTEGER: + OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value))); + break; + case SNMP_ASN1_TYPE_COUNTER: + case SNMP_ASN1_TYPE_GAUGE: + case SNMP_ASN1_TYPE_TIMETICKS: + OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value))); + break; + case SNMP_ASN1_TYPE_OCTET_STRING: + case SNMP_ASN1_TYPE_IPADDR: + case SNMP_ASN1_TYPE_OPAQUE: + OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); + len.value_value_len = varbind->value_len; + break; + case SNMP_ASN1_TYPE_OBJECT_ID: + OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t))); + break; + case SNMP_ASN1_TYPE_COUNTER64: + OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value)); + break; + default: + LWIP_ASSERT("Unknown variable type", 0); + break; + } + } + } + + return ERR_OK; +} + +static err_t +snmp_complete_outbound_frame(struct snmp_request *request) +{ + struct snmp_asn1_tlv tlv; + u16_t frame_size; + u8_t outbound_padding = 0; + + if (request->version == SNMP_VERSION_1) { + if (request->error_status != SNMP_ERR_NOERROR) { + /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ + switch (request->error_status) { + /* mapping of implementation specific "virtual" error codes + * (during processing of frame we already stored them in error_status field, + * so no need to check all varbinds here for those exceptions as suggested by RFC) */ + case SNMP_ERR_NOSUCHINSTANCE: + case SNMP_ERR_NOSUCHOBJECT: + case SNMP_ERR_ENDOFMIBVIEW: + request->error_status = SNMP_ERR_NOSUCHNAME; + break; + /* mapping according to RFC */ + case SNMP_ERR_WRONGVALUE: + case SNMP_ERR_WRONGENCODING: + case SNMP_ERR_WRONGTYPE: + case SNMP_ERR_WRONGLENGTH: + case SNMP_ERR_INCONSISTENTVALUE: + request->error_status = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_NOACCESS: + case SNMP_ERR_NOTWRITABLE: + case SNMP_ERR_NOCREATION: + case SNMP_ERR_INCONSISTENTNAME: + case SNMP_ERR_AUTHORIZATIONERROR: + request->error_status = SNMP_ERR_NOSUCHNAME; + break; + case SNMP_ERR_RESOURCEUNAVAILABLE: + case SNMP_ERR_COMMITFAILED: + case SNMP_ERR_UNDOFAILED: + default: + request->error_status = SNMP_ERR_GENERROR; + break; + } + } + } else { + if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { + /* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */ + switch (request->error_status) { + case SNMP_ERR_NOSUCHINSTANCE: + case SNMP_ERR_NOSUCHOBJECT: + case SNMP_ERR_ENDOFMIBVIEW: + request->error_status = SNMP_ERR_NOTWRITABLE; + break; + default: + break; + } + } + + if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { + /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ + LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); + return ERR_ARG; + } + } + + if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { + /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ + struct snmp_pbuf_stream inbound_stream; + OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); + OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) ); + snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0); + } + + frame_size = request->outbound_pbuf_stream.offset; + +#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO + /* Calculate padding for encryption */ + if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { + u8_t i; + outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07; + for (i = 0; i < outbound_padding; i++) { + snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0); + } + } +#endif + + /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ + OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); + +#if LWIP_SNMP_V3 + if (request->version == SNMP_VERSION_3) { + /* complete missing length in 'globalData' sequence */ + /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end + - request->outbound_msg_global_data_offset - 1 - 1); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset)); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); + + /* complete missing length in 'msgSecurityParameters' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end + - request->outbound_msg_security_parameters_str_offset - 1 - 1); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset)); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); + + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end + - request->outbound_msg_security_parameters_seq_offset - 1 - 1); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset)); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); + + /* complete missing length in scoped PDU sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset)); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); + } +#endif + + /* complete missing length in 'PDU' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, + frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ + OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); + OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); + + /* process and encode final error status */ + if (request->error_status != 0) { + u16_t len; + snmp_asn1_enc_s32t_cnt(request->error_status, &len); + if (len != 1) { + /* error, we only reserved one byte for it */ + return ERR_ARG; + } + OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); + OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); + + /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ + switch (request->error_status) { + case SNMP_ERR_TOOBIG: + snmp_stats.outtoobigs++; + break; + case SNMP_ERR_NOSUCHNAME: + snmp_stats.outnosuchnames++; + break; + case SNMP_ERR_BADVALUE: + snmp_stats.outbadvalues++; + break; + case SNMP_ERR_GENERROR: + default: + snmp_stats.outgenerrs++; + break; + } + + if (request->error_status == SNMP_ERR_TOOBIG) { + request->error_index = 0; /* defined by RFC 1157 */ + } else if (request->error_index == 0) { + /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ + request->error_index = request->inbound_varbind_enumerator.varbind_count; + } + } else { + if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { + snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; + } else { + snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; + } + } + + /* encode final error index*/ + if (request->error_index != 0) { + u16_t len; + snmp_asn1_enc_s32t_cnt(request->error_index, &len); + if (len != 1) { + /* error, we only reserved one byte for it */ + return ERR_VAL; + } + OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); + OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); + } + + /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); + OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ + OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); + + /* Authenticate response */ +#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO + /* Encrypt response */ + if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { + u8_t key[20]; + u8_t algo; + + /* complete missing length in PDU sequence */ + OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset)); + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding + - request->outbound_scoped_pdu_string_offset - 1 - 3); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); + + OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); + + OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, + request->msg_privacy_parameters, request->msg_authoritative_engine_boots, + request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT)); + } + + if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { + u8_t key[20]; + u8_t algo; + u8_t hmac[20]; + + OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); + OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), + request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); + OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); + + MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH); + OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, + request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); + OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream, + request->outbound_msg_authentication_parameters_offset)); + + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); + OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv)); + OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream, + request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); + } +#endif + + pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding); + + snmp_stats.outgetresponses++; + snmp_stats.outpkts++; + + return ERR_OK; +} + +static void +snmp_execute_write_callbacks(struct snmp_request *request) +{ + struct snmp_varbind_enumerator inbound_varbind_enumerator; + struct snmp_varbind vb; + + snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); + vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */ + + while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) { + snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg); + } +} + + +/* ----------------------------------------------------------------------- */ +/* VarBind enumerator methods */ +/* ----------------------------------------------------------------------- */ + +void +snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length) +{ + snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length); + enumerator->varbind_count = 0; +} + +#define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) +#define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) + +snmp_vb_enumerator_err_t +snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind) +{ + struct snmp_asn1_tlv tlv; + u16_t varbind_len; + err_t err; + + if (enumerator->pbuf_stream.length == 0) + { + return SNMP_VB_ENUMERATOR_ERR_EOVB; + } + enumerator->varbind_count++; + + /* decode varbind itself (parent container of a varbind) */ + VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); + VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length)); + varbind_len = tlv.value_len; + + /* decode varbind name (object id) */ + VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); + VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length)); + + VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN)); + varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv); + + /* decode varbind value (object id) */ + VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); + VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length)); + varbind->type = tlv.type; + + /* shall the value be decoded ? */ + if (varbind->value != NULL) { + switch (varbind->type) { + case SNMP_ASN1_TYPE_INTEGER: + VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value)); + varbind->value_len = sizeof(s32_t*); + break; + case SNMP_ASN1_TYPE_COUNTER: + case SNMP_ASN1_TYPE_GAUGE: + case SNMP_ASN1_TYPE_TIMETICKS: + VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); + varbind->value_len = sizeof(u32_t*); + break; + case SNMP_ASN1_TYPE_OCTET_STRING: + case SNMP_ASN1_TYPE_OPAQUE: + err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE); + if (err == ERR_MEM) { + return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; + } + VB_PARSE_ASSERT(err == ERR_OK); + break; + case SNMP_ASN1_TYPE_NULL: + varbind->value_len = 0; + break; + case SNMP_ASN1_TYPE_OBJECT_ID: + /* misuse tlv.length_len as OID_length transporter */ + err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN); + if (err == ERR_MEM) { + return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; + } + VB_PARSE_ASSERT(err == ERR_OK); + varbind->value_len = tlv.length_len * sizeof(u32_t); + break; + case SNMP_ASN1_TYPE_IPADDR: + if (tlv.value_len == 4) { + /* must be exactly 4 octets! */ + VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE)); + } else { + VB_PARSE_ASSERT(0); + } + break; + case SNMP_ASN1_TYPE_COUNTER64: + VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); + varbind->value_len = 2 * sizeof(u32_t*); + break; + default: + VB_PARSE_ASSERT(0); + break; + } + } else { + snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len); + varbind->value_len = tlv.value_len; + } + + return SNMP_VB_ENUMERATOR_ERR_OK; +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.h b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.h new file mode 100644 index 0000000000..2d01ef36eb --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_msg.h @@ -0,0 +1,194 @@ +/** + * @file + * SNMP Agent message handling structures (internal API, do not use in client code). + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + * Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_MSG_H +#define LWIP_HDR_APPS_SNMP_MSG_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP + +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "snmp_pbuf_stream.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#if LWIP_SNMP_V3 +#include "snmpv3_priv.h" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to + this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't + work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +/* version defines used in PDU */ +#define SNMP_VERSION_1 0 +#define SNMP_VERSION_2c 1 +#define SNMP_VERSION_3 3 + +struct snmp_varbind_enumerator +{ + struct snmp_pbuf_stream pbuf_stream; + u16_t varbind_count; +}; + +typedef enum { + SNMP_VB_ENUMERATOR_ERR_OK = 0, + SNMP_VB_ENUMERATOR_ERR_EOVB = 1, + SNMP_VB_ENUMERATOR_ERR_ASN1ERROR = 2, + SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH = 3 +} snmp_vb_enumerator_err_t; + +void snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length); +snmp_vb_enumerator_err_t snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind); + +struct snmp_request +{ + /* Communication handle */ + void *handle; + /* source IP address */ + const ip_addr_t *source_ip; + /* source UDP port */ + u16_t source_port; + /* incoming snmp version */ + u8_t version; + /* community name (zero terminated) */ + u8_t community[SNMP_MAX_COMMUNITY_STR_LEN + 1]; + /* community string length (exclusive zero term) */ + u16_t community_strlen; + /* request type */ + u8_t request_type; + /* request ID */ + s32_t request_id; + /* error status */ + s32_t error_status; + /* error index */ + s32_t error_index; + /* non-repeaters (getBulkRequest (SNMPv2c)) */ + s32_t non_repeaters; + /* max-repetitions (getBulkRequest (SNMPv2c)) */ + s32_t max_repetitions; + +#if LWIP_SNMP_V3 + s32_t msg_id; + s32_t msg_max_size; + u8_t msg_flags; + s32_t msg_security_model; + u8_t msg_authoritative_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH]; + u8_t msg_authoritative_engine_id_len; + s32_t msg_authoritative_engine_boots; + s32_t msg_authoritative_engine_time; + u8_t msg_user_name[SNMP_V3_MAX_USER_LENGTH]; + u8_t msg_user_name_len; + u8_t msg_authentication_parameters[SNMP_V3_MAX_AUTH_PARAM_LENGTH]; + u8_t msg_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH]; + u8_t context_engine_id[SNMP_V3_MAX_ENGINE_ID_LENGTH]; + u8_t context_engine_id_len; + u8_t context_name[SNMP_V3_MAX_ENGINE_ID_LENGTH]; + u8_t context_name_len; +#endif + + struct pbuf *inbound_pbuf; + struct snmp_varbind_enumerator inbound_varbind_enumerator; + u16_t inbound_varbind_offset; + u16_t inbound_varbind_len; + u16_t inbound_padding_len; + + struct pbuf *outbound_pbuf; + struct snmp_pbuf_stream outbound_pbuf_stream; + u16_t outbound_pdu_offset; + u16_t outbound_error_status_offset; + u16_t outbound_error_index_offset; + u16_t outbound_varbind_offset; +#if LWIP_SNMP_V3 + u16_t outbound_msg_global_data_offset; + u16_t outbound_msg_global_data_end; + u16_t outbound_msg_security_parameters_str_offset; + u16_t outbound_msg_security_parameters_seq_offset; + u16_t outbound_msg_security_parameters_end; + u16_t outbound_msg_authentication_parameters_offset; + u16_t outbound_scoped_pdu_seq_offset; + u16_t outbound_scoped_pdu_string_offset; +#endif + + u8_t value_buffer[SNMP_MAX_VALUE_SIZE]; +}; + +/** A helper struct keeping length information about varbinds */ +struct snmp_varbind_len +{ + u8_t vb_len_len; + u16_t vb_value_len; + u8_t oid_len_len; + u16_t oid_value_len; + u8_t value_len_len; + u16_t value_value_len; +}; + +/** Agent community string */ +extern const char *snmp_community; +/** Agent community string for write access */ +extern const char *snmp_community_write; +/** handle for sending traps */ +extern void* snmp_traps_handle; + +void snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port); +err_t snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port); +u8_t snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result); +err_t snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len); +err_t snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_MSG_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_netconn.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_netconn.c new file mode 100644 index 0000000000..24c3e26531 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_netconn.c @@ -0,0 +1,121 @@ +/** + * @file + * SNMP netconn frontend. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP && SNMP_USE_NETCONN + +#include +#include "lwip/api.h" +#include "lwip/ip.h" +#include "lwip/udp.h" +#include "snmp_msg.h" +#include "lwip/sys.h" + +/** SNMP netconn API worker thread */ +static void +snmp_netconn_thread(void *arg) +{ + struct netconn *conn; + struct netbuf *buf; + err_t err; + LWIP_UNUSED_ARG(arg); + + /* Bind to SNMP port with default IP address */ +#if LWIP_IPV6 + conn = netconn_new(NETCONN_UDP_IPV6); + netconn_bind(conn, IP6_ADDR_ANY, SNMP_IN_PORT); +#else /* LWIP_IPV6 */ + conn = netconn_new(NETCONN_UDP); + netconn_bind(conn, IP4_ADDR_ANY, SNMP_IN_PORT); +#endif /* LWIP_IPV6 */ + LWIP_ERROR("snmp_netconn: invalid conn", (conn != NULL), return;); + + snmp_traps_handle = conn; + + do { + err = netconn_recv(conn, &buf); + + if (err == ERR_OK) { + snmp_receive(conn, buf->p, &buf->addr, buf->port); + } + + if (buf != NULL) { + netbuf_delete(buf); + } + } while(1); +} + +err_t +snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port) +{ + err_t result; + struct netbuf buf; + + memset(&buf, 0, sizeof(buf)); + buf.p = p; + result = netconn_sendto((struct netconn*)handle, &buf, dst, port); + + return result; +} + +u8_t +snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result) +{ + struct netconn* conn = (struct netconn*)handle; + struct netif *dst_if; + const ip_addr_t* dst_ip; + + LWIP_UNUSED_ARG(conn); /* unused in case of IPV4 only configuration */ + + ip_route_get_local_ip(&conn->pcb.udp->local_ip, dst, dst_if, dst_ip); + + if ((dst_if != NULL) && (dst_ip != NULL)) { + ip_addr_copy(*result, *dst_ip); + return 1; + } else { + return 0; + } +} + +/** + * Starts SNMP Agent. + */ +void +snmp_init(void) +{ + sys_thread_new("snmp_netconn", snmp_netconn_thread, NULL, SNMP_STACK_SIZE, SNMP_THREAD_PRIO); +} + +#endif /* LWIP_SNMP && SNMP_USE_NETCONN */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.c new file mode 100644 index 0000000000..3c1217d710 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.c @@ -0,0 +1,156 @@ +/** + * @file + * SNMP pbuf stream wrapper implementation (internal API, do not use in client code). + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "snmp_pbuf_stream.h" +#include "lwip/def.h" +#include + +err_t +snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length) +{ + pbuf_stream->offset = offset; + pbuf_stream->length = length; + pbuf_stream->pbuf = p; + + return ERR_OK; +} + +err_t +snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data) +{ + if (pbuf_stream->length == 0) { + return ERR_BUF; + } + + if (pbuf_copy_partial(pbuf_stream->pbuf, data, 1, pbuf_stream->offset) == 0) { + return ERR_BUF; + } + + pbuf_stream->offset++; + pbuf_stream->length--; + + return ERR_OK; +} + +err_t +snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data) +{ + return snmp_pbuf_stream_writebuf(pbuf_stream, &data, 1); +} + +err_t +snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len) +{ + if (pbuf_stream->length < buf_len) { + return ERR_BUF; + } + + if (pbuf_take_at(pbuf_stream->pbuf, buf, buf_len, pbuf_stream->offset) != ERR_OK) { + return ERR_BUF; + } + + pbuf_stream->offset += buf_len; + pbuf_stream->length -= buf_len; + + return ERR_OK; +} + +err_t +snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len) +{ + + if ((pbuf_stream == NULL) || (target_pbuf_stream == NULL)) { + return ERR_ARG; + } + if ((len > pbuf_stream->length) || (len > target_pbuf_stream->length)) { + return ERR_ARG; + } + + if (len == 0) { + len = LWIP_MIN(pbuf_stream->length, target_pbuf_stream->length); + } + + while (len > 0) { + u16_t chunk_len; + err_t err; + u16_t target_offset; + struct pbuf* pbuf = pbuf_skip(pbuf_stream->pbuf, pbuf_stream->offset, &target_offset); + + if ((pbuf == NULL) || (pbuf->len == 0)) { + return ERR_BUF; + } + + chunk_len = LWIP_MIN(len, pbuf->len); + err = snmp_pbuf_stream_writebuf(target_pbuf_stream, &((u8_t*)pbuf->payload)[target_offset], chunk_len); + if (err != ERR_OK) { + return err; + } + + pbuf_stream->offset += chunk_len; + pbuf_stream->length -= chunk_len; + len -= chunk_len; + } + + return ERR_OK; +} + +err_t +snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset) +{ + if ((offset < 0) || (offset > pbuf_stream->length)) { + /* we cannot seek backwards or forward behind stream end */ + return ERR_ARG; + } + + pbuf_stream->offset += (u16_t)offset; + pbuf_stream->length -= (u16_t)offset; + + return ERR_OK; +} + +err_t +snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset) +{ + s32_t rel_offset = offset - pbuf_stream->offset; + return snmp_pbuf_stream_seek(pbuf_stream, rel_offset); +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.h b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.h new file mode 100644 index 0000000000..9778de774e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_pbuf_stream.h @@ -0,0 +1,73 @@ +/** + * @file + * SNMP pbuf stream wrapper (internal API, do not use in client code). + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_PBUF_STREAM_H +#define LWIP_HDR_APPS_SNMP_PBUF_STREAM_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP + +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct snmp_pbuf_stream +{ + struct pbuf* pbuf; + u16_t offset; + u16_t length; +}; + +err_t snmp_pbuf_stream_init(struct snmp_pbuf_stream* pbuf_stream, struct pbuf* p, u16_t offset, u16_t length); +err_t snmp_pbuf_stream_read(struct snmp_pbuf_stream* pbuf_stream, u8_t* data); +err_t snmp_pbuf_stream_write(struct snmp_pbuf_stream* pbuf_stream, u8_t data); +err_t snmp_pbuf_stream_writebuf(struct snmp_pbuf_stream* pbuf_stream, const void* buf, u16_t buf_len); +err_t snmp_pbuf_stream_writeto(struct snmp_pbuf_stream* pbuf_stream, struct snmp_pbuf_stream* target_pbuf_stream, u16_t len); +err_t snmp_pbuf_stream_seek(struct snmp_pbuf_stream* pbuf_stream, s32_t offset); +err_t snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream* pbuf_stream, u32_t offset); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_PBUF_STREAM_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_raw.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_raw.c new file mode 100644 index 0000000000..4a40864fc9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_raw.c @@ -0,0 +1,100 @@ +/** + * @file + * SNMP RAW API frontend. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + */ + +#include "lwip/apps/snmp_opts.h" +#include "lwip/ip_addr.h" + +#if LWIP_SNMP && SNMP_USE_RAW + +#include "lwip/udp.h" +#include "lwip/ip.h" +#include "snmp_msg.h" + +/* lwIP UDP receive callback function */ +static void +snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + LWIP_UNUSED_ARG(arg); + + snmp_receive(pcb, p, addr, port); + + pbuf_free(p); +} + +err_t +snmp_sendto(void *handle, struct pbuf *p, const ip_addr_t *dst, u16_t port) +{ + return udp_sendto((struct udp_pcb*)handle, p, dst, port); +} + +u8_t +snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result) +{ + struct udp_pcb* udp_pcb = (struct udp_pcb*)handle; + struct netif *dst_if; + const ip_addr_t* dst_ip; + + LWIP_UNUSED_ARG(udp_pcb); /* unused in case of IPV4 only configuration */ + + ip_route_get_local_ip(&udp_pcb->local_ip, dst, dst_if, dst_ip); + + if ((dst_if != NULL) && (dst_ip != NULL)) { + ip_addr_copy(*result, *dst_ip); + return 1; + } else { + return 0; + } +} + +/** + * @ingroup snmp_core + * Starts SNMP Agent. + * Allocates UDP pcb and binds it to IP_ANY_TYPE port 161. + */ +void +snmp_init(void) +{ + err_t err; + + struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;); + + snmp_traps_handle = snmp_pcb; + + udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT); + err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT); + LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;); +} + +#endif /* LWIP_SNMP && SNMP_USE_RAW */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_scalar.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_scalar.c new file mode 100644 index 0000000000..136c9eccd0 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_scalar.c @@ -0,0 +1,220 @@ +/** + * @file + * SNMP scalar node support implementation. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_scalar.h" +#include "lwip/apps/snmp_core.h" + +static s16_t snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value); +static snmp_err_t snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value); +static snmp_err_t snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value); + +snmp_err_t +snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + const struct snmp_scalar_node* scalar_node = (const struct snmp_scalar_node*)(const void*)instance->node; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + /* scalar only has one dedicated instance: .0 */ + if ((instance->instance_oid.len != 1) || (instance->instance_oid.id[0] != 0)) { + return SNMP_ERR_NOSUCHINSTANCE; + } + + instance->access = scalar_node->access; + instance->asn1_type = scalar_node->asn1_type; + instance->get_value = scalar_node->get_value; + instance->set_test = scalar_node->set_test; + instance->set_value = scalar_node->set_value; + return SNMP_ERR_NOERROR; +} + +snmp_err_t +snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + /* because our only instance is .0 we can only return a next instance if no instance oid is passed */ + if (instance->instance_oid.len == 0) { + instance->instance_oid.len = 1; + instance->instance_oid.id[0] = 0; + + return snmp_scalar_get_instance(root_oid, root_oid_len, instance); + } + + return SNMP_ERR_NOSUCHINSTANCE; +} + + +snmp_err_t +snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + if ((instance->instance_oid.len == 2) && (instance->instance_oid.id[1] == 0)) { + const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; + const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes; + u32_t i = 0; + + while (i < array_node->array_node_count) { + if (array_node_def->oid == instance->instance_oid.id[0]) { + break; + } + + array_node_def++; + i++; + } + + if (i < array_node->array_node_count) { + instance->access = array_node_def->access; + instance->asn1_type = array_node_def->asn1_type; + instance->get_value = snmp_scalar_array_get_value; + instance->set_test = snmp_scalar_array_set_test; + instance->set_value = snmp_scalar_array_set_value; + instance->reference.const_ptr = array_node_def; + + return SNMP_ERR_NOERROR; + } + } + + return SNMP_ERR_NOSUCHINSTANCE; +} + +snmp_err_t +snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; + const struct snmp_scalar_array_node_def* array_node_def = array_node->array_nodes; + const struct snmp_scalar_array_node_def* result = NULL; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + if ((instance->instance_oid.len == 0) && (array_node->array_node_count > 0)) { + /* return node with lowest OID */ + u16_t i = 0; + + result = array_node_def; + array_node_def++; + + for (i = 1; i < array_node->array_node_count; i++) { + if (array_node_def->oid < result->oid) { + result = array_node_def; + } + array_node_def++; + } + } else if (instance->instance_oid.len >= 1) { + if (instance->instance_oid.len == 1) { + /* if we have the requested OID we return its instance, otherwise we search for the next available */ + u16_t i = 0; + while (i < array_node->array_node_count) { + if (array_node_def->oid == instance->instance_oid.id[0]) { + result = array_node_def; + break; + } + + array_node_def++; + i++; + } + } + if (result == NULL) { + u32_t oid_dist = 0xFFFFFFFFUL; + u16_t i = 0; + array_node_def = array_node->array_nodes; /* may be already at the end when if case before was executed without result -> reinitialize to start */ + while (i < array_node->array_node_count) { + if ((array_node_def->oid > instance->instance_oid.id[0]) && + ((u32_t)(array_node_def->oid - instance->instance_oid.id[0]) < oid_dist)) { + result = array_node_def; + oid_dist = array_node_def->oid - instance->instance_oid.id[0]; + } + + array_node_def++; + i++; + } + } + } + + if (result == NULL) { + /* nothing to return */ + return SNMP_ERR_NOSUCHINSTANCE; + } + + instance->instance_oid.len = 2; + instance->instance_oid.id[0] = result->oid; + instance->instance_oid.id[1] = 0; + + instance->access = result->access; + instance->asn1_type = result->asn1_type; + instance->get_value = snmp_scalar_array_get_value; + instance->set_test = snmp_scalar_array_set_test; + instance->set_value = snmp_scalar_array_set_value; + instance->reference.const_ptr = result; + + return SNMP_ERR_NOERROR; +} + +static s16_t +snmp_scalar_array_get_value(struct snmp_node_instance* instance, void* value) +{ + const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; + const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; + + return array_node->get_value(array_node_def, value); +} + +static snmp_err_t +snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value) +{ + const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; + const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; + + return array_node->set_test(array_node_def, value_len, value); +} + +static snmp_err_t +snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value) +{ + const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node; + const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr; + + return array_node->set_value(array_node_def, value_len, value); +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_table.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_table.c new file mode 100644 index 0000000000..63ca595633 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_table.c @@ -0,0 +1,343 @@ +/** + * @file + * SNMP table support implementation. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_core.h" +#include "lwip/apps/snmp_table.h" +#include + +snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; + const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ + /* fixed row entry always has oid 1 */ + if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { + /* search column */ + const struct snmp_table_col_def* col_def = table_node->columns; + u16_t i = table_node->column_count; + while (i > 0) { + if (col_def->index == instance->instance_oid.id[1]) { + break; + } + + col_def++; + i--; + } + + if (i > 0) { + /* everything may be overwritten by get_cell_instance_method() in order to implement special handling for single columns/cells */ + instance->asn1_type = col_def->asn1_type; + instance->access = col_def->access; + instance->get_value = table_node->get_value; + instance->set_test = table_node->set_test; + instance->set_value = table_node->set_value; + + ret = table_node->get_cell_instance( + &(instance->instance_oid.id[1]), + &(instance->instance_oid.id[2]), + instance->instance_oid.len-2, + instance); + } + } + + return ret; +} + +snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + const struct snmp_table_node* table_node = (const struct snmp_table_node*)(const void*)instance->node; + const struct snmp_table_col_def* col_def; + struct snmp_obj_id row_oid; + u32_t column = 0; + snmp_err_t result; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + /* check that first part of id is 0 or 1, referencing fixed row entry */ + if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { + return SNMP_ERR_NOSUCHINSTANCE; + } + if (instance->instance_oid.len > 1) { + column = instance->instance_oid.id[1]; + } + if (instance->instance_oid.len > 2) { + snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); + } else { + row_oid.len = 0; + } + + instance->get_value = table_node->get_value; + instance->set_test = table_node->set_test; + instance->set_value = table_node->set_value; + + /* resolve column and value */ + do { + u16_t i; + const struct snmp_table_col_def* next_col_def = NULL; + col_def = table_node->columns; + + for (i = 0; i < table_node->column_count; i++) { + if (col_def->index == column) { + next_col_def = col_def; + break; + } else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index))) { + next_col_def = col_def; + } + col_def++; + } + + if (next_col_def == NULL) { + /* no further column found */ + return SNMP_ERR_NOSUCHINSTANCE; + } + + instance->asn1_type = next_col_def->asn1_type; + instance->access = next_col_def->access; + + result = table_node->get_next_cell_instance( + &next_col_def->index, + &row_oid, + instance); + + if (result == SNMP_ERR_NOERROR) { + col_def = next_col_def; + break; + } + + row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ + column = next_col_def->index + 1; + } while (1); + + /* build resulting oid */ + instance->instance_oid.len = 2; + instance->instance_oid.id[0] = 1; + instance->instance_oid.id[1] = col_def->index; + snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); + + return SNMP_ERR_NOERROR; +} + + +snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + snmp_err_t ret = SNMP_ERR_NOSUCHINSTANCE; + const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + /* check min. length (fixed row entry definition, column, row instance oid with at least one entry */ + /* fixed row entry always has oid 1 */ + if ((instance->instance_oid.len >= 3) && (instance->instance_oid.id[0] == 1)) { + ret = table_node->get_cell_value( + &(instance->instance_oid.id[1]), + &(instance->instance_oid.id[2]), + instance->instance_oid.len-2, + &instance->reference, + &instance->reference_len); + + if (ret == SNMP_ERR_NOERROR) { + /* search column */ + const struct snmp_table_simple_col_def* col_def = table_node->columns; + u32_t i = table_node->column_count; + while (i > 0) { + if (col_def->index == instance->instance_oid.id[1]) { + break; + } + + col_def++; + i--; + } + + if (i > 0) { + instance->asn1_type = col_def->asn1_type; + instance->access = SNMP_NODE_INSTANCE_READ_ONLY; + instance->set_test = NULL; + instance->set_value = NULL; + + switch (col_def->data_type) { + case SNMP_VARIANT_VALUE_TYPE_U32: + instance->get_value = snmp_table_extract_value_from_u32ref; + break; + case SNMP_VARIANT_VALUE_TYPE_S32: + instance->get_value = snmp_table_extract_value_from_s32ref; + break; + case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ + case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: + instance->get_value = snmp_table_extract_value_from_refconstptr; + break; + default: + LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); + return SNMP_ERR_GENERROR; + } + + ret = SNMP_ERR_NOERROR; + } else { + ret = SNMP_ERR_NOSUCHINSTANCE; + } + } + } + + return ret; +} + +snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)(const void*)instance->node; + const struct snmp_table_simple_col_def* col_def; + struct snmp_obj_id row_oid; + u32_t column = 0; + snmp_err_t result; + + LWIP_UNUSED_ARG(root_oid); + LWIP_UNUSED_ARG(root_oid_len); + + /* check that first part of id is 0 or 1, referencing fixed row entry */ + if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1)) { + return SNMP_ERR_NOSUCHINSTANCE; + } + if (instance->instance_oid.len > 1) { + column = instance->instance_oid.id[1]; + } + if (instance->instance_oid.len > 2) { + snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2); + } else { + row_oid.len = 0; + } + + /* resolve column and value */ + do { + u32_t i; + const struct snmp_table_simple_col_def* next_col_def = NULL; + col_def = table_node->columns; + + for (i = 0; i < table_node->column_count; i++) { + if (col_def->index == column) { + next_col_def = col_def; + break; + } else if ((col_def->index > column) && ((next_col_def == NULL) || + (col_def->index < next_col_def->index))) { + next_col_def = col_def; + } + col_def++; + } + + if (next_col_def == NULL) { + /* no further column found */ + return SNMP_ERR_NOSUCHINSTANCE; + } + + result = table_node->get_next_cell_instance_and_value( + &next_col_def->index, + &row_oid, + &instance->reference, + &instance->reference_len); + + if (result == SNMP_ERR_NOERROR) { + col_def = next_col_def; + break; + } + + row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */ + column = next_col_def->index + 1; + } + while (1); + + instance->asn1_type = col_def->asn1_type; + instance->access = SNMP_NODE_INSTANCE_READ_ONLY; + instance->set_test = NULL; + instance->set_value = NULL; + + switch (col_def->data_type) { + case SNMP_VARIANT_VALUE_TYPE_U32: + instance->get_value = snmp_table_extract_value_from_u32ref; + break; + case SNMP_VARIANT_VALUE_TYPE_S32: + instance->get_value = snmp_table_extract_value_from_s32ref; + break; + case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */ + case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: + instance->get_value = snmp_table_extract_value_from_refconstptr; + break; + default: + LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type)); + return SNMP_ERR_GENERROR; + } + + /* build resulting oid */ + instance->instance_oid.len = 2; + instance->instance_oid.id[0] = 1; + instance->instance_oid.id[1] = col_def->index; + snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len); + + return SNMP_ERR_NOERROR; +} + + +s16_t +snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value) +{ + s32_t *dst = (s32_t*)value; + *dst = instance->reference.s32; + return sizeof(*dst); +} + +s16_t +snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value) +{ + u32_t *dst = (u32_t*)value; + *dst = instance->reference.u32; + return sizeof(*dst); +} + +s16_t +snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value) +{ + MEMCPY(value, instance->reference.const_ptr, instance->reference_len); + return (u16_t)instance->reference_len; +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_threadsync.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_threadsync.c new file mode 100644 index 0000000000..204f265dc8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_threadsync.c @@ -0,0 +1,219 @@ +/** + * @file + * SNMP thread synchronization implementation. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dirk Ziegelmeier + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_threadsync.h" +#include "lwip/apps/snmp_core.h" +#include "lwip/sys.h" +#include + +static void +call_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn) +{ + sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex); + call_data->threadsync_node->instance->sync_fn(fn, call_data); + sys_sem_wait(&call_data->threadsync_node->instance->sem); + sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex); +} + +static void +threadsync_get_value_synced(void *ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + + call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static s16_t +threadsync_get_value(struct snmp_node_instance* instance, void* value) +{ + struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; + + call_data->arg1.value = value; + call_synced_function(call_data, threadsync_get_value_synced); + + return call_data->retval.s16; +} + +static void +threadsync_set_test_synced(void *ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + + call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static snmp_err_t +threadsync_set_test(struct snmp_node_instance* instance, u16_t len, void *value) +{ + struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; + + call_data->arg1.value = value; + call_data->arg2.len = len; + call_synced_function(call_data, threadsync_set_test_synced); + + return call_data->retval.err; +} + +static void +threadsync_set_value_synced(void *ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + + call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static snmp_err_t +threadsync_set_value(struct snmp_node_instance* instance, u16_t len, void *value) +{ + struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; + + call_data->arg1.value = value; + call_data->arg2.len = len; + call_synced_function(call_data, threadsync_set_value_synced); + + return call_data->retval.err; +} + +static void +threadsync_release_instance_synced(void* ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + + call_data->proxy_instance.release_instance(&call_data->proxy_instance); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static void +threadsync_release_instance(struct snmp_node_instance *instance) +{ + struct threadsync_data *call_data = (struct threadsync_data*)instance->reference.ptr; + + if (call_data->proxy_instance.release_instance != NULL) { + call_synced_function(call_data, threadsync_release_instance_synced); + } +} + +static void +get_instance_synced(void* ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node; + + call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static void +get_next_instance_synced(void* ctx) +{ + struct threadsync_data *call_data = (struct threadsync_data*)ctx; + const struct snmp_leaf_node *leaf = (const struct snmp_leaf_node*)(const void*)call_data->proxy_instance.node; + + call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance); + + sys_sem_signal(&call_data->threadsync_node->instance->sem); +} + +static snmp_err_t +do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn) +{ + const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node; + struct threadsync_data *call_data = &threadsync_node->instance->data; + + if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) { + LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID")); + return SNMP_ERR_NOSUCHINSTANCE; + } + + memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance)); + + instance->reference.ptr = call_data; + snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len); + + call_data->proxy_instance.node = &threadsync_node->target->node; + call_data->threadsync_node = threadsync_node; + + call_data->arg1.root_oid = root_oid; + call_data->arg2.root_oid_len = root_oid_len; + call_synced_function(call_data, fn); + + if (call_data->retval.err == SNMP_ERR_NOERROR) { + instance->access = call_data->proxy_instance.access; + instance->asn1_type = call_data->proxy_instance.asn1_type; + instance->release_instance = threadsync_release_instance; + instance->get_value = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL; + instance->set_value = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL; + instance->set_test = (call_data->proxy_instance.set_test != NULL)? threadsync_set_test : NULL; + snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len); + } + + return call_data->retval.err; +} + +snmp_err_t +snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + return do_sync(root_oid, root_oid_len, instance, get_instance_synced); +} + +snmp_err_t +snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance) +{ + return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced); +} + +/** Initializes thread synchronization instance */ +void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn) +{ + err_t err = sys_mutex_new(&instance->sem_usage_mutex); + LWIP_ASSERT("Failed to set up mutex", err == ERR_OK); + err = sys_sem_new(&instance->sem, 0); + LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK); + instance->sync_fn = sync_fn; +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_traps.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_traps.c new file mode 100644 index 0000000000..0d2df64991 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmp_traps.c @@ -0,0 +1,445 @@ +/** + * @file + * SNMPv1 traps implementation. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * Christiaan Simons + * + */ + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "lwip/snmp.h" +#include "lwip/sys.h" +#include "lwip/apps/snmp.h" +#include "lwip/apps/snmp_core.h" +#include "snmp_msg.h" +#include "snmp_asn1.h" +#include "snmp_core_priv.h" + +struct snmp_msg_trap +{ + /* source enterprise ID (sysObjectID) */ + const struct snmp_obj_id *enterprise; + /* source IP address, raw network order format */ + ip_addr_t sip; + /* generic trap code */ + u32_t gen_trap; + /* specific trap code */ + u32_t spc_trap; + /* timestamp */ + u32_t ts; + /* snmp_version */ + u32_t snmp_version; + + /* output trap lengths used in ASN encoding */ + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding sequence length */ + u16_t seqlen; + /* encoding varbinds sequence length */ + u16_t vbseqlen; +}; + +static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds); +static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len); +static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); +static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds); + +/** Agent community string for sending traps */ +extern const char *snmp_community_trap; + +void* snmp_traps_handle; + +struct snmp_trap_dst +{ + /* destination IP address in network order */ + ip_addr_t dip; + /* set to 0 when disabled, >0 when enabled */ + u8_t enable; +}; +static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; + +static u8_t snmp_auth_traps_enabled = 0; + +/** + * @ingroup snmp_traps + * Sets enable switch for this trap destination. + * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 + * @param enable switch if 0 destination is disabled >0 enabled. + */ +void +snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) +{ + if (dst_idx < SNMP_TRAP_DESTINATIONS) { + trap_dst[dst_idx].enable = enable; + } +} + +/** + * @ingroup snmp_traps + * Sets IPv4 address for this trap destination. + * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 + * @param dst IPv4 address in host order. + */ +void +snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst) +{ + if (dst_idx < SNMP_TRAP_DESTINATIONS) { + ip_addr_set(&trap_dst[dst_idx].dip, dst); + } +} + +/** + * @ingroup snmp_traps + * Enable/disable authentication traps + */ +void +snmp_set_auth_traps_enabled(u8_t enable) +{ + snmp_auth_traps_enabled = enable; +} + +/** + * @ingroup snmp_traps + * Get authentication traps enabled state + */ +u8_t +snmp_get_auth_traps_enabled(void) +{ + return snmp_auth_traps_enabled; +} + + +/** + * @ingroup snmp_traps + * Sends a generic or enterprise specific trap message. + * + * @param eoid points to enterprise object identifier + * @param generic_trap is the trap code + * @param specific_trap used for enterprise traps when generic_trap == 6 + * @param varbinds linked list of varbinds to be sent + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the use of the enterprise identifier field + * is per RFC1215. + * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps + * and .iso.org.dod.internet.private.enterprises.yourenterprise + * (sysObjectID) for specific traps. + */ +err_t +snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) +{ + struct snmp_msg_trap trap_msg; + struct snmp_trap_dst *td; + struct pbuf *p; + u16_t i, tot_len; + err_t err = ERR_OK; + + trap_msg.snmp_version = 0; + + for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) { + if ((td->enable != 0) && !ip_addr_isany(&td->dip)) { + /* lookup current source address for this dst */ + if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) { + if (eoid == NULL) { + trap_msg.enterprise = snmp_get_device_enterprise_oid(); + } else { + trap_msg.enterprise = eoid; + } + + trap_msg.gen_trap = generic_trap; + if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) { + trap_msg.spc_trap = specific_trap; + } else { + trap_msg.spc_trap = 0; + } + + MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts); + + /* pass 0, calculate length fields */ + tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds); + tot_len = snmp_trap_header_sum(&trap_msg, tot_len); + + /* allocate pbuf(s) */ + p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM); + if (p != NULL) { + struct snmp_pbuf_stream pbuf_stream; + snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len); + + /* pass 1, encode packet ino the pbuf(s) */ + snmp_trap_header_enc(&trap_msg, &pbuf_stream); + snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds); + + snmp_stats.outtraps++; + snmp_stats.outpkts++; + + /** send to the TRAP destination */ + snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT); + pbuf_free(p); + } else { + err = ERR_MEM; + } + } else { + /* routing error */ + err = ERR_RTE; + } + } + } + return err; +} + +/** + * @ingroup snmp_traps + * Send generic SNMP trap + */ +err_t +snmp_send_trap_generic(s32_t generic_trap) +{ + static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } }; + return snmp_send_trap(&oid, generic_trap, 0, NULL); +} + +/** + * @ingroup snmp_traps + * Send specific SNMP trap with variable bindings + */ +err_t +snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds) +{ + return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds); +} + +/** + * @ingroup snmp_traps + * Send coldstart trap + */ +void +snmp_coldstart_trap(void) +{ + snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART); +} + +/** + * @ingroup snmp_traps + * Send authentication failure trap (used internally by agent) + */ +void +snmp_authfail_trap(void) +{ + if (snmp_auth_traps_enabled != 0) { + snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE); + } +} + +static u16_t +snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds) +{ + struct snmp_varbind *varbind; + u16_t tot_len; + u8_t tot_len_len; + + tot_len = 0; + varbind = varbinds; + while (varbind != NULL) { + struct snmp_varbind_len len; + + if (snmp_varbind_length(varbind, &len) == ERR_OK) { + tot_len += 1 + len.vb_len_len + len.vb_value_len; + } + + varbind = varbind->next; + } + + trap->vbseqlen = tot_len; + snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len); + tot_len += 1 + tot_len_len; + + return tot_len; +} + +/** + * Sums trap header field lengths from tail to head and + * returns trap_header_lengths for second encoding pass. + * + * @param trap Trap message + * @param vb_len varbind-list length + * @return the required length for encoding the trap header + */ +static u16_t +snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) +{ + u16_t tot_len; + u16_t len; + u8_t lenlen; + + tot_len = vb_len; + + snmp_asn1_enc_u32t_cnt(trap->ts, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + if (IP_IS_V6_VAL(trap->sip)) { +#if LWIP_IPV6 + len = sizeof(ip_2_ip6(&trap->sip)->addr); +#endif + } else { +#if LWIP_IPV4 + len = sizeof(ip_2_ip4(&trap->sip)->addr); +#endif + } + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + trap->pdulen = tot_len; + snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen); + tot_len += 1 + lenlen; + + trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF); + snmp_asn1_enc_length_cnt(trap->comlen, &lenlen); + tot_len += 1 + lenlen + trap->comlen; + + snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len); + snmp_asn1_enc_length_cnt(len, &lenlen); + tot_len += 1 + len + lenlen; + + trap->seqlen = tot_len; + snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen); + tot_len += 1 + lenlen; + + return tot_len; +} + +static void +snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds) +{ + struct snmp_asn1_tlv tlv; + struct snmp_varbind *varbind; + + varbind = varbinds; + + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + + while (varbind != NULL) { + snmp_append_outbound_varbind(pbuf_stream, varbind); + + varbind = varbind->next; + } +} + +/** + * Encodes trap header from head to tail. + */ +static void +snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) +{ + struct snmp_asn1_tlv tlv; + + /* 'Message' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + + /* version */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version); + + /* community */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen); + + /* 'PDU' sequence */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + + /* object ID */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0); + snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len); + + /* IP addr */ + if (IP_IS_V6_VAL(trap->sip)) { +#if LWIP_IPV6 + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr)); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr)); +#endif + } else { +#if LWIP_IPV4 + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr)); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr)); +#endif + } + + /* trap length */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap); + + /* specific trap */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap); + + /* timestamp */ + SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0); + snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len); + snmp_ans1_enc_tlv(pbuf_stream, &tlv); + snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts); +} + +#endif /* LWIP_SNMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3.c new file mode 100644 index 0000000000..69fb3a0aaf --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3.c @@ -0,0 +1,136 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#include "snmpv3_priv.h" +#include "lwip/apps/snmpv3.h" +#include "lwip/sys.h" +#include + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#ifdef LWIP_SNMPV3_INCLUDE_ENGINE +#include LWIP_SNMPV3_INCLUDE_ENGINE +#endif + +#define SNMP_MAX_TIME_BOOT 2147483647UL + +/** Call this if engine has been changed. Has to reset boots, see below */ +void +snmpv3_engine_id_changed(void) +{ + snmpv3_set_engine_boots(0); +} + +/** According to RFC3414 2.2.2. + * + * The number of times that the SNMP engine has + * (re-)initialized itself since snmpEngineID + * was last configured. + */ +u32_t +snmpv3_get_engine_boots_internal(void) +{ + if (snmpv3_get_engine_boots() == 0 || + snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) { + return snmpv3_get_engine_boots(); + } + + snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); + return snmpv3_get_engine_boots(); +} + +/** RFC3414 2.2.2. + * + * Once the timer reaches 2147483647 it gets reset to zero and the + * engine boot ups get incremented. + */ +u32_t +snmpv3_get_engine_time_internal(void) +{ + if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) { + snmpv3_reset_engine_time(); + + if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) { + snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1); + } else { + snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); + } + } + + return snmpv3_get_engine_time(); +} + +#if LWIP_SNMP_V3_CRYPTO + +/* This function ignores the byte order suggestion in RFC3414 + * since it simply doesn't influence the effectiveness of an IV. + * + * Implementing RFC3826 priv param algorithm if LWIP_RAND is available. + * + * @todo: This is a potential thread safety issue. + */ +err_t +snmpv3_build_priv_param(u8_t* priv_param) +{ +#ifdef LWIP_RAND /* Based on RFC3826 */ + static u8_t init; + static u32_t priv1, priv2; + + /* Lazy initialisation */ + if (init == 0) { + init = 1; + priv1 = LWIP_RAND(); + priv2 = LWIP_RAND(); + } + + SMEMCPY(&priv_param[0], &priv1, sizeof(priv1)); + SMEMCPY(&priv_param[4], &priv2, sizeof(priv2)); + + /* Emulate 64bit increment */ + priv1++; + if (!priv1) { /* Overflow */ + priv2++; + } +#else /* Based on RFC3414 */ + static u32_t ctr; + u32_t boots = LWIP_SNMPV3_GET_ENGINE_BOOTS(); + SMEMCPY(&priv_param[0], &boots, 4); + SMEMCPY(&priv_param[4], &ctr, 4); + ctr++; +#endif + return ERR_OK; +} +#endif /* LWIP_SNMP_V3_CRYPTO */ + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_dummy.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_dummy.c new file mode 100644 index 0000000000..bdfe844994 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_dummy.c @@ -0,0 +1,145 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + * Dirk Ziegelmeier + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" +#include +#include "lwip/err.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +/** + * @param username is a pointer to a string. + * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + */ +err_t +snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key) +{ + const char* engine_id; + u8_t engine_id_len; + + if(strlen(username) == 0) { + return ERR_OK; + } + + if(memcmp(username, "lwip", 4) != 0) { + return ERR_VAL; + } + + snmpv3_get_engine_id(&engine_id, &engine_id_len); + + if(auth_key != NULL) { + snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10, + (const u8_t*)engine_id, engine_id_len, + auth_key); + *auth_algo = SNMP_V3_AUTH_ALGO_SHA; + } + if(priv_key != NULL) { + snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10, + (const u8_t*)engine_id, engine_id_len, + priv_key); + *priv_algo = SNMP_V3_PRIV_ALGO_DES; + } + return ERR_OK; +} + +/** + * Get engine ID from persistence + * @param id + * @param len + */ +void +snmpv3_get_engine_id(const char **id, u8_t *len) +{ + *id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"; + *len = 12; +} + +/** + * Store engine ID in persistence + * @param id + * @param len + */ +err_t +snmpv3_set_engine_id(const char *id, u8_t len) +{ + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(len); + return ERR_OK; +} + +/** + * Get engine boots from persistence. Must be increased on each boot. + * @return + */ +u32_t +snmpv3_get_engine_boots(void) +{ + return 0; +} + +/** + * Store engine boots in persistence + * @param boots + */ +void +snmpv3_set_engine_boots(u32_t boots) +{ + LWIP_UNUSED_ARG(boots); +} + +/** + * RFC3414 2.2.2. + * Once the timer reaches 2147483647 it gets reset to zero and the + * engine boot ups get incremented. + */ +u32_t +snmpv3_get_engine_time(void) +{ + return 0; +} + +/** + * Reset current engine time to 0 + */ +void +snmpv3_reset_engine_time(void) +{ +} + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_mbedtls.c b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_mbedtls.c new file mode 100644 index 0000000000..0b1eefb87e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_mbedtls.c @@ -0,0 +1,331 @@ +/** + * @file + * SNMPv3 crypto/auth functions implemented for ARM mbedtls. + */ + +/* + * Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + * Dirk Ziegelmeier + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" +#include "lwip/arch.h" +#include "snmp_msg.h" +#include "lwip/sys.h" +#include + +#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS + +#include "mbedtls/md.h" +#include "mbedtls/cipher.h" + +#include "mbedtls/md5.h" +#include "mbedtls/sha1.h" + +err_t +snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, + const u8_t* key, u8_t algo, u8_t* hmac_out) +{ + u32_t i; + u8_t key_len; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t ctx; + struct snmp_pbuf_stream read_stream; + snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); + + if (algo == SNMP_V3_AUTH_ALGO_MD5) { + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + key_len = SNMP_V3_MD5_LEN; + } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + key_len = SNMP_V3_SHA_LEN; + } else { + return ERR_ARG; + } + + mbedtls_md_init(&ctx); + if(mbedtls_md_setup(&ctx, md_info, 1) != 0) { + return ERR_ARG; + } + + if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { + goto free_md; + } + + for (i = 0; i < length; i++) { + u8_t byte; + + if (snmp_pbuf_stream_read(&read_stream, &byte)) { + goto free_md; + } + + if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) { + goto free_md; + } + } + + if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) { + goto free_md; + } + + mbedtls_md_free(&ctx); + return ERR_OK; + +free_md: + mbedtls_md_free(&ctx); + return ERR_ARG; +} + +#if LWIP_SNMP_V3_CRYPTO + +err_t +snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, + const u8_t* key, const u8_t* priv_param, const u32_t engine_boots, + const u32_t engine_time, u8_t algo, u8_t mode) +{ + size_t i; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + + struct snmp_pbuf_stream read_stream; + struct snmp_pbuf_stream write_stream; + snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); + snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length); + mbedtls_cipher_init(&ctx); + + if (algo == SNMP_V3_PRIV_ALGO_DES) { + u8_t iv_local[8]; + u8_t out_bytes[8]; + size_t out_len; + + /* RFC 3414 mandates padding for DES */ + if ((length & 0x07) != 0) { + return ERR_ARG; + } + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC); + if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { + return ERR_ARG; + } + if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) { + return ERR_ARG; + } + if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { + goto error; + } + + /* Prepare IV */ + for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) { + iv_local[i] = priv_param[i] ^ key[i + 8]; + } + if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { + goto error; + } + + for (i = 0; i < length; i += 8) { + size_t j; + u8_t in_bytes[8]; + out_len = LWIP_ARRAYSIZE(out_bytes) ; + + for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) { + snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); + } + + if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) { + goto error; + } + + snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); + } + + out_len = LWIP_ARRAYSIZE(out_bytes); + if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) { + goto error; + } + snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); + } else if (algo == SNMP_V3_PRIV_ALGO_AES) { + u8_t iv_local[16]; + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128); + if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { + return ERR_ARG; + } + if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { + goto error; + } + + /* + * IV is the big endian concatenation of boots, + * uptime and priv param - see RFC3826. + */ + iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; + iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; + iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; + iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; + iv_local[4 + 0] = (engine_time >> 24) & 0xFF; + iv_local[4 + 1] = (engine_time >> 16) & 0xFF; + iv_local[4 + 2] = (engine_time >> 8) & 0xFF; + iv_local[4 + 3] = (engine_time >> 0) & 0xFF; + SMEMCPY(iv_local + 8, priv_param, 8); + if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { + goto error; + } + + for (i = 0; i < length; i++) { + u8_t in_byte; + u8_t out_byte; + size_t out_len = sizeof(out_byte); + + snmp_pbuf_stream_read(&read_stream, &in_byte); + if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) { + goto error; + } + snmp_pbuf_stream_write(&write_stream, out_byte); + } + } else { + return ERR_ARG; + } + + mbedtls_cipher_free(&ctx); + return ERR_OK; + +error: + mbedtls_cipher_free(&ctx); + return ERR_OK; +} + +#endif /* LWIP_SNMP_V3_CRYPTO */ + +/* A.2.1. Password to Key Sample Code for MD5 */ +void +snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength,/* IN - length of snmpEngineID */ + u8_t *key) /* OUT - pointer to caller 16-octet buffer */ +{ + mbedtls_md5_context MD; + u8_t *cp, password_buf[64]; + u32_t password_index = 0; + u8_t i; + u32_t count = 0; + + mbedtls_md5_init(&MD); /* initialize MD5 */ + mbedtls_md5_starts(&MD); + + /**********************************************/ + /* Use while loop until we've done 1 Megabyte */ + /**********************************************/ + while (count < 1048576) { + cp = password_buf; + for (i = 0; i < 64; i++) { + /*************************************************/ + /* Take the next octet of the password, wrapping */ + /* to the beginning of the password as necessary.*/ + /*************************************************/ + *cp++ = password[password_index++ % passwordlen]; + } + mbedtls_md5_update(&MD, password_buf, 64); + count += 64; + } + mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */ + + /*****************************************************/ + /* Now localize the key with the engineID and pass */ + /* through MD5 to produce final key */ + /* May want to ensure that engineLength <= 32, */ + /* otherwise need to use a buffer larger than 64 */ + /*****************************************************/ + SMEMCPY(password_buf, key, 16); + MEMCPY(password_buf + 16, engineID, engineLength); + SMEMCPY(password_buf + 16 + engineLength, key, 16); + + mbedtls_md5_starts(&MD); + mbedtls_md5_update(&MD, password_buf, 32 + engineLength); + mbedtls_md5_finish(&MD, key); + + mbedtls_md5_free(&MD); + return; +} + +/* A.2.2. Password to Key Sample Code for SHA */ +void +snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength,/* IN - length of snmpEngineID */ + u8_t *key) /* OUT - pointer to caller 20-octet buffer */ +{ + mbedtls_sha1_context SH; + u8_t *cp, password_buf[72]; + u32_t password_index = 0; + u8_t i; + u32_t count = 0; + + mbedtls_sha1_init(&SH); /* initialize SHA */ + mbedtls_sha1_starts(&SH); + + /**********************************************/ + /* Use while loop until we've done 1 Megabyte */ + /**********************************************/ + while (count < 1048576) { + cp = password_buf; + for (i = 0; i < 64; i++) { + /*************************************************/ + /* Take the next octet of the password, wrapping */ + /* to the beginning of the password as necessary.*/ + /*************************************************/ + *cp++ = password[password_index++ % passwordlen]; + } + mbedtls_sha1_update(&SH, password_buf, 64); + count += 64; + } + mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */ + + /*****************************************************/ + /* Now localize the key with the engineID and pass */ + /* through SHA to produce final key */ + /* May want to ensure that engineLength <= 32, */ + /* otherwise need to use a buffer larger than 72 */ + /*****************************************************/ + SMEMCPY(password_buf, key, 20); + MEMCPY(password_buf + 20, engineID, engineLength); + SMEMCPY(password_buf + 20 + engineLength, key, 20); + + mbedtls_sha1_starts(&SH); + mbedtls_sha1_update(&SH, password_buf, 40 + engineLength); + mbedtls_sha1_finish(&SH, key); + + mbedtls_sha1_free(&SH); + return; +} + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_priv.h b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_priv.h new file mode 100644 index 0000000000..b87666da99 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/snmp/snmpv3_priv.h @@ -0,0 +1,66 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826 (internal API, do not use in client code). + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H +#define LWIP_HDR_APPS_SNMP_V3_PRIV_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#include "snmp_pbuf_stream.h" + +/* According to RFC 3411 */ +#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32 +#define SNMP_V3_MAX_USER_LENGTH 32 + +#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12 +#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8 + +#define SNMP_V3_AUTH_FLAG 0x01 +#define SNMP_V3_PRIV_FLAG 0x02 + +#define SNMP_V3_MD5_LEN 16 +#define SNMP_V3_SHA_LEN 20 + +u32_t snmpv3_get_engine_boots_internal(void); +u32_t snmpv3_get_engine_time_internal(void); +err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out); +err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, + const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode); +err_t snmpv3_build_priv_param(u8_t* priv_param); + +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/sntp/sntp.c b/Sming/third-party/lwip2/lwip2-src/src/apps/sntp/sntp.c new file mode 100644 index 0000000000..71b2abedb8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/sntp/sntp.c @@ -0,0 +1,727 @@ +/** + * @file + * SNTP client module + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + */ + + +/** + * @defgroup sntp SNTP + * @ingroup apps + * + * This is simple "SNTP" client for the lwIP raw API. + * It is a minimal implementation of SNTPv4 as specified in RFC 4330. + * + * For a list of some public NTP servers, see this link : + * http://support.ntp.org/bin/view/Servers/NTPPoolServers + * + * @todo: + * - set/change servers at runtime + * - complete SNTP_CHECK_RESPONSE checks 3 and 4 + */ + +#include "lwip/apps/sntp.h" + +#include "lwip/opt.h" +#include "lwip/timeouts.h" +#include "lwip/udp.h" +#include "lwip/dns.h" +#include "lwip/ip_addr.h" +#include "lwip/pbuf.h" +#include "lwip/dhcp.h" + +#include +#include + +#if LWIP_UDP + +/* Handle support for more than one server via SNTP_MAX_SERVERS */ +#if SNTP_MAX_SERVERS > 1 +#define SNTP_SUPPORT_MULTIPLE_SERVERS 1 +#else /* NTP_MAX_SERVERS > 1 */ +#define SNTP_SUPPORT_MULTIPLE_SERVERS 0 +#endif /* NTP_MAX_SERVERS > 1 */ + +#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK) +#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!" +#endif + +/* Configure behaviour depending on microsecond or second precision */ +#ifdef SNTP_SET_SYSTEM_TIME_US +#define SNTP_CALC_TIME_US 1 +#define SNTP_RECEIVE_TIME_SIZE 2 +#else +#define SNTP_SET_SYSTEM_TIME_US(sec, us) +#define SNTP_CALC_TIME_US 0 +#define SNTP_RECEIVE_TIME_SIZE 1 +#endif + + +/* the various debug levels for this file */ +#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) +#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) +#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) +#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) + +#define SNTP_ERR_KOD 1 + +/* SNTP protocol defines */ +#define SNTP_MSG_LEN 48 + +#define SNTP_OFFSET_LI_VN_MODE 0 +#define SNTP_LI_MASK 0xC0 +#define SNTP_LI_NO_WARNING 0x00 +#define SNTP_LI_LAST_MINUTE_61_SEC 0x01 +#define SNTP_LI_LAST_MINUTE_59_SEC 0x02 +#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ + +#define SNTP_VERSION_MASK 0x38 +#define SNTP_VERSION (4/* NTP Version 4*/<<3) + +#define SNTP_MODE_MASK 0x07 +#define SNTP_MODE_CLIENT 0x03 +#define SNTP_MODE_SERVER 0x04 +#define SNTP_MODE_BROADCAST 0x05 + +#define SNTP_OFFSET_STRATUM 1 +#define SNTP_STRATUM_KOD 0x00 + +#define SNTP_OFFSET_ORIGINATE_TIME 24 +#define SNTP_OFFSET_RECEIVE_TIME 32 +#define SNTP_OFFSET_TRANSMIT_TIME 40 + +/* number of seconds between 1900 and 1970 (MSB=1)*/ +#define DIFF_SEC_1900_1970 (2208988800UL) +/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */ +#define DIFF_SEC_1970_2036 (2085978496UL) + +/** + * SNTP packet format (without optional fields) + * Timestamps are coded as 64 bits: + * - 32 bits seconds since Jan 01, 1970, 00:00 + * - 32 bits seconds fraction (0-padded) + * For future use, if the MSB in the seconds part is set, seconds are based + * on Feb 07, 2036, 06:28:16. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct sntp_msg { + PACK_STRUCT_FLD_8(u8_t li_vn_mode); + PACK_STRUCT_FLD_8(u8_t stratum); + PACK_STRUCT_FLD_8(u8_t poll); + PACK_STRUCT_FLD_8(u8_t precision); + PACK_STRUCT_FIELD(u32_t root_delay); + PACK_STRUCT_FIELD(u32_t root_dispersion); + PACK_STRUCT_FIELD(u32_t reference_identifier); + PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); + PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); + PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); + PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* function prototypes */ +static void sntp_request(void *arg); + +/** The operating mode */ +static u8_t sntp_opmode; + +/** The UDP pcb used by the SNTP client */ +static struct udp_pcb* sntp_pcb; +/** Names/Addresses of servers */ +struct sntp_server { +#if SNTP_SERVER_DNS + char* name; +#endif /* SNTP_SERVER_DNS */ + ip_addr_t addr; +}; +static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; + +#if SNTP_GET_SERVERS_FROM_DHCP +static u8_t sntp_set_servers_from_dhcp; +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** The currently used server (initialized to 0) */ +static u8_t sntp_current_server; +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +#define sntp_current_server 0 +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +#if SNTP_RETRY_TIMEOUT_EXP +#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT +/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ +static u32_t sntp_retry_timeout; +#else /* SNTP_RETRY_TIMEOUT_EXP */ +#define SNTP_RESET_RETRY_TIMEOUT() +#define sntp_retry_timeout SNTP_RETRY_TIMEOUT +#endif /* SNTP_RETRY_TIMEOUT_EXP */ + +#if SNTP_CHECK_RESPONSE >= 1 +/** Saves the last server address to compare with response */ +static ip_addr_t sntp_last_server_address; +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + +#if SNTP_CHECK_RESPONSE >= 2 +/** Saves the last timestamp sent (which is sent back by the server) + * to compare against in response */ +static u32_t sntp_last_timestamp_sent[2]; +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + +/** + * SNTP processing of received timestamp + */ +static void +sntp_process(u32_t *receive_timestamp) +{ + /* convert SNTP time (1900-based) to unix GMT time (1970-based) + * if MSB is 0, SNTP time is 2036-based! + */ + u32_t rx_secs = lwip_ntohl(receive_timestamp[0]); + int is_1900_based = ((rx_secs & 0x80000000) != 0); + u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036); + time_t tim = t; + +#if SNTP_CALC_TIME_US + u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295; + SNTP_SET_SYSTEM_TIME_US(t, us); + /* display local time from GMT time */ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us)); + +#else /* SNTP_CALC_TIME_US */ + + /* change system time and/or the update the RTC clock */ + SNTP_SET_SYSTEM_TIME(t); + /* display local time from GMT time */ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim))); +#endif /* SNTP_CALC_TIME_US */ + LWIP_UNUSED_ARG(tim); +} + +/** + * Initialize request struct to be sent to server. + */ +static void +sntp_initialize_request(struct sntp_msg *req) +{ + memset(req, 0, SNTP_MSG_LEN); + req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; + +#if SNTP_CHECK_RESPONSE >= 2 + { + u32_t sntp_time_sec, sntp_time_us; + /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ + SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); + sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970); + req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; + /* we send/save us instead of fraction to be faster... */ + sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us); + req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; + } +#endif /* SNTP_CHECK_RESPONSE >= 2 */ +} + +/** + * Retry: send a new request (and increase retry timeout). + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_retry(void* arg) +{ + LWIP_UNUSED_ARG(arg); + + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", + sntp_retry_timeout)); + + /* set up a timer to send a retry and increase the retry delay */ + sys_timeout(sntp_retry_timeout, sntp_request, NULL); + +#if SNTP_RETRY_TIMEOUT_EXP + { + u32_t new_retry_timeout; + /* increase the timeout for next retry */ + new_retry_timeout = sntp_retry_timeout << 1; + /* limit to maximum timeout and prevent overflow */ + if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && + (new_retry_timeout > sntp_retry_timeout)) { + sntp_retry_timeout = new_retry_timeout; + } + } +#endif /* SNTP_RETRY_TIMEOUT_EXP */ +} + +#if SNTP_SUPPORT_MULTIPLE_SERVERS +/** + * If Kiss-of-Death is received (or another packet parsing error), + * try the next server or retry the current server and increase the retry + * timeout if only one server is available. + * (implicitly, SNTP_MAX_SERVERS > 1) + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_try_next_server(void* arg) +{ + u8_t old_server, i; + LWIP_UNUSED_ARG(arg); + + old_server = sntp_current_server; + for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) { + sntp_current_server++; + if (sntp_current_server >= SNTP_MAX_SERVERS) { + sntp_current_server = 0; + } + if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) +#if SNTP_SERVER_DNS + || (sntp_servers[sntp_current_server].name != NULL) +#endif + ) { + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", + (u16_t)sntp_current_server)); + /* new server: reset retry timeout */ + SNTP_RESET_RETRY_TIMEOUT(); + /* instantly send a request to the next server */ + sntp_request(NULL); + return; + } + } + /* no other valid server found */ + sntp_current_server = old_server; + sntp_retry(NULL); +} +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +/* Always retry on error if only one server is supported */ +#define sntp_try_next_server sntp_retry +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + +/** UDP recv callback for the sntp pcb */ +static void +sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + u8_t mode; + u8_t stratum; + u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; + err_t err; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + + /* packet received: stop retry timeout */ + sys_untimeout(sntp_try_next_server, NULL); + sys_untimeout(sntp_request, NULL); + + err = ERR_ARG; +#if SNTP_CHECK_RESPONSE >= 1 + /* check server address and port */ + if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && + (port == SNTP_PORT)) +#else /* SNTP_CHECK_RESPONSE >= 1 */ + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + { + /* process the response */ + if (p->tot_len == SNTP_MSG_LEN) { + pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); + mode &= SNTP_MODE_MASK; + /* if this is a SNTP response... */ + if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) || + ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) { + pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); + if (stratum == SNTP_STRATUM_KOD) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + err = SNTP_ERR_KOD; + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); + } else { +#if SNTP_CHECK_RESPONSE >= 2 + /* check originate_timetamp against sntp_last_timestamp_sent */ + u32_t originate_timestamp[2]; + pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); + if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || + (originate_timestamp[1] != sntp_last_timestamp_sent[1])) + { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); + } else +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ + { + /* correct answer */ + err = ERR_OK; + pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME); + } + } + } else { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); + /* wait for correct response */ + err = ERR_TIMEOUT; + } + } else { + LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); + } + } +#if SNTP_CHECK_RESPONSE >= 1 + else { + /* packet from wrong remote address or port, wait for correct response */ + err = ERR_TIMEOUT; + } +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + pbuf_free(p); + if (err == ERR_OK) { + sntp_process(receive_timestamp); + + /* Set up timeout for next request (only if poll response was received)*/ + if (sntp_opmode == SNTP_OPMODE_POLL) { + /* Correct response, reset retry timeout */ + SNTP_RESET_RETRY_TIMEOUT(); + + sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", + (u32_t)SNTP_UPDATE_DELAY)); + } + } else if (err != ERR_TIMEOUT) { + /* Errors are only processed in case of an explicit poll response */ + if (sntp_opmode == SNTP_OPMODE_POLL) { + if (err == SNTP_ERR_KOD) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + sntp_try_next_server(NULL); + } else { + /* another error, try the same server again */ + sntp_retry(NULL); + } + } + } +} + +/** Actually send an sntp request to a server. + * + * @param server_addr resolved IP address of the SNTP server + */ +static void +sntp_send_request(const ip_addr_t *server_addr) +{ + struct pbuf* p; + p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); + if (p != NULL) { + struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); + /* initialize request message */ + sntp_initialize_request(sntpmsg); + /* send request */ + udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); + /* free the pbuf after sending it */ + pbuf_free(p); + /* set up receive timeout: try next server or retry on timeout */ + sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); +#if SNTP_CHECK_RESPONSE >= 1 + /* save server address to verify it in sntp_recv */ + ip_addr_set(&sntp_last_server_address, server_addr); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + } else { + LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", + (u32_t)SNTP_RETRY_TIMEOUT)); + /* out of memory: set up a timer to send a retry */ + sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); + } +} + +#if SNTP_SERVER_DNS +/** + * DNS found callback when using DNS names as server address. + */ +static void +sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg) +{ + LWIP_UNUSED_ARG(hostname); + LWIP_UNUSED_ARG(arg); + + if (ipaddr != NULL) { + /* Address resolved, send request */ + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); + sntp_send_request(ipaddr); + } else { + /* DNS resolving failed -> try another server */ + LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); + sntp_try_next_server(NULL); + } +} +#endif /* SNTP_SERVER_DNS */ + +/** + * Send out an sntp request. + * + * @param arg is unused (only necessary to conform to sys_timeout) + */ +static void +sntp_request(void *arg) +{ + ip_addr_t sntp_server_address; + err_t err; + + LWIP_UNUSED_ARG(arg); + + /* initialize SNTP server address */ +#if SNTP_SERVER_DNS + if (sntp_servers[sntp_current_server].name) { + /* always resolve the name and rely on dns-internal caching & timeout */ + ip_addr_set_zero(&sntp_servers[sntp_current_server].addr); + err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address, + sntp_dns_found, NULL); + if (err == ERR_INPROGRESS) { + /* DNS request sent, wait for sntp_dns_found being called */ + LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); + return; + } else if (err == ERR_OK) { + sntp_servers[sntp_current_server].addr = sntp_server_address; + } + } else +#endif /* SNTP_SERVER_DNS */ + { + sntp_server_address = sntp_servers[sntp_current_server].addr; + err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK; + } + + if (err == ERR_OK) { + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n", + ipaddr_ntoa(&sntp_server_address))); + sntp_send_request(&sntp_server_address); + } else { + /* address conversion failed, try another server */ + LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); + sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); + } +} + +/** + * @ingroup sntp + * Initialize this module. + * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). + */ +void +sntp_init(void) +{ +#ifdef SNTP_SERVER_ADDRESS +#if SNTP_SERVER_DNS + sntp_setservername(0, SNTP_SERVER_ADDRESS); +#else +#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0 +#endif +#endif /* SNTP_SERVER_ADDRESS */ + + if (sntp_pcb == NULL) { + sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); + if (sntp_pcb != NULL) { + udp_recv(sntp_pcb, sntp_recv, NULL); + + if (sntp_opmode == SNTP_OPMODE_POLL) { + SNTP_RESET_RETRY_TIMEOUT(); +#if SNTP_STARTUP_DELAY + sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); +#else + sntp_request(NULL); +#endif + } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) { + ip_set_option(sntp_pcb, SOF_BROADCAST); + udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT); + } + } + } +} + +/** + * @ingroup sntp + * Stop this module. + */ +void +sntp_stop(void) +{ + if (sntp_pcb != NULL) { + sys_untimeout(sntp_request, NULL); + sys_untimeout(sntp_try_next_server, NULL); + udp_remove(sntp_pcb); + sntp_pcb = NULL; + } +} + +/** + * @ingroup sntp + * Get enabled state. + */ +u8_t sntp_enabled(void) +{ + return (sntp_pcb != NULL)? 1 : 0; +} + +/** + * @ingroup sntp + * Sets the operating mode. + * @param operating_mode one of the available operating modes + */ +void +sntp_setoperatingmode(u8_t operating_mode) +{ + LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY); + LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL); + sntp_opmode = operating_mode; +} + +/** + * @ingroup sntp + * Gets the operating mode. + */ +u8_t +sntp_getoperatingmode(void) +{ + return sntp_opmode; +} + +#if SNTP_GET_SERVERS_FROM_DHCP +/** + * Config SNTP server handling by IP address, name, or DHCP; clear table + * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp + */ +void +sntp_servermode_dhcp(int set_servers_from_dhcp) +{ + u8_t new_mode = set_servers_from_dhcp ? 1 : 0; + if (sntp_set_servers_from_dhcp != new_mode) { + sntp_set_servers_from_dhcp = new_mode; + } +} +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +/** + * @ingroup sntp + * Initialize one of the NTP servers by IP address + * + * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param server IP address of the NTP server to set + */ +void +sntp_setserver(u8_t idx, const ip_addr_t *server) +{ + if (idx < SNTP_MAX_SERVERS) { + if (server != NULL) { + sntp_servers[idx].addr = (*server); + } else { + ip_addr_set_zero(&sntp_servers[idx].addr); + } +#if SNTP_SERVER_DNS + sntp_servers[idx].name = NULL; +#endif + } +} + +#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP +/** + * Initialize one of the NTP servers by IP address, required by DHCP + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver IP address of the NTP server to set + */ +void +dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server) +{ + LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n", + (sntp_set_servers_from_dhcp ? "Got" : "Rejected"), + ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num)); + if (sntp_set_servers_from_dhcp && num) { + u8_t i; + for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) { + ip_addr_t addr; + ip_addr_copy_from_ip4(addr, server[i]); + sntp_setserver(i, &addr); + } + for (i = num; i < SNTP_MAX_SERVERS; i++) { + sntp_setserver(i, NULL); + } + } +} +#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */ + +/** + * @ingroup sntp + * Obtain one of the currently configured by IP address (or DHCP) NTP servers + * + * @param idx the index of the NTP server + * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP + * server has not been configured by address (or at all). + */ +const ip_addr_t* +sntp_getserver(u8_t idx) +{ + if (idx < SNTP_MAX_SERVERS) { + return &sntp_servers[idx].addr; + } + return IP_ADDR_ANY; +} + +#if SNTP_SERVER_DNS +/** + * Initialize one of the NTP servers by name + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time + */ +void +sntp_setservername(u8_t idx, char *server) +{ + if (idx < SNTP_MAX_SERVERS) { + sntp_servers[idx].name = server; + } +} + +/** + * Obtain one of the currently configured by name NTP servers. + * + * @param numdns the index of the NTP server + * @return IP address of the indexed NTP server or NULL if the NTP + * server has not been configured by name (or at all) + */ +char * +sntp_getservername(u8_t idx) +{ + if (idx < SNTP_MAX_SERVERS) { + return sntp_servers[idx].name; + } + return NULL; +} +#endif /* SNTP_SERVER_DNS */ + +#endif /* LWIP_UDP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/apps/tftp/tftp_server.c b/Sming/third-party/lwip2/lwip2-src/src/apps/tftp/tftp_server.c new file mode 100644 index 0000000000..243b0924bd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/apps/tftp/tftp_server.c @@ -0,0 +1,417 @@ +/****************************************************************//** + * + * @file tftp_server.c + * + * @author Logan Gunthorpe + * Dirk Ziegelmeier + * + * @brief Trivial File Transfer Protocol (RFC 1350) + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * Dirk Ziegelmeier + * + */ + +/** + * @defgroup tftp TFTP server + * @ingroup apps + * + * This is simple TFTP server for the lwIP raw API. + */ + +#include "lwip/apps/tftp_server.h" + +#if LWIP_UDP + +#include "lwip/udp.h" +#include "lwip/timeouts.h" +#include "lwip/debug.h" + +#define TFTP_MAX_PAYLOAD_SIZE 512 +#define TFTP_HEADER_LENGTH 4 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +enum tftp_error { + TFTP_ERROR_FILE_NOT_FOUND = 1, + TFTP_ERROR_ACCESS_VIOLATION = 2, + TFTP_ERROR_DISK_FULL = 3, + TFTP_ERROR_ILLEGAL_OPERATION = 4, + TFTP_ERROR_UNKNOWN_TRFR_ID = 5, + TFTP_ERROR_FILE_EXISTS = 6, + TFTP_ERROR_NO_SUCH_USER = 7 +}; + +#include + +struct tftp_state { + const struct tftp_context *ctx; + void *handle; + struct pbuf *last_data; + struct udp_pcb *upcb; + ip_addr_t addr; + u16_t port; + int timer; + int last_pkt; + u16_t blknum; + u8_t retries; + u8_t mode_write; +}; + +static struct tftp_state tftp_state; + +static void tftp_tmr(void* arg); + +static void +close_handle(void) +{ + tftp_state.port = 0; + ip_addr_set_any(0, &tftp_state.addr); + + if(tftp_state.last_data != NULL) { + pbuf_free(tftp_state.last_data); + tftp_state.last_data = NULL; + } + + sys_untimeout(tftp_tmr, NULL); + + if (tftp_state.handle) { + tftp_state.ctx->close(tftp_state.handle); + tftp_state.handle = NULL; + LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n")); + } +} + +static void +send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str) +{ + int str_length = strlen(str); + struct pbuf* p; + u16_t* payload; + + p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM); + if(p == NULL) { + return; + } + + payload = (u16_t*) p->payload; + payload[0] = PP_HTONS(TFTP_ERROR); + payload[1] = lwip_htons(code); + MEMCPY(&payload[2], str, str_length + 1); + + udp_sendto(tftp_state.upcb, p, addr, port); + pbuf_free(p); +} + +static void +send_ack(u16_t blknum) +{ + struct pbuf* p; + u16_t* payload; + + p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM); + if(p == NULL) { + return; + } + payload = (u16_t*) p->payload; + + payload[0] = PP_HTONS(TFTP_ACK); + payload[1] = lwip_htons(blknum); + udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port); + pbuf_free(p); +} + +static void +resend_data(void) +{ + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM); + if(p == NULL) { + return; + } + + if(pbuf_copy(p, tftp_state.last_data) != ERR_OK) { + pbuf_free(p); + return; + } + + udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port); + pbuf_free(p); +} + +static void +send_data(void) +{ + u16_t *payload; + int ret; + + if(tftp_state.last_data != NULL) { + pbuf_free(tftp_state.last_data); + } + + tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM); + if(tftp_state.last_data == NULL) { + return; + } + + payload = (u16_t *) tftp_state.last_data->payload; + payload[0] = PP_HTONS(TFTP_DATA); + payload[1] = lwip_htons(tftp_state.blknum); + + ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE); + if (ret < 0) { + send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file."); + close_handle(); + return; + } + + pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret)); + resend_data(); +} + +static void +recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + u16_t *sbuf = (u16_t *) p->payload; + int opcode; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(upcb); + + if (((tftp_state.port != 0) && (port != tftp_state.port)) || + (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); + pbuf_free(p); + return; + } + + opcode = sbuf[0]; + + tftp_state.last_pkt = tftp_state.timer; + tftp_state.retries = 0; + + switch (opcode) { + case PP_HTONS(TFTP_RRQ): /* fall through */ + case PP_HTONS(TFTP_WRQ): + { + const char tftp_null = 0; + char filename[TFTP_MAX_FILENAME_LEN]; + char mode[TFTP_MAX_MODE_LEN]; + u16_t filename_end_offset; + u16_t mode_end_offset; + + if(tftp_state.handle != NULL) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); + break; + } + + sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); + + /* find \0 in pbuf -> end of filename string */ + filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2); + if((u16_t)(filename_end_offset-2) > sizeof(filename)) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated"); + break; + } + pbuf_copy_partial(p, filename, filename_end_offset-2, 2); + + /* find \0 in pbuf -> end of mode string */ + mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1); + if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated"); + break; + } + pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1); + + tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ)); + tftp_state.blknum = 1; + + if (!tftp_state.handle) { + send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file."); + break; + } + + LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read")); + ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr); + LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode)); + + ip_addr_copy(tftp_state.addr, *addr); + tftp_state.port = port; + + if (opcode == PP_HTONS(TFTP_WRQ)) { + tftp_state.mode_write = 1; + send_ack(0); + } else { + tftp_state.mode_write = 0; + send_data(); + } + + break; + } + + case PP_HTONS(TFTP_DATA): + { + int ret; + u16_t blknum; + + if (tftp_state.handle == NULL) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); + break; + } + + if (tftp_state.mode_write != 1) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection"); + break; + } + + blknum = lwip_ntohs(sbuf[1]); + pbuf_header(p, -TFTP_HEADER_LENGTH); + + ret = tftp_state.ctx->write(tftp_state.handle, p); + if (ret < 0) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file"); + close_handle(); + } else { + send_ack(blknum); + } + + if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) { + close_handle(); + } + break; + } + + case PP_HTONS(TFTP_ACK): + { + u16_t blknum; + int lastpkt; + + if (tftp_state.handle == NULL) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); + break; + } + + if (tftp_state.mode_write != 0) { + send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection"); + break; + } + + blknum = lwip_ntohs(sbuf[1]); + if (blknum != tftp_state.blknum) { + send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number"); + break; + } + + lastpkt = 0; + + if (tftp_state.last_data != NULL) { + lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH); + } + + if (!lastpkt) { + tftp_state.blknum++; + send_data(); + } else { + close_handle(); + } + + break; + } + + default: + send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation"); + break; + } + + pbuf_free(p); +} + +static void +tftp_tmr(void* arg) +{ + LWIP_UNUSED_ARG(arg); + + tftp_state.timer++; + + if (tftp_state.handle == NULL) { + return; + } + + sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); + + if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) { + if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) { + LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n")); + resend_data(); + tftp_state.retries++; + } else { + LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n")); + close_handle(); + } + } +} + +/** @ingroup tftp + * Initialize TFTP server. + * @param ctx TFTP callback struct + */ +err_t +tftp_init(const struct tftp_context *ctx) +{ + err_t ret; + + struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (pcb == NULL) { + return ERR_MEM; + } + + ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT); + if (ret != ERR_OK) { + udp_remove(pcb); + return ret; + } + + tftp_state.handle = NULL; + tftp_state.port = 0; + tftp_state.ctx = ctx; + tftp_state.timer = 0; + tftp_state.last_data = NULL; + tftp_state.upcb = pcb; + + udp_recv(pcb, recv, NULL); + + return ERR_OK; +} + +#endif /* LWIP_UDP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/def.c b/Sming/third-party/lwip2/lwip2-src/src/core/def.c new file mode 100644 index 0000000000..8125313f41 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/def.c @@ -0,0 +1,222 @@ +/** + * @file + * Common functions used throughout the stack. + * + * These are reference implementations of the byte swapping functions. + * Again with the aim of being simple, correct and fully portable. + * Byte swapping is the second thing you would want to optimize. You will + * need to port it to your architecture and in your cc.h: + * + * \#define lwip_htons(x) your_htons + * \#define lwip_htonl(x) your_htonl + * + * Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts. + * + * If you \#define them to htons() and htonl(), you should + * \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from + * defining htonx/ntohx compatibility macros. + + * @defgroup sys_nonstandard Non-standard functions + * @ingroup sys_layer + * lwIP provides default implementations for non-standard functions. + * These can be mapped to OS functions to reduce code footprint if desired. + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/cc.h! + * These options cannot be \#defined in lwipopts.h since they are not options + * of lwIP itself, but options of the lwIP port to your system. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include + +#if BYTE_ORDER == LITTLE_ENDIAN + +#if !defined(lwip_htons) +/** + * Convert an u16_t from host- to network byte order. + * + * @param n u16_t in host byte order + * @return n in network byte order + */ +u16_t +lwip_htons(u16_t n) +{ + return (u16_t)PP_HTONS(n); +} +#endif /* lwip_htons */ + +#if !defined(lwip_htonl) +/** + * Convert an u32_t from host- to network byte order. + * + * @param n u32_t in host byte order + * @return n in network byte order + */ +u32_t +lwip_htonl(u32_t n) +{ + return (u32_t)PP_HTONL(n); +} +#endif /* lwip_htonl */ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#ifndef lwip_strnstr +/** + * @ingroup sys_nonstandard + * lwIP default implementation for strnstr() non-standard function. + * This can be \#defined to strnstr() depending on your platform port. + */ +char* +lwip_strnstr(const char* buffer, const char* token, size_t n) +{ + const char* p; + size_t tokenlen = strlen(token); + if (tokenlen == 0) { + return LWIP_CONST_CAST(char *, buffer); + } + for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { + if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { + return LWIP_CONST_CAST(char *, p); + } + } + return NULL; +} +#endif + +#ifndef lwip_stricmp +/** + * @ingroup sys_nonstandard + * lwIP default implementation for stricmp() non-standard function. + * This can be \#defined to stricmp() depending on your platform port. + */ +int +lwip_stricmp(const char* str1, const char* str2) +{ + char c1, c2; + + do { + c1 = *str1++; + c2 = *str2++; + if (c1 != c2) { + char c1_upc = c1 | 0x20; + if ((c1_upc >= 'a') && (c1_upc <= 'z')) { + /* characters are not equal an one is in the alphabet range: + downcase both chars and check again */ + char c2_upc = c2 | 0x20; + if (c1_upc != c2_upc) { + /* still not equal */ + /* don't care for < or > */ + return 1; + } + } else { + /* characters are not equal but none is in the alphabet range */ + return 1; + } + } + } while (c1 != 0); + return 0; +} +#endif + +#ifndef lwip_strnicmp +/** + * @ingroup sys_nonstandard + * lwIP default implementation for strnicmp() non-standard function. + * This can be \#defined to strnicmp() depending on your platform port. + */ +int +lwip_strnicmp(const char* str1, const char* str2, size_t len) +{ + char c1, c2; + + do { + c1 = *str1++; + c2 = *str2++; + if (c1 != c2) { + char c1_upc = c1 | 0x20; + if ((c1_upc >= 'a') && (c1_upc <= 'z')) { + /* characters are not equal an one is in the alphabet range: + downcase both chars and check again */ + char c2_upc = c2 | 0x20; + if (c1_upc != c2_upc) { + /* still not equal */ + /* don't care for < or > */ + return 1; + } + } else { + /* characters are not equal but none is in the alphabet range */ + return 1; + } + } + } while (len-- && c1 != 0); + return 0; +} +#endif + +#ifndef lwip_itoa +/** + * @ingroup sys_nonstandard + * lwIP default implementation for itoa() non-standard function. + * This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port. + */ +void +lwip_itoa(char* result, size_t bufsize, int number) +{ + const int base = 10; + char* ptr = result, *ptr1 = result, tmp_char; + int tmp_value; + LWIP_UNUSED_ARG(bufsize); + + do { + tmp_value = number; + number /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - number * base)]; + } while(number); + + /* Apply negative sign */ + if (tmp_value < 0) { + *ptr++ = '-'; + } + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } +} +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/dns.c b/Sming/third-party/lwip2/lwip2-src/src/core/dns.c new file mode 100644 index 0000000000..12c6f16fe3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/dns.c @@ -0,0 +1,1573 @@ +/** + * @file + * DNS - host name to IP address resolver. + * + * @defgroup dns DNS + * @ingroup callbackstyle_api + * + * Implements a DNS host name to IP address resolver. + * + * The lwIP DNS resolver functions are used to lookup a host name and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the dns_lookup() function. + * New hostnames can be resolved using the dns_query() function. + * + * The lwIP version of the resolver also adds a non-blocking version of + * gethostbyname() that will work with a raw API application. This function + * checks for an IP address string first and converts it if it is valid. + * gethostbyname() then does a dns_lookup() to see if the name is + * already in the table. If so, the IP is returned. If not, a query is + * issued and the function returns with a ERR_INPROGRESS status. The app + * using the dns client must then go into a waiting state. + * + * Once a hostname has been resolved (or found to be non-existent), + * the resolver code calls a specified callback function (which + * must be implemented by the module that uses the resolver). + * + * Multicast DNS queries are supported for names ending on ".local". + * However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762 + * chapter 5.1), this is not a fully compliant implementation of continuous + * mDNS querying! + * + * All functions must be called from TCPIP thread. + * + * @see @ref netconn_common for thread-safe access. + */ + +/* + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + * + * security fixes and more by Simon Goldschmidt + * + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*----------------------------------------------------------------------------- + * RFC 1035 - Domain names - implementation and specification + * RFC 2181 - Clarifications to the DNS Specification + *----------------------------------------------------------------------------*/ + +/** @todo: define good default values (rfc compliance) */ +/** @todo: improve answer parsing, more checkings... */ +/** @todo: check RFC1035 - 7.3. Processing responses */ +/** @todo: one-shot mDNS: dual-stack fallback to another IP version */ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/dns.h" +#include "lwip/prot/dns.h" + +#include + +/** Random generator function to create random TXIDs and source ports for queries */ +#ifndef DNS_RAND_TXID +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) +#define DNS_RAND_TXID LWIP_RAND +#else +static u16_t dns_txid; +#define DNS_RAND_TXID() (++dns_txid) +#endif +#endif + +/** Limits the source port to be >= 1024 by default */ +#ifndef DNS_PORT_ALLOWED +#define DNS_PORT_ALLOWED(port) ((port) >= 1024) +#endif + +/** DNS maximum number of retries when asking for a name, before "timeout". */ +#ifndef DNS_MAX_RETRIES +#define DNS_MAX_RETRIES 4 +#endif + +/** DNS resource record max. TTL (one week as default) */ +#ifndef DNS_MAX_TTL +#define DNS_MAX_TTL 604800 +#elif DNS_MAX_TTL > 0x7FFFFFFF +#error DNS_MAX_TTL must be a positive 32-bit value +#endif + +#if DNS_TABLE_SIZE > 255 +#error DNS_TABLE_SIZE must fit into an u8_t +#endif +#if DNS_MAX_SERVERS > 255 +#error DNS_MAX_SERVERS must fit into an u8_t +#endif + +/* The number of parallel requests (i.e. calls to dns_gethostbyname + * that cannot be answered from the DNS table. + * This is set to the table size by default. + */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) +#ifndef DNS_MAX_REQUESTS +#define DNS_MAX_REQUESTS DNS_TABLE_SIZE +#else +#if DNS_MAX_REQUESTS > 255 +#error DNS_MAX_REQUESTS must fit into an u8_t +#endif +#endif +#else +/* In this configuration, both arrays have to have the same size and are used + * like one entry (used/free) */ +#define DNS_MAX_REQUESTS DNS_TABLE_SIZE +#endif + +/* The number of UDP source ports used in parallel */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +#ifndef DNS_MAX_SOURCE_PORTS +#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS +#else +#if DNS_MAX_SOURCE_PORTS > 255 +#error DNS_MAX_SOURCE_PORTS must fit into an u8_t +#endif +#endif +#else +#ifdef DNS_MAX_SOURCE_PORTS +#undef DNS_MAX_SOURCE_PORTS +#endif +#define DNS_MAX_SOURCE_PORTS 1 +#endif + +#if LWIP_IPV4 && LWIP_IPV6 +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6)) +#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t))) +#define LWIP_DNS_ADDRTYPE_ARG(x) , x +#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x +#define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0) +#else +#if LWIP_IPV6 +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1 +#else +#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0 +#endif +#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1 +#define LWIP_DNS_ADDRTYPE_ARG(x) +#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0 +#define LWIP_DNS_SET_ADDRTYPE(x, y) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES +#define LWIP_DNS_ISMDNS_ARG(x) , x +#else +#define LWIP_DNS_ISMDNS_ARG(x) +#endif + +/** DNS query message structure. + No packing needed: only used locally on the stack. */ +struct dns_query { + /* DNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; +}; +#define SIZEOF_DNS_QUERY 4 + +/** DNS answer message structure. + No packing needed: only used locally on the stack. */ +struct dns_answer { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t cls; + u32_t ttl; + u16_t len; +}; +#define SIZEOF_DNS_ANSWER 10 +/* maximum allowed size for the struct due to non-packed */ +#define SIZEOF_DNS_ANSWER_ASSERT 12 + +/* DNS table entry states */ +typedef enum { + DNS_STATE_UNUSED = 0, + DNS_STATE_NEW = 1, + DNS_STATE_ASKING = 2, + DNS_STATE_DONE = 3 +} dns_state_enum_t; + +/** DNS table entry */ +struct dns_table_entry { + u32_t ttl; + ip_addr_t ipaddr; + u16_t txid; + u8_t state; + u8_t server_idx; + u8_t tmr; + u8_t retries; + u8_t seqno; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + u8_t pcb_idx; +#endif + char name[DNS_MAX_NAME_LENGTH]; +#if LWIP_IPV4 && LWIP_IPV6 + u8_t reqaddrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + u8_t is_mdns; +#endif +}; + +/** DNS request table entry: used when dns_gehostbyname cannot answer the + * request from the DNS table */ +struct dns_req_entry { + /* pointer to callback on DNS query done */ + dns_found_callback found; + /* argument passed to the callback function */ + void *arg; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + u8_t dns_table_idx; +#endif +#if LWIP_IPV4 && LWIP_IPV6 + u8_t reqaddrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +}; + +#if DNS_LOCAL_HOSTLIST + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Local host-list. For hostnames in this list, no + * external name resolution is performed */ +static struct local_hostlist_entry *local_hostlist_dynamic; +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE +#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST +#define DNS_LOCAL_HOSTLIST_STORAGE_POST +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ +DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] + DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; + +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +static void dns_init_local(void); +static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); +#endif /* DNS_LOCAL_HOSTLIST */ + + +/* forward declarations */ +static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +static void dns_check_entries(void); +static void dns_call_found(u8_t idx, ip_addr_t* addr); + +/*----------------------------------------------------------------------------- + * Globals + *----------------------------------------------------------------------------*/ + +/* DNS variables */ +static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +static u8_t dns_last_pcb_idx; +#endif +static u8_t dns_seqno; +static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; +static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; +static ip_addr_t dns_servers[DNS_MAX_SERVERS]; + +#if LWIP_IPV4 +const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT; +#endif /* LWIP_IPV6 */ + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (if DNS_SERVER_ADDRESS is set). + */ +void +dns_init(void) +{ +#ifdef DNS_SERVER_ADDRESS + /* initialize default DNS server address */ + ip_addr_t dnsserver; + DNS_SERVER_ADDRESS(&dnsserver); + dns_setserver(0, &dnsserver); +#endif /* DNS_SERVER_ADDRESS */ + + LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", + sizeof(struct dns_query) == SIZEOF_DNS_QUERY); + LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER", + sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT); + + LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); + + /* if dns client not yet initialized... */ +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) + if (dns_pcbs[0] == NULL) { + dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL); + + /* initialize DNS table not needed (initialized to zero since it is a + * global variable) */ + LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", + DNS_STATE_UNUSED == 0); + + /* initialize DNS client */ + udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0); + udp_recv(dns_pcbs[0], dns_recv, NULL); + } +#endif + +#if DNS_LOCAL_HOSTLIST + dns_init_local(); +#endif +} + +/** + * @ingroup dns + * Initialize one of the DNS servers. + * + * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS + * @param dnsserver IP address of the DNS server to set + */ +void +dns_setserver(u8_t numdns, const ip_addr_t *dnsserver) +{ + if (numdns < DNS_MAX_SERVERS) { + if (dnsserver != NULL) { + dns_servers[numdns] = (*dnsserver); + } else { + dns_servers[numdns] = *IP_ADDR_ANY; + } + } +} + +/** + * @ingroup dns + * Obtain one of the currently configured DNS server. + * + * @param numdns the index of the DNS server + * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS + * server has not been configured. + */ +const ip_addr_t* +dns_getserver(u8_t numdns) +{ + if (numdns < DNS_MAX_SERVERS) { + return &dns_servers[numdns]; + } else { + return IP_ADDR_ANY; + } +} + +/** + * The DNS resolver client timer - handle retries and timeouts and should + * be called every DNS_TMR_INTERVAL milliseconds (every second by default). + */ +void +dns_tmr(void) +{ + LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); + dns_check_entries(); +} + +#if DNS_LOCAL_HOSTLIST +static void +dns_init_local(void) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) + size_t i; + struct local_hostlist_entry *entry; + /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ + struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; + size_t namelen; + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) { + struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; + LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); + namelen = strlen(init_entry->name); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); + if (entry != NULL) { + char* entry_name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY(entry_name, init_entry->name, namelen); + entry_name[namelen] = 0; + entry->name = entry_name; + entry->addr = init_entry->addr; + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ +} + +/** + * @ingroup dns + * Iterate the local host-list for a hostname. + * + * @param iterator_fn a function that is called for every entry in the local host-list + * @param iterator_arg 3rd argument passed to iterator_fn + * @return the number of entries in the local host-list + */ +size_t +dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) +{ + size_t i; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + i = 0; + while (entry != NULL) { + if (iterator_fn != NULL) { + iterator_fn(entry->name, &entry->addr, iterator_arg); + } + i++; + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { + if (iterator_fn != NULL) { + iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg); + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return i; +} + +/** + * @ingroup dns + * Scans the local host-list for a hostname. + * + * @param hostname Hostname to look for in the local host-list + * @param addr the first IP address for the hostname in the local host-list or + * IPADDR_NONE if not found. + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!) + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!) + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + * @return ERR_OK if found, ERR_ARG if not found + */ +err_t +dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) +{ + LWIP_UNUSED_ARG(dns_addrtype); + return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); +} + +/* Internal implementation for dns_local_lookup and dns_lookup */ +static err_t +dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC + struct local_hostlist_entry *entry = local_hostlist_dynamic; + while (entry != NULL) { + if ((lwip_stricmp(entry->name, hostname) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { + if (addr) { + ip_addr_copy(*addr, entry->addr); + } + return ERR_OK; + } + entry = entry->next; + } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + size_t i; + for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { + if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { + if (addr) { + ip_addr_copy(*addr, local_hostlist_static[i].addr); + } + return ERR_OK; + } + } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + return ERR_ARG; +} + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** + * @ingroup dns + * Remove all entries from the local host-list for a specific hostname + * and/or IP address + * + * @param hostname hostname for which entries shall be removed from the local + * host-list + * @param addr address for which entries shall be removed from the local host-list + * @return the number of removed entries + */ +int +dns_local_removehost(const char *hostname, const ip_addr_t *addr) +{ + int removed = 0; + struct local_hostlist_entry *entry = local_hostlist_dynamic; + struct local_hostlist_entry *last_entry = NULL; + while (entry != NULL) { + if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && + ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { + struct local_hostlist_entry *free_entry; + if (last_entry != NULL) { + last_entry->next = entry->next; + } else { + local_hostlist_dynamic = entry->next; + } + free_entry = entry; + entry = entry->next; + memp_free(MEMP_LOCALHOSTLIST, free_entry); + removed++; + } else { + last_entry = entry; + entry = entry->next; + } + } + return removed; +} + +/** + * @ingroup dns + * Add a hostname/IP address pair to the local host-list. + * Duplicates are not checked. + * + * @param hostname hostname of the new entry + * @param addr IP address of the new entry + * @return ERR_OK if succeeded or ERR_MEM on memory error + */ +err_t +dns_local_addhost(const char *hostname, const ip_addr_t *addr) +{ + struct local_hostlist_entry *entry; + size_t namelen; + char* entry_name; + LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); + namelen = strlen(hostname); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); + if (entry == NULL) { + return ERR_MEM; + } + entry_name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY(entry_name, hostname, namelen); + entry_name[namelen] = 0; + entry->name = entry_name; + ip_addr_copy(entry->addr, *addr); + entry->next = local_hostlist_dynamic; + local_hostlist_dynamic = entry; + return ERR_OK; +} +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** + * @ingroup dns + * Look up a hostname in the array of known hostnames. + * + * @note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function dns_enqueue() can be used to send a query + * for a hostname. + * + * @param name the hostname to look up + * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to + * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname + * was not found in the cached dns_table. + * @return ERR_OK if found, ERR_ARG if not found + */ +static err_t +dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +{ + u8_t i; +#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) +#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ +#if DNS_LOCAL_HOSTLIST + if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN + if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#endif /* DNS_LOOKUP_LOCAL_EXTERN */ + + /* Walk through name list, return entry if found. If not, return NULL. */ + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + if ((dns_table[i].state == DNS_STATE_DONE) && + (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && + LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); + ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + if (addr) { + ip_addr_copy(*addr, dns_table[i].ipaddr); + } + return ERR_OK; + } + } + + return ERR_ARG; +} + +/** + * Compare the "dotted" name "query" with the encoded name "response" + * to make sure an answer from the DNS server matches the current dns_table + * entry (otherwise, answers might arrive late for hostname not on the list + * any more). + * + * @param query hostname (not encoded) from the dns_table + * @param p pbuf containing the encoded hostname in the DNS response + * @param start_offset offset into p where the name starts + * @return 0xFFFF: names differ, other: names equal -> offset behind name + */ +static u16_t +dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset) +{ + int n; + u16_t response_offset = start_offset; + + do { + n = pbuf_try_get_at(p, response_offset++); + if (n < 0) { + return 0xFFFF; + } + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name: cannot be equal since we don't send them */ + return 0xFFFF; + } else { + /* Not compressed name */ + while (n > 0) { + int c = pbuf_try_get_at(p, response_offset); + if (c < 0) { + return 0xFFFF; + } + if ((*query) != (u8_t)c) { + return 0xFFFF; + } + ++response_offset; + ++query; + --n; + } + ++query; + } + n = pbuf_try_get_at(p, response_offset); + if (n < 0) { + return 0xFFFF; + } + } while (n != 0); + + return response_offset + 1; +} + +/** + * Walk through a compact encoded DNS name and return the end of the name. + * + * @param p pbuf containing the name + * @param query_idx start index into p pointing to encoded DNS name in the DNS server response + * @return index to end of the name + */ +static u16_t +dns_skip_name(struct pbuf* p, u16_t query_idx) +{ + int n; + u16_t offset = query_idx; + + do { + n = pbuf_try_get_at(p, offset++); + if (n < 0) { + return 0xFFFF; + } + /** @see RFC 1035 - 4.1.4. Message compression */ + if ((n & 0xc0) == 0xc0) { + /* Compressed name: since we only want to skip it (not check it), stop here */ + break; + } else { + /* Not compressed name */ + if (offset + n >= p->tot_len) { + return 0xFFFF; + } + offset = (u16_t)(offset + n); + } + n = pbuf_try_get_at(p, offset); + if (n < 0) { + return 0xFFFF; + } + } while (n != 0); + + return offset + 1; +} + +/** + * Send a DNS query packet. + * + * @param idx the DNS table entry index for which to send a request + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t +dns_send(u8_t idx) +{ + err_t err; + struct dns_hdr hdr; + struct dns_query qry; + struct pbuf *p; + u16_t query_idx, copy_len; + const char *hostname, *hostname_part; + u8_t n; + u8_t pcb_idx; + struct dns_table_entry* entry = &dns_table[idx]; + + LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", + (u16_t)(entry->server_idx), entry->name)); + LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); + if (ip_addr_isany_val(dns_servers[entry->server_idx]) +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + && !entry->is_mdns +#endif + ) { + /* DNS server not valid anymore, e.g. PPP netif has been shut down */ + /* call specified callback function if provided */ + dns_call_found(idx, NULL); + /* flush this entry */ + entry->state = DNS_STATE_UNUSED; + return ERR_OK; + } + + /* if here, we have either a new query or a retry on a previous query to process */ + p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + + SIZEOF_DNS_QUERY), PBUF_RAM); + if (p != NULL) { + const ip_addr_t* dst; + u16_t dst_port; + /* fill dns header */ + memset(&hdr, 0, SIZEOF_DNS_HDR); + hdr.id = lwip_htons(entry->txid); + hdr.flags1 = DNS_FLAG1_RD; + hdr.numquestions = PP_HTONS(1); + pbuf_take(p, &hdr, SIZEOF_DNS_HDR); + hostname = entry->name; + --hostname; + + /* convert hostname into suitable query format. */ + query_idx = SIZEOF_DNS_HDR; + do { + ++hostname; + hostname_part = hostname; + for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { + ++n; + } + copy_len = (u16_t)(hostname - hostname_part); + pbuf_put_at(p, query_idx, n); + pbuf_take_at(p, hostname_part, copy_len, query_idx + 1); + query_idx += n + 1; + } while (*hostname != 0); + pbuf_put_at(p, query_idx, 0); + query_idx++; + + /* fill dns query */ + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { + qry.type = PP_HTONS(DNS_RRTYPE_AAAA); + } else { + qry.type = PP_HTONS(DNS_RRTYPE_A); + } + qry.cls = PP_HTONS(DNS_RRCLASS_IN); + pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + pcb_idx = entry->pcb_idx; +#else + pcb_idx = 0; +#endif + /* send dns packet */ + LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", + entry->txid, entry->name, entry->server_idx)); +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (entry->is_mdns) { + dst_port = DNS_MQUERY_PORT; +#if LWIP_IPV6 + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) + { + dst = &dns_mquery_v6group; + } +#endif +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif +#if LWIP_IPV4 + { + dst = &dns_mquery_v4group; + } +#endif + } else +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + dst_port = DNS_SERVER_PORT; + dst = &dns_servers[entry->server_idx]; + } + err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); + + /* free pbuf */ + pbuf_free(p); + } else { + err = ERR_MEM; + } + + return err; +} + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) +static struct udp_pcb* +dns_alloc_random_port(void) +{ + err_t err; + struct udp_pcb* ret; + + ret = udp_new_ip_type(IPADDR_TYPE_ANY); + if (ret == NULL) { + /* out of memory, have to reuse an existing pcb */ + return NULL; + } + do { + u16_t port = (u16_t)DNS_RAND_TXID(); + if (!DNS_PORT_ALLOWED(port)) { + /* this port is not allowed, try again */ + err = ERR_USE; + continue; + } + err = udp_bind(ret, IP_ANY_TYPE, port); + } while (err == ERR_USE); + if (err != ERR_OK) { + udp_remove(ret); + return NULL; + } + udp_recv(ret, dns_recv, NULL); + return ret; +} + +/** + * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used + * for sending a request + * + * @return an index into dns_pcbs + */ +static u8_t +dns_alloc_pcb(void) +{ + u8_t i; + u8_t idx; + + for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { + if (dns_pcbs[i] == NULL) { + break; + } + } + if (i < DNS_MAX_SOURCE_PORTS) { + dns_pcbs[i] = dns_alloc_random_port(); + if (dns_pcbs[i] != NULL) { + /* succeeded */ + dns_last_pcb_idx = i; + return i; + } + } + /* if we come here, creating a new UDP pcb failed, so we have to use + an already existing one */ + for (i = 0, idx = dns_last_pcb_idx + 1; i < DNS_MAX_SOURCE_PORTS; i++, idx++) { + if (idx >= DNS_MAX_SOURCE_PORTS) { + idx = 0; + } + if (dns_pcbs[idx] != NULL) { + dns_last_pcb_idx = idx; + return idx; + } + } + return DNS_MAX_SOURCE_PORTS; +} +#endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ + +/** + * dns_call_found() - call the found callback and check if there are duplicate + * entries for the given hostname. If there are any, their found callback will + * be called and they will be removed. + * + * @param idx dns table index of the entry that is resolved or removed + * @param addr IP address for the hostname (or NULL on error or memory shortage) + */ +static void +dns_call_found(u8_t idx, ip_addr_t* addr) +{ +#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) + u8_t i; +#endif + +#if LWIP_IPV4 && LWIP_IPV6 + if (addr != NULL) { + /* check that address type matches the request and adapt the table entry */ + if (IP_IS_V6_VAL(*addr)) { + LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); + dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; + } else { + LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); + dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; + } + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + for (i = 0; i < DNS_MAX_REQUESTS; i++) { + if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { + (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); + /* flush this entry */ + dns_requests[i].found = NULL; + } + } +#else + if (dns_requests[idx].found) { + (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); + } + dns_requests[idx].found = NULL; +#endif +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + /* close the pcb used unless other request are using it */ + for (i = 0; i < DNS_MAX_REQUESTS; i++) { + if (i == idx) { + continue; /* only check other requests */ + } + if (dns_table[i].state == DNS_STATE_ASKING) { + if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { + /* another request is still using the same pcb */ + dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; + break; + } + } + } + if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { + /* if we come here, the pcb is not used any more and can be removed */ + udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); + dns_pcbs[dns_table[idx].pcb_idx] = NULL; + dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; + } +#endif +} + +/* Create a query transmission ID that is unique for all outstanding queries */ +static u16_t +dns_create_txid(void) +{ + u16_t txid; + u8_t i; + +again: + txid = (u16_t)DNS_RAND_TXID(); + + /* check whether the ID is unique */ + for (i = 0; i < DNS_TABLE_SIZE; i++) { + if ((dns_table[i].state == DNS_STATE_ASKING) && + (dns_table[i].txid == txid)) { + /* ID already used by another pending query */ + goto again; + } + } + + return txid; +} + +/** + * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. + * Check an entry in the dns_table: + * - send out query for new entries + * - retry old pending entries on timeout (also with different servers) + * - remove completed entries from the table if their TTL has expired + * + * @param i index of the dns_table entry to check + */ +static void +dns_check_entry(u8_t i) +{ + err_t err; + struct dns_table_entry *entry = &dns_table[i]; + + LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); + + switch (entry->state) { + case DNS_STATE_NEW: + /* initialize new entry */ + entry->txid = dns_create_txid(); + entry->state = DNS_STATE_ASKING; + entry->server_idx = 0; + entry->tmr = 1; + entry->retries = 0; + + /* send DNS packet for this entry */ + err = dns_send(i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + break; + case DNS_STATE_ASKING: + if (--entry->tmr == 0) { + if (++entry->retries == DNS_MAX_RETRIES) { + if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1]) +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + && !entry->is_mdns +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + ) { + /* change of server */ + entry->server_idx++; + entry->tmr = 1; + entry->retries = 0; + } else { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); + /* call specified callback function if provided */ + dns_call_found(i, NULL); + /* flush this entry */ + entry->state = DNS_STATE_UNUSED; + break; + } + } else { + /* wait longer for the next retry */ + entry->tmr = entry->retries; + } + + /* send DNS packet for this entry */ + err = dns_send(i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } + } + break; + case DNS_STATE_DONE: + /* if the time to live is nul */ + if ((entry->ttl == 0) || (--entry->ttl == 0)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); + /* flush this entry, there cannot be any related pending entries in this state */ + entry->state = DNS_STATE_UNUSED; + } + break; + case DNS_STATE_UNUSED: + /* nothing to do */ + break; + default: + LWIP_ASSERT("unknown dns_table entry state:", 0); + break; + } +} + +/** + * Call dns_check_entry for each entry in dns_table - check all entries. + */ +static void +dns_check_entries(void) +{ + u8_t i; + + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + dns_check_entry(i); + } +} + +/** + * Save TTL and call dns_call_found for correct response. + */ +static void +dns_correct_response(u8_t idx, u32_t ttl) +{ + struct dns_table_entry *entry = &dns_table[idx]; + + entry->state = DNS_STATE_DONE; + + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); + ip_addr_debug_print(DNS_DEBUG, (&(entry->ipaddr))); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + + /* read the answer resource record's TTL, and maximize it if needed */ + entry->ttl = ttl; + if (entry->ttl > DNS_MAX_TTL) { + entry->ttl = DNS_MAX_TTL; + } + dns_call_found(idx, &entry->ipaddr); + + if (entry->ttl == 0) { + /* RFC 883, page 29: "Zero values are + interpreted to mean that the RR can only be used for the + transaction in progress, and should not be cached." + -> flush this entry now */ + /* entry reused during callback? */ + if (entry->state == DNS_STATE_DONE) { + entry->state = DNS_STATE_UNUSED; + } + } +} +/** + * Receive input function for DNS response packets arriving for the dns UDP pcb. + */ +static void +dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + u8_t i; + u16_t txid; + u16_t res_idx; + struct dns_hdr hdr; + struct dns_answer ans; + struct dns_query qry; + u16_t nquestions, nanswers; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(port); + + /* is the dns message big enough ? */ + if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); + /* free pbuf and return */ + goto memerr; + } + + /* copy dns payload inside static buffer for processing */ + if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { + /* Match the ID in the DNS header with the name table. */ + txid = lwip_htons(hdr.id); + for (i = 0; i < DNS_TABLE_SIZE; i++) { + const struct dns_table_entry *entry = &dns_table[i]; + if ((entry->state == DNS_STATE_ASKING) && + (entry->txid == txid)) { + + /* We only care about the question(s) and the answers. The authrr + and the extrarr are simply discarded. */ + nquestions = lwip_htons(hdr.numquestions); + nanswers = lwip_htons(hdr.numanswers); + + /* Check for correct response. */ + if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); + goto memerr; /* ignore this packet */ + } + if (nquestions != 1) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto memerr; /* ignore this packet */ + } + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (!entry->is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* Check whether response comes from the same network address to which the + question was sent. (RFC 5452) */ + if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { + goto memerr; /* ignore this packet */ + } + } + + /* Check if the name in the "question" part match with the name in the entry and + skip it if equal. */ + res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); + if (res_idx == 0xFFFF) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto memerr; /* ignore this packet */ + } + + /* check if "question" part matches the request */ + if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { + goto memerr; /* ignore this packet */ + } + if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || + (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || + (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); + goto memerr; /* ignore this packet */ + } + /* skip the rest of the "question" part */ + res_idx += SIZEOF_DNS_QUERY; + + /* Check for error. If so, call callback to inform. */ + if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); + } else { + while ((nanswers > 0) && (res_idx < p->tot_len)) { + /* skip answer resource record's host name */ + res_idx = dns_skip_name(p, res_idx); + if (res_idx == 0xFFFF) { + goto memerr; /* ignore this packet */ + } + + /* Check for IP address type and Internet class. Others are discarded. */ + if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { + goto memerr; /* ignore this packet */ + } + res_idx += SIZEOF_DNS_ANSWER; + + if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { +#if LWIP_IPV4 + if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { +#if LWIP_IPV4 && LWIP_IPV6 + if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + ip4_addr_t ip4addr; + /* read the IP address after answer resource record's header */ + if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { + goto memerr; /* ignore this packet */ + } + ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); + pbuf_free(p); + /* handle correct response */ + dns_correct_response(i, lwip_ntohl(ans.ttl)); + return; + } + } +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_t)))) { +#if LWIP_IPV4 && LWIP_IPV6 + if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + ip6_addr_t ip6addr; + /* read the IP address after answer resource record's header */ + if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx) != sizeof(ip6_addr_t)) { + goto memerr; /* ignore this packet */ + } + ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr); + pbuf_free(p); + /* handle correct response */ + dns_correct_response(i, lwip_ntohl(ans.ttl)); + return; + } + } +#endif /* LWIP_IPV6 */ + } + /* skip this answer */ + if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { + goto memerr; /* ignore this packet */ + } + res_idx += lwip_htons(ans.len); + --nanswers; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || + (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { + if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { + /* IPv4 failed, try IPv6 */ + dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; + } else { + /* IPv6 failed, try IPv4 */ + dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; + } + pbuf_free(p); + dns_table[i].state = DNS_STATE_NEW; + dns_check_entry(i); + return; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); + } + /* call callback to indicate error, clean up memory and return */ + pbuf_free(p); + dns_call_found(i, NULL); + dns_table[i].state = DNS_STATE_UNUSED; + return; + } + } + } + +memerr: + /* deallocate memory and return */ + pbuf_free(p); + return; +} + +/** + * Queues a new hostname to resolve and sends out a DNS query for that hostname + * + * @param name the hostname that is to be queried + * @param hostnamelen length of the hostname + * @param found a callback function to be called on success, failure or timeout + * @param callback_arg argument to pass to the callback function + * @return err_t return code. + */ +static err_t +dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, + void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) +{ + u8_t i; + u8_t lseq, lseqi; + struct dns_table_entry *entry = NULL; + size_t namelen; + struct dns_req_entry* req; + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + u8_t r; + /* check for duplicate entries */ + for (i = 0; i < DNS_TABLE_SIZE; i++) { + if ((dns_table[i].state == DNS_STATE_ASKING) && + (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { +#if LWIP_IPV4 && LWIP_IPV6 + if (dns_table[i].reqaddrtype != dns_addrtype) { + /* requested address types don't match + this can lead to 2 concurrent requests, but mixing the address types + for the same host should not be that common */ + continue; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + /* this is a duplicate entry, find a free request entry */ + for (r = 0; r < DNS_MAX_REQUESTS; r++) { + if (dns_requests[r].found == 0) { + dns_requests[r].found = found; + dns_requests[r].arg = callback_arg; + dns_requests[r].dns_table_idx = i; + LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); + return ERR_INPROGRESS; + } + } + } + } + /* no duplicate entries found */ +#endif + + /* search an unused entry, or the oldest one */ + lseq = 0; + lseqi = DNS_TABLE_SIZE; + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + entry = &dns_table[i]; + /* is it an unused entry ? */ + if (entry->state == DNS_STATE_UNUSED) { + break; + } + /* check if this is the oldest completed entry */ + if (entry->state == DNS_STATE_DONE) { + u8_t age = dns_seqno - entry->seqno; + if (age > lseq) { + lseq = age; + lseqi = i; + } + } + } + + /* if we don't have found an unused entry, use the oldest completed one */ + if (i == DNS_TABLE_SIZE) { + if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { + /* no entry can be used now, table is full */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); + return ERR_MEM; + } else { + /* use the oldest completed one */ + i = lseqi; + entry = &dns_table[i]; + } + } + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) + /* find a free request entry */ + req = NULL; + for (r = 0; r < DNS_MAX_REQUESTS; r++) { + if (dns_requests[r].found == NULL) { + req = &dns_requests[r]; + break; + } + } + if (req == NULL) { + /* no request entry can be used now, table is full */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); + return ERR_MEM; + } + req->dns_table_idx = i; +#else + /* in this configuration, the entry index is the same as the request index */ + req = &dns_requests[i]; +#endif + + /* use this entry */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); + + /* fill the entry */ + entry->state = DNS_STATE_NEW; + entry->seqno = dns_seqno; + LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); + LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); + req->found = found; + req->arg = callback_arg; + namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH-1); + MEMCPY(entry->name, name, namelen); + entry->name[namelen] = 0; + +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) + entry->pcb_idx = dns_alloc_pcb(); + if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { + /* failed to get a UDP pcb */ + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); + entry->state = DNS_STATE_UNUSED; + req->found = NULL; + return ERR_MEM; + } + LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); +#endif + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + entry->is_mdns = is_mdns; +#endif + + dns_seqno++; + + /* force to send query without waiting timer */ + dns_check_entry(i); + + /* dns query is enqueued */ + return ERR_INPROGRESS; +} + +/** + * @ingroup dns + * Resolve a hostname (string) into an IP address. + * NON-BLOCKING callback version for use with raw API!!! + * + * Returns immediately with one of err_t return codes: + * - ERR_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ERR_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ERR_ARG: dns client not initialized or invalid hostname + * + * @param hostname the hostname that is to be queried + * @param addr pointer to a ip_addr_t where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @return a err_t return code. + */ +err_t +dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg) +{ + return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); +} + +/** + * @ingroup dns + * Like dns_gethostbyname, but returned address type can be controlled: + * @param hostname the hostname that is to be queried + * @param addr pointer to a ip_addr_t where to store the address if it is already + * cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + */ +err_t +dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, + void *callback_arg, u8_t dns_addrtype) +{ + size_t hostnamelen; +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + u8_t is_mdns; +#endif + /* not initialized or no valid server yet, or invalid addr pointer + * or invalid hostname or invalid hostname length */ + if ((addr == NULL) || + (!hostname) || (!hostname[0])) { + return ERR_ARG; + } +#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) + if (dns_pcbs[0] == NULL) { + return ERR_ARG; + } +#endif + hostnamelen = strlen(hostname); + if (hostnamelen >= DNS_MAX_NAME_LENGTH) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); + return ERR_ARG; + } + + +#if LWIP_HAVE_LOOPIF + if (strcmp(hostname, "localhost") == 0) { + ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); + return ERR_OK; + } +#endif /* LWIP_HAVE_LOOPIF */ + + /* host name already in octet notation? set ip addr and return ERR_OK */ + if (ipaddr_aton(hostname, addr)) { +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || + (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + { + return ERR_OK; + } + } + /* already have this address cached? */ + if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + return ERR_OK; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { + /* fallback to 2nd IP type and try again to lookup */ + u8_t fallback; + if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { + fallback = LWIP_DNS_ADDRTYPE_IPV6; + } else { + fallback = LWIP_DNS_ADDRTYPE_IPV4; + } + if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { + return ERR_OK; + } + } +#else /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_UNUSED_ARG(dns_addrtype); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_DNS_SUPPORT_MDNS_QUERIES + if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { + is_mdns = 1; + } else { + is_mdns = 0; + } + + if (!is_mdns) +#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ + { + /* prevent calling found callback if no server is set, return error instead */ + if (ip_addr_isany_val(dns_servers[0])) { + return ERR_VAL; + } + } + + /* queue query with specified callback */ + return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) + LWIP_DNS_ISMDNS_ARG(is_mdns)); +} + +#endif /* LWIP_DNS */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/inet_chksum.c b/Sming/third-party/lwip2/lwip2-src/src/core/inet_chksum.c new file mode 100644 index 0000000000..917f3e4f1a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/inet_chksum.c @@ -0,0 +1,609 @@ +/** + * @file + * Incluse internet checksum functions.\n + * + * These are some reference implementations of the checksum algorithm, with the + * aim of being simple, correct and fully portable. Checksumming is the + * first thing you would want to optimize for your platform. If you create + * your own version, link it in and in your cc.h put: + * + * \#define LWIP_CHKSUM your_checksum_routine + * + * Or you can select from the implementations below by defining + * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet_chksum.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + +#include + +#ifndef LWIP_CHKSUM +# define LWIP_CHKSUM lwip_standard_chksum +# ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 2 +# endif +u16_t lwip_standard_chksum(const void *dataptr, int len); +#endif +/* If none set: */ +#ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 0 +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ +/** + * lwip checksum + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * @note accumulator size limits summable length to 64k + * @note host endianess is irrelevant (p3 RFC1071) + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + u32_t acc; + u16_t src; + const u8_t *octetptr; + + acc = 0; + /* dataptr may be at odd or even addresses */ + octetptr = (const u8_t*)dataptr; + while (len > 1) { + /* declare first octet as most significant + thus assume network order, ignoring host order */ + src = (*octetptr) << 8; + octetptr++; + /* declare second octet as least significant */ + src |= (*octetptr); + octetptr++; + acc += src; + len -= 2; + } + if (len > 0) { + /* accumulate remaining octet */ + src = (*octetptr) << 8; + acc += src; + } + /* add deferred carry bits */ + acc = (acc >> 16) + (acc & 0x0000ffffUL); + if ((acc & 0xffff0000UL) != 0) { + acc = (acc >> 16) + (acc & 0x0000ffffUL); + } + /* This maybe a little confusing: reorder sum using lwip_htons() + instead of lwip_ntohs() since it has a little less call overhead. + The caller must invert bits for Internet sum ! */ + return lwip_htons((u16_t)acc); +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ +/* + * Curt McDowell + * Broadcom Corp. + * csm@broadcom.com + * + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum) + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + const u8_t *pb = (const u8_t *)dataptr; + const u16_t *ps; + u16_t t = 0; + u32_t sum = 0; + int odd = ((mem_ptr_t)pb & 1); + + /* Get aligned to u16_t */ + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + /* Add the bulk of the data */ + ps = (const u16_t *)(const void *)pb; + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* Consume left-over byte, if any */ + if (len > 0) { + ((u8_t *)&t)[0] = *(const u8_t *)ps; + } + + /* Add end bytes */ + sum += t; + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + /* Swap if alignment was odd */ + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time. + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * @return host order (!) lwip checksum (non-inverted Internet sum) + * + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ +u16_t +lwip_standard_chksum(const void *dataptr, int len) +{ + const u8_t *pb = (const u8_t *)dataptr; + const u16_t *ps; + u16_t t = 0; + const u32_t *pl; + u32_t sum = 0, tmp; + /* starts at odd byte address? */ + int odd = ((mem_ptr_t)pb & 1); + + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + ps = (const u16_t *)(const void*)pb; + + if (((mem_ptr_t)ps & 3) && len > 1) { + sum += *ps++; + len -= 2; + } + + pl = (const u32_t *)(const void*)ps; + + while (len > 7) { + tmp = sum + *pl++; /* ping */ + if (tmp < sum) { + tmp++; /* add back carry */ + } + + sum = tmp + *pl++; /* pong */ + if (sum < tmp) { + sum++; /* add back carry */ + } + + len -= 8; + } + + /* make room in upper bits */ + sum = FOLD_U32T(sum); + + ps = (const u16_t *)pl; + + /* 16-bit aligned word remaining? */ + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* dangling tail byte remaining? */ + if (len > 0) { /* include odd byte */ + ((u8_t *)&t)[0] = *(const u8_t *)ps; + } + + sum += t; /* add end bytes */ + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + sum = FOLD_U32T(sum); + sum = FOLD_U32T(sum); + + if (odd) { + sum = SWAP_BYTES_IN_WORD(sum); + } + + return (u16_t)sum; +} +#endif + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) +{ + struct pbuf *q; + u8_t swapped = 0; + + /* iterate through all pbuf in chain */ + for (q = p; q != NULL; q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + acc += LWIP_CHKSUM(q->payload, q->len); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* just executing this next line is probably faster that the if statement needed + to check whether we really need to execute it, and does no harm */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)lwip_htons((u16_t)proto); + acc += (u32_t)lwip_htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +#if LWIP_IPV4 +/* inet_chksum_pseudo: + * + * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip4_addr_t *src, const ip4_addr_t *dest) +{ + u32_t acc; + u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dest destination ipv6 address (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip6_addr_t *src, const ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#endif /* LWIP_IPV6 */ + +/* ip_chksum_pseudo: + * + * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip_addr_t *src, const ip_addr_t *dest) +{ +#if LWIP_IPV6 + if (IP_IS_V6(dest)) { + return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest)); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest)); + } +#endif /* LWIP_IPV4 */ +} + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, u32_t acc) +{ + struct pbuf *q; + u8_t swapped = 0; + u16_t chklen; + + /* iterate through all pbuf in chain */ + for (q = p; (q != NULL) && (chksum_len > 0); q = q->next) { + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", + (void *)q, (void *)q->next)); + chklen = q->len; + if (chklen > chksum_len) { + chklen = chksum_len; + } + acc += LWIP_CHKSUM(q->payload, chklen); + chksum_len -= chklen; + LWIP_ASSERT("delete me", chksum_len < 0x7fff); + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ + /* fold the upper bit down */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + acc += (u32_t)lwip_htons((u16_t)proto); + acc += (u32_t)lwip_htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is probably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +#if LWIP_IPV4 +/* inet_chksum_pseudo_partial: + * + * Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest) +{ + u32_t acc; + u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. Will only compute for a + * portion of the payload. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param chksum_len number of payload bytes used to compute chksum + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dest destination ipv6 address (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} +#endif /* LWIP_IPV6 */ + +/* ip_chksum_pseudo_partial: + * + * Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest) +{ +#if LWIP_IPV6 + if (IP_IS_V6(dest)) { + return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest)); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest)); + } +#endif /* LWIP_IPV4 */ +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarily for IP + * and ICMP. + * + * @param dataptr start of the buffer to calculate the checksum (no alignment needed) + * @param len length of the buffer to calculate the checksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ + +u16_t +inet_chksum(const void *dataptr, u16_t len) +{ + return (u16_t)~(unsigned int)LWIP_CHKSUM(dataptr, len); +} + +/** + * Calculate a checksum over a chain of pbufs (without pseudo-header, much like + * inet_chksum only pbufs are used). + * + * @param p pbuf chain over that the checksum should be calculated + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ + u32_t acc; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + for (q = p; q != NULL; q = q->next) { + acc += LWIP_CHKSUM(q->payload, q->len); + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + } + + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + return (u16_t)~(acc & 0xffffUL); +} + +/* These are some implementations for LWIP_CHKSUM_COPY, which copies data + * like MEMCPY but generates a checksum at the same time. Since this is a + * performance-sensitive function, you might want to create your own version + * in assembly targeted at your hardware by defining it in lwipopts.h: + * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) + */ + +#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ +/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. + * For architectures with big caches, data might still be in cache when + * generating the checksum after copying. + */ +u16_t +lwip_chksum_copy(void *dst, const void *src, u16_t len) +{ + MEMCPY(dst, src, len); + return LWIP_CHKSUM(dst, len); +} +#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/init.c b/Sming/third-party/lwip2/lwip2-src/src/core/init.c new file mode 100644 index 0000000000..313146133d --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/init.c @@ -0,0 +1,385 @@ +/** + * @file + * Modules initialization + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#include "lwip/opt.h" + +#include "lwip/init.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/sockets.h" +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/timeouts.h" +#include "lwip/etharp.h" +#include "lwip/ip6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/api.h" + +#include "netif/ppp/ppp_opts.h" +#include "netif/ppp/ppp_impl.h" + +#ifndef LWIP_SKIP_PACKING_CHECK + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct packed_struct_test +{ + PACK_STRUCT_FLD_8(u8_t dummy1); + PACK_STRUCT_FIELD(u32_t dummy2); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5 + +#endif + +/* Compile-time sanity checks for configuration errors. + * These can be done independently of LWIP_DEBUG, without penalty. + */ +#ifndef BYTE_ORDER + #error "BYTE_ORDER is not defined, you have to define it in your cc.h" +#endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_UDPLITE) + #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DHCP) + #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS) + #error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DNS) + #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ +#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) + #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" +#endif +#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) + #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) + #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) + #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) + #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS) + #error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h" +#endif +#if (LWIP_IGMP && !LWIP_IPV4) + #error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" +#endif +#if (LWIP_MULTICAST_TX_OPTIONS && !LWIP_IPV4) + #error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h" +#endif +#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) + #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" +#endif +/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))) + #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#endif +#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) + #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" +#endif +#endif /* !MEMP_MEM_MALLOC */ +#if LWIP_WND_SCALE +#if (LWIP_TCP && (TCP_WND > 0xffffffff)) + #error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_RCV_SCALE > 14)) + #error "The maximum valid window scale value is 14!" +#endif +#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) + #error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" +#endif +#if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0)) + #error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" +#endif +#else /* LWIP_WND_SCALE */ +#if (LWIP_TCP && (TCP_WND > 0xffff)) + #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" +#endif +#endif /* LWIP_WND_SCALE */ +#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) + #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) + #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" +#endif +#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) + #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" +#endif +#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))) + #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" +#endif +#if (LWIP_NETIF_API && (NO_SYS==1)) + #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) + #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if (LWIP_PPP_API && (NO_SYS==1)) + #error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if (LWIP_PPP_API && (PPP_SUPPORT==0)) + #error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) + #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) + #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && LWIP_AUTOIP) + #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) + #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" +#endif +#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) + #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" +#endif +#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) + #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" +#endif +#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) + #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" +#endif +#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) + #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" +#endif +#if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT && !PPPOL2TP_SUPPORT + #error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on" +#endif +#if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT + #error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on" +#endif +#if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4 + #error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on" +#endif +#if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6 + #error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" +#endif +#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) + #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" +#endif +#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING + #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" +#endif +#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE + #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" +#endif +#if LWIP_NETCONN && LWIP_TCP +#if NETCONN_COPY != TCP_WRITE_FLAG_COPY + #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" +#endif +#if NETCONN_MORE != TCP_WRITE_FLAG_MORE + #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" +#endif +#endif /* LWIP_NETCONN && LWIP_TCP */ +#if LWIP_SOCKET +/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ +#if SO_REUSEADDR != SOF_REUSEADDR + #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" +#endif +#if SO_KEEPALIVE != SOF_KEEPALIVE + #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" +#endif +#if SO_BROADCAST != SOF_BROADCAST + #error "WARNING: SO_BROADCAST != SOF_BROADCAST" +#endif +#endif /* LWIP_SOCKET */ + + +/* Compile-time checks for deprecated options. + */ +#ifdef MEMP_NUM_TCPIP_MSG + #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef TCP_REXMIT_DEBUG + #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef RAW_STATS + #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_QUEUE_FIRST + #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_ALWAYS_INSERT + #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." +#endif +#if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED) + #error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)" +#endif + +#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS +#define LWIP_DISABLE_TCP_SANITY_CHECKS 0 +#endif +#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 +#endif + +/* MEMP sanity checks */ +#if MEMP_MEM_MALLOC +#if !LWIP_DISABLE_MEMP_SANITY_CHECKS +#if LWIP_NETCONN || LWIP_SOCKET +#if !MEMP_NUM_NETCONN && LWIP_SOCKET +#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!" +#endif +#else /* MEMP_MEM_MALLOC */ +#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) +#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." +#endif +#endif /* LWIP_NETCONN || LWIP_SOCKET */ +#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ +#if MEM_USE_POOLS +#error "MEMP_MEM_MALLOC and MEM_USE_POOLS cannot be enabled at the same time" +#endif +#ifdef LWIP_HOOK_MEMP_AVAILABLE +#error "LWIP_HOOK_MEMP_AVAILABLE doesn't make sense with MEMP_MEM_MALLOC" +#endif +#endif /* MEMP_MEM_MALLOC */ + +/* TCP sanity checks */ +#if !LWIP_DISABLE_TCP_SANITY_CHECKS +#if LWIP_TCP +#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) + #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_BUF < (2 * TCP_MSS) + #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) + #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDLOWAT >= TCP_SND_BUF + #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) + #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" +#endif +#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN + #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + #error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) + #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_WND < TCP_MSS + #error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#endif /* LWIP_TCP */ +#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ + +/** + * @ingroup lwip_nosys + * Initialize all modules. + * Use this in NO_SYS mode. Use tcpip_init() otherwise. + */ +void +lwip_init(void) +{ +#ifndef LWIP_SKIP_CONST_CHECK + int a; + LWIP_UNUSED_ARG(a); + LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void*, &a) == &a); +#endif +#ifndef LWIP_SKIP_PACKING_CHECK + LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE); +#endif + + /* Modules initialization */ + stats_init(); +#if !NO_SYS + sys_init(); +#endif /* !NO_SYS */ + mem_init(); + memp_init(); + pbuf_init(); + netif_init(); +#if LWIP_IPV4 + ip_init(); +#if LWIP_ARP + etharp_init(); +#endif /* LWIP_ARP */ +#endif /* LWIP_IPV4 */ +#if LWIP_RAW + raw_init(); +#endif /* LWIP_RAW */ +#if LWIP_UDP + udp_init(); +#endif /* LWIP_UDP */ +#if LWIP_TCP + tcp_init(); +#endif /* LWIP_TCP */ +#if LWIP_IGMP + igmp_init(); +#endif /* LWIP_IGMP */ +#if LWIP_DNS + dns_init(); +#endif /* LWIP_DNS */ +#if PPP_SUPPORT + ppp_init(); +#endif + +#if LWIP_TIMERS + sys_timeouts_init(); +#endif /* LWIP_TIMERS */ +} diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ip.c b/Sming/third-party/lwip2/lwip2-src/src/core/ip.c new file mode 100644 index 0000000000..2e0240851f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ip.c @@ -0,0 +1,124 @@ +/** + * @file + * Common IPv4 and IPv6 code + * + * @defgroup ip IP + * @ingroup callbackstyle_api + * + * @defgroup ip4 IPv4 + * @ingroup ip + * + * @defgroup ip6 IPv6 + * @ingroup ip + * + * @defgroup ipaddr IP address handling + * @ingroup infrastructure + * + * @defgroup ip4addr IPv4 only + * @ingroup ipaddr + * + * @defgroup ip6addr IPv6 only + * @ingroup ipaddr + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 || LWIP_IPV6 + +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +/** Global data for both IPv4 and IPv6 */ +struct ip_globals ip_data; + +#if LWIP_IPV4 && LWIP_IPV6 + +const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT; + +/** + * @ingroup ipaddr + * Convert IP address string (both versions) to numeric. + * The version is auto-detected from the string. + * + * @param cp IP address string to convert + * @param addr conversion result is stored here + * @return 1 on success, 0 on error + */ +int +ipaddr_aton(const char *cp, ip_addr_t *addr) +{ + if (cp != NULL) { + const char* c; + for (c = cp; *c != 0; c++) { + if (*c == ':') { + /* contains a colon: IPv6 address */ + if (addr) { + IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); + } + return ip6addr_aton(cp, ip_2_ip6(addr)); + } else if (*c == '.') { + /* contains a dot: IPv4 address */ + break; + } + } + /* call ip4addr_aton as fallback or if IPv4 was found */ + if (addr) { + IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); + } + return ip4addr_aton(cp, ip_2_ip4(addr)); + } + return 0; +} + +/** + * @ingroup lwip_nosys + * If both IP versions are enabled, this function can dispatch packets to the correct one. + * Don't call directly, pass to netif_add() and call netif->input(). + */ +err_t +ip_input(struct pbuf *p, struct netif *inp) +{ + if (p != NULL) { + if (IP_HDR_GET_VERSION(p->payload) == 6) { + return ip6_input(p, inp); + } + return ip4_input(p, inp); + } + return ERR_VAL; +} + +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#endif /* LWIP_IPV4 || LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/autoip.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/autoip.c new file mode 100644 index 0000000000..10db8a3444 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/autoip.c @@ -0,0 +1,527 @@ +/** + * @file + * AutoIP Automatic LinkLocal IP Configuration + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * @defgroup autoip AUTOIP + * @ingroup ip4 + * AUTOIP related functions + * USAGE: + * + * define @ref LWIP_AUTOIP 1 in your lwipopts.h + * Options: + * AUTOIP_TMR_INTERVAL msecs, + * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. + * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + * + * Without DHCP: + * - Call autoip_start() after netif_add(). + * + * With DHCP: + * - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. + * - Configure your DHCP Client. + * + * @see netifapi_autoip + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +/* #include "lwip/udp.h" */ +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/autoip.h" +#include "lwip/etharp.h" +#include "lwip/prot/autoip.h" + +#include + +/** Pseudo random macro based on netif informations. + * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ +#ifndef LWIP_AUTOIP_RAND +#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ + ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ + ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ + ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ + (netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0)) +#endif /* LWIP_AUTOIP_RAND */ + +/** + * Macro that generates the initial IP address to be tried by AUTOIP. + * If you want to override this, define it to something else in lwipopts.h. + */ +#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR +#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ + lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ + ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) +#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ + +/* static functions */ +static err_t autoip_arp_announce(struct netif *netif); +static void autoip_start_probing(struct netif *netif); + +/** + * @ingroup autoip + * Set a statically allocated struct autoip to work with. + * Using this prevents autoip_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct autoip + * @param autoip (uninitialised) autoip struct allocated by the application + */ +void +autoip_set_struct(struct netif *netif, struct autoip *autoip) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("autoip != NULL", autoip != NULL); + LWIP_ASSERT("netif already has a struct autoip set", + netif_autoip_data(netif) == NULL); + + /* clear data structure */ + memset(autoip, 0, sizeof(struct autoip)); + /* autoip->state = AUTOIP_STATE_OFF; */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); +} + +/** Restart AutoIP client and check the next address (conflict detected) + * + * @param netif The netif under AutoIP control + */ +static void +autoip_restart(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + autoip->tried_llipaddr++; + autoip_start(netif); +} + +/** + * Handle a IP address conflict after an ARP conflict detection + */ +static void +autoip_handle_arp_conflict(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + + /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where + a) means retreat on the first conflict and + b) allows to keep an already configured address when having only one + conflict in 10 seconds + We use option b) since it helps to improve the chance that one of the two + conflicting hosts may be able to retain its address. */ + + if (autoip->lastconflict > 0) { + /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + + /* Active TCP sessions are aborted when removing the ip addresss */ + autoip_restart(netif); + } else { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); + autoip_arp_announce(netif); + autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } +} + +/** + * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * + * @param netif network interface on which create the IP-Address + * @param ipaddr ip address to initialize + */ +static void +autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr) +{ + struct autoip* autoip = netif_autoip_data(netif); + + /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * compliant to RFC 3927 Section 2.1 + * We have 254 * 256 possibilities */ + + u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); + addr += autoip->tried_llipaddr; + addr = AUTOIP_NET | (addr & 0xffff); + /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ + + if (addr < AUTOIP_RANGE_START) { + addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + if (addr > AUTOIP_RANGE_END) { + addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; + } + LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && + (addr <= AUTOIP_RANGE_END)); + ip4_addr_set_u32(ipaddr, lwip_htonl(addr)); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), + ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); +} + +/** + * Sends an ARP probe from a network interface + * + * @param netif network interface used to send the probe + */ +static err_t +autoip_arp_probe(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + /* this works because netif->ip_addr is ANY */ + return etharp_request(netif, &autoip->llipaddr); +} + +/** + * Sends an ARP announce from a network interface + * + * @param netif network interface used to send the announce + */ +static err_t +autoip_arp_announce(struct netif *netif) +{ + return etharp_gratuitous(netif); +} + +/** + * Configure interface for use with current LL IP-Address + * + * @param netif network interface to configure with current LL IP-Address + */ +static err_t +autoip_bind(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + ip4_addr_t sn_mask, gw_addr; + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + + IP4_ADDR(&sn_mask, 255, 255, 0, 0); + IP4_ADDR(&gw_addr, 0, 0, 0, 0); + + netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr); + /* interface is used by routing now that an address is set */ + + return ERR_OK; +} + +/** + * @ingroup autoip + * Start AutoIP client + * + * @param netif network interface on which start the AutoIP client + */ +err_t +autoip_start(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + err_t result = ERR_OK; + + LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); + + /* Set IP-Address, Netmask and Gateway to 0 to make sure that + * ARP Packets are formed correctly + */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], + netif->name[1], (u16_t)netif->num)); + if (autoip == NULL) { + /* no AutoIP client attached yet? */ + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): starting new AUTOIP client\n")); + autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); + if (autoip == NULL) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_start(): could not allocate autoip\n")); + return ERR_MEM; + } + memset(autoip, 0, sizeof(struct autoip)); + /* store this AutoIP client in the netif */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); + } else { + autoip->state = AUTOIP_STATE_OFF; + autoip->ttw = 0; + autoip->sent_num = 0; + ip4_addr_set_zero(&autoip->llipaddr); + autoip->lastconflict = 0; + } + + autoip_create_addr(netif, &(autoip->llipaddr)); + autoip_start_probing(netif); + + return result; +} + +static void +autoip_start_probing(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + + autoip->state = AUTOIP_STATE_PROBING; + autoip->sent_num = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + + /* time to wait to first probe, this is randomly + * chosen out of 0 to PROBE_WAIT seconds. + * compliant to RFC 3927 Section 2.2.1 + */ + autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); + + /* + * if we tried more then MAX_CONFLICTS we must limit our rate for + * acquiring and probing address + * compliant to RFC 3927 Section 2.2.1 + */ + if (autoip->tried_llipaddr > MAX_CONFLICTS) { + autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; + } +} + +/** + * Handle a possible change in the network configuration. + * + * If there is an AutoIP address configured, take the interface down + * and begin probing with the same address. + */ +void +autoip_network_changed(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + + if (autoip && (autoip->state != AUTOIP_STATE_OFF)) { + autoip_start_probing(netif); + } +} + +/** + * @ingroup autoip + * Stop AutoIP client + * + * @param netif network interface on which stop the AutoIP client + */ +err_t +autoip_stop(struct netif *netif) +{ + struct autoip* autoip = netif_autoip_data(netif); + + if (autoip != NULL) { + autoip->state = AUTOIP_STATE_OFF; + if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + } + } + return ERR_OK; +} + +/** + * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds + */ +void +autoip_tmr(void) +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + struct autoip* autoip = netif_autoip_data(netif); + /* only act on AutoIP configured interfaces */ + if (autoip != NULL) { + if (autoip->lastconflict > 0) { + autoip->lastconflict--; + } + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, + ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", + (u16_t)(autoip->state), autoip->ttw)); + + if (autoip->ttw > 0) { + autoip->ttw--; + } + + switch(autoip->state) { + case AUTOIP_STATE_PROBING: + if (autoip->ttw == 0) { + if (autoip->sent_num >= PROBE_NUM) { + /* Switch to ANNOUNCING: now we can bind to an IP address and use it */ + autoip->state = AUTOIP_STATE_ANNOUNCING; + autoip_bind(netif); + /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP + which counts as an announcement */ + autoip->sent_num = 1; + autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + } else { + autoip_arp_probe(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); + autoip->sent_num++; + if (autoip->sent_num == PROBE_NUM) { + /* calculate time to wait to for announce */ + autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + } else { + /* calculate time to wait to next probe */ + autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % + ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + + PROBE_MIN * AUTOIP_TICKS_PER_SECOND); + } + } + } + break; + + case AUTOIP_STATE_ANNOUNCING: + if (autoip->ttw == 0) { + autoip_arp_announce(netif); + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); + autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; + autoip->sent_num++; + + if (autoip->sent_num >= ANNOUNCE_NUM) { + autoip->state = AUTOIP_STATE_BOUND; + autoip->sent_num = 0; + autoip->ttw = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); + } + } + break; + + default: + /* nothing to do in other states */ + break; + } + } + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * Handles every incoming ARP Packet, called by etharp_input(). + * + * @param netif network interface to use for autoip processing + * @param hdr Incoming ARP packet + */ +void +autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + struct autoip* autoip = netif_autoip_data(netif); + + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); + if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) { + /* when ip.src == llipaddr && hw.src != netif->hwaddr + * + * when probing ip.dst == llipaddr && hw.src != netif->hwaddr + * we have a conflict and must solve it + */ + ip4_addr_t sipaddr, dipaddr; + struct eth_addr netifaddr; + ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); + + /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). + */ + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); + + if (autoip->state == AUTOIP_STATE_PROBING) { + /* RFC 3927 Section 2.2.1: + * from beginning to after ANNOUNCE_WAIT + * seconds we have a conflict if + * ip.src == llipaddr OR + * ip.dst == llipaddr && hw.src != own hwaddr + */ + if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) || + (ip4_addr_isany_val(sipaddr) && + ip4_addr_cmp(&dipaddr, &autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Probe Conflict detected\n")); + autoip_restart(netif); + } + } else { + /* RFC 3927 Section 2.5: + * in any state we have a conflict if + * ip.src == llipaddr && hw.src != own hwaddr + */ + if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) && + !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); + autoip_handle_arp_conflict(netif); + } + } + } +} + +/** check if AutoIP supplied netif->ip_addr + * + * @param netif the netif to check + * @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING), + * 0 otherwise + */ +u8_t +autoip_supplied_address(const struct netif *netif) +{ + if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) { + struct autoip* autoip = netif_autoip_data(netif); + return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING); + } + return 0; +} + +u8_t +autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr) +{ + struct autoip* autoip = netif_autoip_data(netif); + return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr)); +} + +#endif /* LWIP_IPV4 && LWIP_AUTOIP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/dhcp.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/dhcp.c new file mode 100644 index 0000000000..dd35471026 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/dhcp.c @@ -0,0 +1,1950 @@ +/** + * @file + * Dynamic Host Configuration Protocol client + * + * @defgroup dhcp4 DHCPv4 + * @ingroup ip4 + * DHCP (IPv4) related functions + * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform + * with RFC 2131 and RFC 2132. + * + * @todo: + * - Support for interfaces other than Ethernet (SLIP, PPP, ...) + * + * Options: + * @ref DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) + * @ref DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) + * + * dhcp_start() starts a DHCP client instance which + * configures the interface by obtaining an IP address lease and maintaining it. + * + * Use dhcp_release() to end the lease and use dhcp_stop() + * to remove the DHCP client. + * + * @see netifapi_dhcp4 + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. + * + * Author: Leon Woestenberg + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/dns.h" +#include "lwip/etharp.h" +#include "lwip/prot/dhcp.h" + +#include + +/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using + * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) + */ +#ifndef DHCP_CREATE_RAND_XID +#define DHCP_CREATE_RAND_XID 1 +#endif + +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + * \#define DHCP_GLOBAL_XID_HEADER "stdlib.h" + * \#define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * MTU is checked to be big enough in dhcp_start */ +#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) +#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 +/** Minimum length for reply before packet is parsed */ +#define DHCP_MIN_REPLY_LEN 44 + +#define REBOOT_TRIES 2 + +#if LWIP_DNS && LWIP_DHCP_MAX_DNS_SERVERS +#if DNS_MAX_SERVERS > LWIP_DHCP_MAX_DNS_SERVERS +#define LWIP_DHCP_PROVIDE_DNS_SERVERS LWIP_DHCP_MAX_DNS_SERVERS +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS +#endif +#else +#define LWIP_DHCP_PROVIDE_DNS_SERVERS 0 +#endif + +/** Option handling: options are parsed in dhcp_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +enum dhcp_option_idx { + DHCP_OPTION_IDX_OVERLOAD = 0, + DHCP_OPTION_IDX_MSG_TYPE, + DHCP_OPTION_IDX_SERVER_ID, + DHCP_OPTION_IDX_LEASE_TIME, + DHCP_OPTION_IDX_T1, + DHCP_OPTION_IDX_T2, + DHCP_OPTION_IDX_SUBNET_MASK, + DHCP_OPTION_IDX_ROUTER, +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + DHCP_OPTION_IDX_DNS_SERVER, + DHCP_OPTION_IDX_DNS_SERVER_LAST = DHCP_OPTION_IDX_DNS_SERVER + LWIP_DHCP_PROVIDE_DNS_SERVERS - 1, +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP_GET_NTP_SRV + DHCP_OPTION_IDX_NTP_SERVER, + DHCP_OPTION_IDX_NTP_SERVER_LAST = DHCP_OPTION_IDX_NTP_SERVER + LWIP_DHCP_MAX_NTP_SERVERS - 1, +#endif /* LWIP_DHCP_GET_NTP_SRV */ + DHCP_OPTION_IDX_MAX +}; + +/** Holds the decoded option values, only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; +/** Holds a flag which option was received and is contained in dhcp_rx_options_val, + only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; + +static u8_t dhcp_discover_request_options[] = { + DHCP_OPTION_SUBNET_MASK, + DHCP_OPTION_ROUTER, + DHCP_OPTION_BROADCAST +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + , DHCP_OPTION_DNS_SERVER +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +#if LWIP_DHCP_GET_NTP_SRV + , DHCP_OPTION_NTP +#endif /* LWIP_DHCP_GET_NTP_SRV */ + }; + +#ifdef DHCP_GLOBAL_XID +static u32_t xid; +static u8_t xid_initialised; +#endif /* DHCP_GLOBAL_XID */ + +#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) + +static struct udp_pcb *dhcp_pcb; +static u8_t dhcp_pcb_refcount; + +/* DHCP client state machine functions */ +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_bind(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +static err_t dhcp_decline(struct netif *netif); +#endif /* DHCP_DOES_ARP_CHECK */ +static err_t dhcp_rebind(struct netif *netif); +static err_t dhcp_reboot(struct netif *netif); +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); + +/* receive, unfold, parse and free incoming messages */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + +/* set the DHCP timers */ +static void dhcp_timeout(struct netif *netif); +static void dhcp_t1_timeout(struct netif *netif); +static void dhcp_t2_timeout(struct netif *netif); + +/* build outgoing messages */ +/* create a DHCP message, fill in common headers */ +static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); +/* free a DHCP request */ +static void dhcp_delete_msg(struct dhcp *dhcp); +/* add a DHCP option (type, then length in bytes) */ +static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); +/* add option values */ +static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); +static void dhcp_option_short(struct dhcp *dhcp, u16_t value); +static void dhcp_option_long(struct dhcp *dhcp, u32_t value); +#if LWIP_NETIF_HOSTNAME +static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif); +#endif /* LWIP_NETIF_HOSTNAME */ +/* always add the DHCP options trailer to end and pad */ +static void dhcp_option_trailer(struct dhcp *dhcp); + +/** Ensure DHCP PCB is allocated and bound */ +static err_t +dhcp_inc_pcb_refcount(void) +{ + if (dhcp_pcb_refcount == 0) { + LWIP_ASSERT("dhcp_inc_pcb_refcount(): memory leak", dhcp_pcb == NULL); + + /* allocate UDP PCB */ + dhcp_pcb = udp_new(); + + if (dhcp_pcb == NULL) { + return ERR_MEM; + } + + ip_set_option(dhcp_pcb, SOF_BROADCAST); + + /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */ + udp_bind(dhcp_pcb, IP4_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp_pcb, IP4_ADDR_ANY, DHCP_SERVER_PORT); + udp_recv(dhcp_pcb, dhcp_recv, NULL); + } + + dhcp_pcb_refcount++; + + return ERR_OK; +} + +/** Free DHCP PCB if the last netif stops using it */ +static void +dhcp_dec_pcb_refcount(void) +{ + LWIP_ASSERT("dhcp_pcb_refcount(): refcount error", (dhcp_pcb_refcount > 0)); + dhcp_pcb_refcount--; + + if (dhcp_pcb_refcount == 0) { + udp_remove(dhcp_pcb); + dhcp_pcb = NULL; + } +} + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We clear any existing set IP address and restart DHCP negotiation + * afresh (as per RFC2131 3.2.3). + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_nak(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* Change to a defined state - set this before assigning the address + to ensure the callback can use dhcp_supplied_address() */ + dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + /* remove IP address from interface (must no longer be used, as per RFC2131) */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + /* We can immediately restart discovery */ + dhcp_discover(netif); +} + +#if DHCP_DOES_ARP_CHECK +/** + * Checks if the offered IP address is already in use. + * + * It does so by sending an ARP request for the offered address and + * entering CHECKING state. If no ARP reply is received within a small + * interval, the address is assumed to be free for use by us. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_check(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], + (s16_t)netif->name[1])); + dhcp_set_state(dhcp, DHCP_STATE_CHECKING); + /* create an ARP query for the offered IP address, expecting that no host + responds, as the IP address should not be in use. */ + result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); + if (result != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = 500; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); +} +#endif /* DHCP_DOES_ARP_CHECK */ + +/** + * Remember the configuration offered by a DHCP server. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_offer(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + /* obtain the server address */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { + ip_addr_set_ip4_u32(&dhcp->server_ip_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", + ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); + /* remember offered address */ + ip4_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); + } +} + +/** + * Select a DHCP server offer out of all offers. + * + * Simply select the first offer received. + * + * @param netif the netif under DHCP control + * @return lwIP specific error (see error.h) + */ +static err_t +dhcp_select(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + dhcp_set_state(dhcp, DHCP_STATE_REQUESTING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + + /* MUST request the offered IP address */ + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&dhcp->server_ip_addr)))); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + dhcp_option_trailer(dhcp); + /* shrink the pbuf to the actual content length */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* send broadcast to any DHCP server */ + udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * The DHCP timer that checks for lease renewal/rebind timeouts. + * Must be called once a minute (see @ref DHCP_COARSE_TIMER_SECS). + */ +void +dhcp_coarse_tmr(void) +{ + struct netif *netif = netif_list; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); + /* iterate through all network interfaces */ + while (netif != NULL) { + /* only act on DHCP configured interfaces */ + struct dhcp *dhcp = netif_dhcp_data(netif); + if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) { + /* compare lease time to expire timeout */ + if (dhcp->t0_timeout && (++dhcp->lease_used == dhcp->t0_timeout)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t0 timeout\n")); + /* this clients' lease time has expired */ + dhcp_release(netif); + dhcp_discover(netif); + /* timer is active (non zero), and triggers (zeroes) now? */ + } else if (dhcp->t2_rebind_time && (dhcp->t2_rebind_time-- == 1)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); + /* this clients' rebind timeout triggered */ + dhcp_t2_timeout(netif); + /* timer is active (non zero), and triggers (zeroes) now */ + } else if (dhcp->t1_renew_time && (dhcp->t1_renew_time-- == 1)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); + /* this clients' renewal timeout triggered */ + dhcp_t1_timeout(netif); + } + } + /* proceed to next netif */ + netif = netif->next; + } +} + +/** + * DHCP transaction timeout handling (this function must be called every 500ms, + * see @ref DHCP_FINE_TIMER_MSECS). + * + * A DHCP server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCP request is timed out. + */ +void +dhcp_fine_tmr(void) +{ + struct netif *netif = netif_list; + /* loop through netif's */ + while (netif != NULL) { + struct dhcp *dhcp = netif_dhcp_data(netif); + /* only act on DHCP configured interfaces */ + if (dhcp != NULL) { + /* timer is active (non zero), and is about to trigger now */ + if (dhcp->request_timeout > 1) { + dhcp->request_timeout--; + } + else if (dhcp->request_timeout == 1) { + dhcp->request_timeout--; + /* { netif->dhcp->request_timeout == 0 } */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); + /* this client's request timeout triggered */ + dhcp_timeout(netif); + } + } + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * A DHCP negotiation transaction, or ARP request, has timed out. + * + * The timer that was started with the DHCP or ARP request has + * timed out, indicating no response was received in time. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); + /* back-off period has passed, or server selection timed out */ + if ((dhcp->state == DHCP_STATE_BACKING_OFF) || (dhcp->state == DHCP_STATE_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); + dhcp_discover(netif); + /* receiving the requested lease timed out */ + } else if (dhcp->state == DHCP_STATE_REQUESTING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); + if (dhcp->tries <= 5) { + dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); + dhcp_release(netif); + dhcp_discover(netif); + } +#if DHCP_DOES_ARP_CHECK + /* received no ARP reply for the offered address (which is good) */ + } else if (dhcp->state == DHCP_STATE_CHECKING) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); + if (dhcp->tries <= 1) { + dhcp_check(netif); + /* no ARP replies on the offered address, + looks like the IP address is indeed free */ + } else { + /* bind the interface to the offered address */ + dhcp_bind(netif); + } +#endif /* DHCP_DOES_ARP_CHECK */ + } else if (dhcp->state == DHCP_STATE_REBOOTING) { + if (dhcp->tries < REBOOT_TRIES) { + dhcp_reboot(netif); + } else { + dhcp_discover(netif); + } + } +} + +/** + * The renewal period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t1_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); + if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || + (dhcp->state == DHCP_STATE_RENEWING)) { + /* just retry to renew - note that the rebind timer (t2) will + * eventually time-out if renew tries fail. */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t1_timeout(): must renew\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_STATE_RENEWING, not DHCP_STATE_BOUND */ + dhcp_renew(netif); + /* Calculate next timeout */ + if (((dhcp->t2_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) + { + dhcp->t1_renew_time = ((dhcp->t2_timeout - dhcp->lease_used) / 2); + } + } +} + +/** + * The rebind period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t2_timeout(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); + if ((dhcp->state == DHCP_STATE_REQUESTING) || (dhcp->state == DHCP_STATE_BOUND) || + (dhcp->state == DHCP_STATE_RENEWING) || (dhcp->state == DHCP_STATE_REBINDING)) { + /* just retry to rebind */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t2_timeout(): must rebind\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_STATE_REBINDING, not DHCP_STATE_BOUND */ + dhcp_rebind(netif); + /* Calculate next timeout */ + if (((dhcp->t0_timeout - dhcp->lease_used) / 2) >= ((60 + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS)) + { + dhcp->t2_rebind_time = ((dhcp->t0_timeout - dhcp->lease_used) / 2); + } + } +} + +/** + * Handle a DHCP ACK packet + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_ack(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + +#if LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV + u8_t n; +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS || LWIP_DHCP_GET_NTP_SRV */ +#if LWIP_DHCP_GET_NTP_SRV + ip4_addr_t ntp_server_addrs[LWIP_DHCP_MAX_NTP_SERVERS]; +#endif + + /* clear options we might not get from the ACK */ + ip4_addr_set_zero(&dhcp->offered_sn_mask); + ip4_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* lease time given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { + /* remember offered lease time */ + dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); + } + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { + /* remember given renewal period */ + dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); + } else { + /* calculate safe periods for renewal */ + dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; + } + + /* renewal period given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { + /* remember given rebind period */ + dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); + } else { + /* calculate safe periods for rebinding (offered_t0_lease * 0.875 -> 87.5%)*/ + dhcp->offered_t2_rebind = (dhcp->offered_t0_lease * 7U) / 8U; + } + + /* (y)our internet address */ + ip4_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); + +#if LWIP_DHCP_BOOTP_FILE + /* copy boot server address, + boot file name copied in dhcp_parse_reply if not overloaded */ + ip4_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* subnet mask given? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { + /* remember given subnet mask */ + ip4_addr_set_u32(&dhcp->offered_sn_mask, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); + dhcp->subnet_mask_given = 1; + } else { + dhcp->subnet_mask_given = 0; + } + + /* gateway router */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { + ip4_addr_set_u32(&dhcp->offered_gw_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); + } + +#if LWIP_DHCP_GET_NTP_SRV + /* NTP servers */ + for (n = 0; (n < LWIP_DHCP_MAX_NTP_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n); n++) { + ip4_addr_set_u32(&ntp_server_addrs[n], lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_NTP_SERVER + n))); + } + dhcp_set_ntp_servers(n, ntp_server_addrs); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + /* DNS servers */ + for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { + ip_addr_t dns_addr; + ip_addr_set_ip4_u32(&dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); + dns_setserver(n, &dns_addr); + } +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ +} + +/** + * @ingroup dhcp4 + * Set a statically allocated struct dhcp to work with. + * Using this prevents dhcp_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct dhcp + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void +dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp != NULL", dhcp != NULL); + LWIP_ASSERT("netif already has a struct dhcp set", netif_dhcp_data(netif) == NULL); + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); +} + +/** + * @ingroup dhcp4 + * Removes a struct dhcp from a netif. + * + * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the + * struct dhcp since the memory is passed back to the heap. + * + * @param netif the netif from which to remove the struct dhcp + */ +void dhcp_cleanup(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + + if (netif_dhcp_data(netif) != NULL) { + mem_free(netif_dhcp_data(netif)); + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, NULL); + } +} + +/** + * @ingroup dhcp4 + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + */ +err_t +dhcp_start(struct netif *netif) +{ + struct dhcp *dhcp; + err_t result; + + LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); + LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;); + dhcp = netif_dhcp_data(netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* check MTU of the netif */ + if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); + return ERR_MEM; + } + + /* no DHCP client attached yet? */ + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); + dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); + if (dhcp == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); + return ERR_MEM; + } + + /* store this dhcp client in the netif */ + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); + /* already has DHCP client attached */ + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); + LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); + + if (dhcp->pcb_allocated != 0) { + dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ + } + /* dhcp is cleared below, no need to reset flag*/ + } + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_STATE_OFF); */ + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); + + if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ + return ERR_MEM; + } + dhcp->pcb_allocated = 1; + +#if LWIP_DHCP_CHECK_LINK_UP + if (!netif_is_link_up(netif)) { + /* set state INIT and wait for dhcp_network_changed() to call dhcp_discover() */ + dhcp_set_state(dhcp, DHCP_STATE_INIT); + return ERR_OK; + } +#endif /* LWIP_DHCP_CHECK_LINK_UP */ + + + /* (re)start the DHCP negotiation */ + result = dhcp_discover(netif); + if (result != ERR_OK) { + /* free resources allocated above */ + dhcp_stop(netif); + return ERR_MEM; + } + return result; +} + +/** + * @ingroup dhcp4 + * Inform a DHCP server of our manual configuration. + * + * This informs DHCP servers of our fixed IP address configuration + * by sending an INFORM message. It does not involve DHCP address + * configuration, it is just here to be nice to the network. + * + * @param netif The lwIP network interface + */ +void +dhcp_inform(struct netif *netif) +{ + struct dhcp dhcp; + err_t result = ERR_OK; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + if (dhcp_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP PCB is allocated */ + return; + } + + memset(&dhcp, 0, sizeof(struct dhcp)); + dhcp_set_state(&dhcp, DHCP_STATE_INFORMING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); + if (result == ERR_OK) { + dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); + + dhcp_option_trailer(&dhcp); + + pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); + + udp_sendto_if(dhcp_pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + + dhcp_delete_msg(&dhcp); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); + } + + dhcp_dec_pcb_refcount(); /* delete DHCP PCB if not needed any more */ +} + +/** Handle a possible change in the network configuration. + * + * This enters the REBOOTING state to verify that the currently bound + * address is still valid. + */ +void +dhcp_network_changed(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + + if (!dhcp) + return; + switch (dhcp->state) { + case DHCP_STATE_REBINDING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_BOUND: + case DHCP_STATE_REBOOTING: + dhcp->tries = 0; + dhcp_reboot(netif); + break; + case DHCP_STATE_OFF: + /* stay off */ + break; + default: + /* INIT/REQUESTING/CHECKING/BACKING_OFF restart with new 'rid' because the + state changes, SELECTING: continue with current 'rid' as we stay in the + same state */ +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + /* ensure we start with short timeouts, even if already discovering */ + dhcp->tries = 0; + dhcp_discover(netif); + break; + } +} + +#if DHCP_DOES_ARP_CHECK +/** + * Match an ARP reply with the offered IP address: + * check whether the offered IP address is not in use using ARP + * + * @param netif the network interface on which the reply was received + * @param addr The IP address we received a reply from + */ +void +dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr) +{ + struct dhcp *dhcp; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + dhcp = netif_dhcp_data(netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); + /* is a DHCP client doing an ARP check? */ + if ((dhcp != NULL) && (dhcp->state == DHCP_STATE_CHECKING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", + ip4_addr_get_u32(addr))); + /* did a host respond with the address we + were offered by the DHCP server? */ + if (ip4_addr_cmp(addr, &dhcp->offered_ip_addr)) { + /* we will not accept the offered address */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); + dhcp_decline(netif); + } + } +} + +/** + * Decline an offered lease. + * + * Tell the DHCP server we do not accept the offered address. + * One reason to decline the lease is when we find out the address + * is already in use by another host (through ARP). + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_decline(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result = ERR_OK; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); + dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF); + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option_trailer(dhcp); + /* resize pbuf to reflect true size of options */ + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* per section 4.4.4, broadcast DECLINE messages */ + udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_decline: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = 10*1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} +#endif /* DHCP_DOES_ARP_CHECK */ + + +/** + * Start the DHCP process, discover a DHCP server. + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_discover(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result = ERR_OK; + u16_t msecs; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); + ip4_addr_set_any(&dhcp->offered_ip_addr); + dhcp_set_state(dhcp, DHCP_STATE_SELECTING); + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); + if (result == ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); + } + dhcp_option_trailer(dhcp); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); + udp_sendto_if_src(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP4_ADDR_ANY); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; + autoip_start(netif); + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * Bind the interface to the offered IP address. + * + * @param netif network interface to bind to the offered address + */ +static void +dhcp_bind(struct netif *netif) +{ + u32_t timeout; + struct dhcp *dhcp; + ip4_addr_t sn_mask, gw_addr; + LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); + dhcp = netif_dhcp_data(netif); + LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + + /* reset time used of lease */ + dhcp->lease_used = 0; + + if (dhcp->offered_t0_lease != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t0 renewal timer %"U32_F" secs\n", dhcp->offered_t0_lease)); + timeout = (dhcp->offered_t0_lease + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t0_timeout = (u16_t)timeout; + if (dhcp->t0_timeout == 0) { + dhcp->t0_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t0_lease*1000)); + } + + /* temporary DHCP lease? */ + if (dhcp->offered_t1_renew != 0xffffffffUL) { + /* set renewal period timer */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); + timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t1_timeout = (u16_t)timeout; + if (dhcp->t1_timeout == 0) { + dhcp->t1_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); + dhcp->t1_renew_time = dhcp->t1_timeout; + } + /* set renewal period timer */ + if (dhcp->offered_t2_rebind != 0xffffffffUL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); + timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; + if (timeout > 0xffff) { + timeout = 0xffff; + } + dhcp->t2_timeout = (u16_t)timeout; + if (dhcp->t2_timeout == 0) { + dhcp->t2_timeout = 1; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); + dhcp->t2_rebind_time = dhcp->t2_timeout; + } + + /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ + if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { + dhcp->t1_timeout = 0; + } + + if (dhcp->subnet_mask_given) { + /* copy offered network mask */ + ip4_addr_copy(sn_mask, dhcp->offered_sn_mask); + } else { + /* subnet mask not given, choose a safe subnet mask given the network class */ + u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); + if (first_octet <= 127) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); + } else if (first_octet >= 192) { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); + } else { + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); + } + } + + ip4_addr_copy(gw_addr, dhcp->offered_gw_addr); + /* gateway address not given? */ + if (ip4_addr_isany_val(gw_addr)) { + /* copy network address */ + ip4_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); + /* use first host address on network as gateway */ + ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL)); + } + +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F" SN: 0x%08"X32_F" GW: 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr), ip4_addr_get_u32(&sn_mask), ip4_addr_get_u32(&gw_addr))); + /* netif is now bound to DHCP leased address - set this before assigning the address + to ensure the callback can use dhcp_supplied_address() */ + dhcp_set_state(dhcp, DHCP_STATE_BOUND); + + netif_set_addr(netif, &dhcp->offered_ip_addr, &sn_mask, &gw_addr); + /* interface is used by routing now that an address is set */ +} + +/** + * @ingroup dhcp4 + * Renew an existing DHCP lease at the involved DHCP server. + * + * @param netif network interface which must renew its lease + */ +err_t +dhcp_renew(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); + dhcp_set_state(dhcp, DHCP_STATE_RENEWING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + /* append DHCP message trailer */ + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_sendto_if(dhcp_pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + /* back-off on retries, but to a maximum of 20 seconds */ + msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Rebind with a DHCP server for an existing DHCP lease. + * + * @param netif network interface which must rebind with a DHCP server + */ +static err_t +dhcp_rebind(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); + dhcp_set_state(dhcp, DHCP_STATE_REBINDING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); + } + +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* broadcast to server */ + udp_sendto_if(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + +/** + * Enter REBOOTING state to verify an existing lease + * + * @param netif network interface which must reboot + */ +static err_t +dhcp_reboot(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + u16_t msecs; + u8_t i; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); + dhcp_set_state(dhcp, DHCP_STATE_REBOOTING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN_MIN_REQUIRED); + + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); + + dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, LWIP_ARRAYSIZE(dhcp_discover_request_options)); + for (i = 0; i < LWIP_ARRAYSIZE(dhcp_discover_request_options); i++) { + dhcp_option_byte(dhcp, dhcp_discover_request_options[i]); + } + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* broadcast to server */ + udp_sendto_if(dhcp_pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + +/** + * @ingroup dhcp4 + * Release a DHCP lease (usually called before @ref dhcp_stop). + * + * @param netif network interface which must release its lease + */ +err_t +dhcp_release(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + err_t result; + ip_addr_t server_ip_addr; + u8_t is_dhcp_supplied_address; + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); + if (dhcp == NULL) { + return ERR_ARG; + } + ip_addr_copy(server_ip_addr, dhcp->server_ip_addr); + + is_dhcp_supplied_address = dhcp_supplied_address(netif); + + /* idle DHCP client */ + dhcp_set_state(dhcp, DHCP_STATE_OFF); + /* clean old DHCP offer */ + ip_addr_set_zero_ip4(&dhcp->server_ip_addr); + ip4_addr_set_zero(&dhcp->offered_ip_addr); + ip4_addr_set_zero(&dhcp->offered_sn_mask); + ip4_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ + dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; + dhcp->t1_renew_time = dhcp->t2_rebind_time = dhcp->lease_used = dhcp->t0_timeout = 0; + + if (!is_dhcp_supplied_address) { + /* don't issue release message when address is not dhcp-assigned */ + return ERR_OK; + } + + /* create and initialize the DHCP message header */ + result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); + if (result == ERR_OK) { + dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); + dhcp_option_long(dhcp, lwip_ntohl(ip4_addr_get_u32(ip_2_ip4(&server_ip_addr)))); + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + udp_sendto_if(dhcp_pcb, dhcp->p_out, &server_ip_addr, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(dhcp); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_STATE_OFF\n")); + } else { + /* sending release failed, but that's not a problem since the correct behaviour of dhcp does not rely on release */ + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); + } + /* remove IP address from interface (prevents routing from selecting this interface) */ + netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4); + + return result; +} + +/** + * @ingroup dhcp4 + * Remove the DHCP client from the interface. + * + * @param netif The network interface to stop DHCP on + */ +void +dhcp_stop(struct netif *netif) +{ + struct dhcp *dhcp; + LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); + dhcp = netif_dhcp_data(netif); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); + /* netif is DHCP configured? */ + if (dhcp != NULL) { +#if LWIP_DHCP_AUTOIP_COOP + if (dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); + dhcp_set_state(dhcp, DHCP_STATE_OFF); + + if (dhcp->pcb_allocated != 0) { + dhcp_dec_pcb_refcount(); /* free DHCP PCB if not needed any more */ + dhcp->pcb_allocated = 0; + } + } +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + */ +static void +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ + if (new_state != dhcp->state) { + dhcp->state = new_state; + dhcp->tries = 0; + dhcp->request_timeout = 0; + } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static void +dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) +{ + LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = option_type; + dhcp->msg_out->options[dhcp->options_out_len++] = option_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static void +dhcp_option_byte(struct dhcp *dhcp, u8_t value) +{ + LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = value; +} + +static void +dhcp_option_short(struct dhcp *dhcp, u16_t value) +{ + LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); +} + +static void +dhcp_option_long(struct dhcp *dhcp, u32_t value) +{ + LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); + dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); +} + +#if LWIP_NETIF_HOSTNAME +static void +dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) +{ + if (netif->hostname != NULL) { + size_t namelen = strlen(netif->hostname); + if (namelen > 0) { + size_t len; + const char *p = netif->hostname; + /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME + and 1 byte for trailer) */ + size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); + len = LWIP_MIN(namelen, available); + LWIP_ASSERT("DHCP: hostname is too long!", len <= 0xFF); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, (u8_t)len); + while (len--) { + dhcp_option_byte(dhcp, *p++); + } + } + } +} +#endif /* LWIP_NETIF_HOSTNAME */ + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a contiguous piece of memory, and + * use that further on. + * + */ +static err_t +dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) +{ + u8_t *options; + u16_t offset; + u16_t offset_max; + u16_t options_idx; + u16_t options_idx_max; + struct pbuf *q; + int parse_file_as_options = 0; + int parse_sname_as_options = 0; + + /* clear received options */ + dhcp_clear_all_options(dhcp); + /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ + if (p->len < DHCP_SNAME_OFS) { + return ERR_BUF; + } + dhcp->msg_in = (struct dhcp_msg *)p->payload; +#if LWIP_DHCP_BOOTP_FILE + /* clear boot file name */ + dhcp->boot_file_name[0] = 0; +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* parse options */ + + /* start with options field */ + options_idx = DHCP_OPTIONS_OFS; + /* parse options to the end of the received packet */ + options_idx_max = p->tot_len; +again: + q = p; + while ((q != NULL) && (options_idx >= q->len)) { + options_idx -= q->len; + options_idx_max -= q->len; + q = q->next; + } + if (q == NULL) { + return ERR_BUF; + } + offset = options_idx; + offset_max = options_idx_max; + options = (u8_t*)q->payload; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while ((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { + u8_t op = options[offset]; + u8_t len; + u8_t decode_len = 0; + int decode_idx = -1; + u16_t val_offset = offset + 2; + /* len byte might be in the next pbuf */ + if ((offset + 1) < q->len) { + len = options[offset + 1]; + } else { + len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); + } + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + decode_len = len; + switch(op) { + /* case(DHCP_OPTION_END): handled above */ + case(DHCP_OPTION_PAD): + /* special option: no len encoded */ + decode_len = len = 0; + /* will be increased below */ + offset--; + break; + case(DHCP_OPTION_SUBNET_MASK): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; + break; + case(DHCP_OPTION_ROUTER): + decode_len = 4; /* only copy the first given router */ + LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_ROUTER; + break; +#if LWIP_DHCP_PROVIDE_DNS_SERVERS + case(DHCP_OPTION_DNS_SERVER): + /* special case: there might be more than one server */ + LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); + /* limit number of DNS servers */ + decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_DNS_SERVER; + break; +#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */ + case(DHCP_OPTION_LEASE_TIME): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_LEASE_TIME; + break; +#if LWIP_DHCP_GET_NTP_SRV + case(DHCP_OPTION_NTP): + /* special case: there might be more than one server */ + LWIP_ERROR("len %% 4 == 0", len % 4 == 0, return ERR_VAL;); + /* limit number of NTP servers */ + decode_len = LWIP_MIN(len, 4 * LWIP_DHCP_MAX_NTP_SERVERS); + LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_NTP_SERVER; + break; +#endif /* LWIP_DHCP_GET_NTP_SRV*/ + case(DHCP_OPTION_OVERLOAD): + LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); + /* decode overload only in options, not in file/sname: invalid packet */ + LWIP_ERROR("overload in file/sname", options_idx == DHCP_OPTIONS_OFS, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_OVERLOAD; + break; + case(DHCP_OPTION_MESSAGE_TYPE): + LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_MSG_TYPE; + break; + case(DHCP_OPTION_SERVER_ID): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_SERVER_ID; + break; + case(DHCP_OPTION_T1): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T1; + break; + case(DHCP_OPTION_T2): + LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); + decode_idx = DHCP_OPTION_IDX_T2; + break; + default: + decode_len = 0; + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", (u16_t)op)); + break; + } + offset += len + 2; + if (decode_len > 0) { + u32_t value = 0; + u16_t copy_len; +decode_next: + LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); + if (!dhcp_option_given(dhcp, decode_idx)) { + copy_len = LWIP_MIN(decode_len, 4); + if (pbuf_copy_partial(q, &value, copy_len, val_offset) != copy_len) { + return ERR_BUF; + } + if (decode_len > 4) { + /* decode more than one u32_t */ + LWIP_ERROR("decode_len %% 4 == 0", decode_len % 4 == 0, return ERR_VAL;); + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, lwip_htonl(value)); + decode_len -= 4; + val_offset += 4; + decode_idx++; + goto decode_next; + } else if (decode_len == 4) { + value = lwip_ntohl(value); + } else { + LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); + value = ((u8_t*)&value)[0]; + } + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, value); + } + } + if (offset >= q->len) { + offset -= q->len; + offset_max -= q->len; + if ((offset < offset_max) && offset_max) { + q = q->next; + LWIP_ASSERT("next pbuf was null", q); + options = (u8_t*)q->payload; + } else { + /* We've run out of bytes, probably no end marker. Don't proceed. */ + break; + } + } + } + /* is this an overloaded message? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { + u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); + dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); + if (overload == DHCP_OVERLOAD_FILE) { + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME) { + parse_sname_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { + parse_sname_as_options = 1; + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); + } +#if LWIP_DHCP_BOOTP_FILE + if (!parse_file_as_options) { + /* only do this for ACK messages */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && + (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) + /* copy bootp file name, don't care for sname (server hostname) */ + if (pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS) != (DHCP_FILE_LEN-1)) { + return ERR_BUF; + } + /* make sure the string is really NULL-terminated */ + dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; + } +#endif /* LWIP_DHCP_BOOTP_FILE */ + } + if (parse_file_as_options) { + /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ + parse_file_as_options = 0; + options_idx = DHCP_FILE_OFS; + options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; + goto again; + } else if (parse_sname_as_options) { + parse_sname_as_options = 0; + options_idx = DHCP_SNAME_OFS; + options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; + goto again; + } + return ERR_OK; +} + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void +dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + struct netif *netif = ip_current_input_netif(); + struct dhcp *dhcp = netif_dhcp_data(netif); + struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; + u8_t msg_type; + u8_t i; + + LWIP_UNUSED_ARG(arg); + + /* Caught DHCP message from netif that does not have DHCP enabled? -> not interested */ + if ((dhcp == NULL) || (dhcp->pcb_allocated == 0)) { + goto free_pbuf_and_return; + } + + LWIP_ASSERT("invalid server address type", IP_IS_V4(addr)); + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, + ip4_addr1_16(ip_2_ip4(addr)), ip4_addr2_16(ip_2_ip4(addr)), ip4_addr3_16(ip_2_ip4(addr)), ip4_addr4_16(ip_2_ip4(addr)), port)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); + /* prevent warnings about unused arguments */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); + + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); + + if (p->len < DHCP_MIN_REPLY_LEN) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); + goto free_pbuf_and_return; + } + + if (reply_msg->op != DHCP_BOOTREPLY) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); + goto free_pbuf_and_return; + } + /* iterate through hardware address and match against DHCP message */ + for (i = 0; i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN && i < DHCP_CHADDR_LEN; i++) { + if (netif->hwaddr[i] != reply_msg->chaddr[i]) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", + (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); + goto free_pbuf_and_return; + } + } + /* match transaction ID against what we expected */ + if (lwip_ntohl(reply_msg->xid) != dhcp->xid) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",lwip_ntohl(reply_msg->xid),dhcp->xid)); + goto free_pbuf_and_return; + } + /* option fields could be unfold? */ + if (dhcp_parse_reply(dhcp, p) != ERR_OK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("problem unfolding DHCP message - too short on memory?\n")); + goto free_pbuf_and_return; + } + + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); + /* obtain pointer to DHCP message type */ + if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); + goto free_pbuf_and_return; + } + + /* read DHCP message type */ + msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); + /* message type is DHCP ACK? */ + if (msg_type == DHCP_ACK) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); + /* in requesting state? */ + if (dhcp->state == DHCP_STATE_REQUESTING) { + dhcp_handle_ack(netif); +#if DHCP_DOES_ARP_CHECK + if ((netif->flags & NETIF_FLAG_ETHARP) != 0) { + /* check if the acknowledged lease address is already in use */ + dhcp_check(netif); + } else { + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); + } +#else + /* bind interface to the acknowledged lease address */ + dhcp_bind(netif); +#endif + } + /* already bound to the given lease address? */ + else if ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REBINDING) || + (dhcp->state == DHCP_STATE_RENEWING)) { + dhcp_handle_ack(netif); + dhcp_bind(netif); + } + } + /* received a DHCP_NAK in appropriate state? */ + else if ((msg_type == DHCP_NAK) && + ((dhcp->state == DHCP_STATE_REBOOTING) || (dhcp->state == DHCP_STATE_REQUESTING) || + (dhcp->state == DHCP_STATE_REBINDING) || (dhcp->state == DHCP_STATE_RENEWING ))) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); + dhcp_handle_nak(netif); + } + /* received a DHCP_OFFER in DHCP_STATE_SELECTING state? */ + else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_STATE_SELECTING)) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_STATE_SELECTING state\n")); + dhcp->request_timeout = 0; + /* remember offered lease */ + dhcp_handle_offer(netif); + } + +free_pbuf_and_return: + if (dhcp != NULL) { + dhcp->msg_in = NULL; + } + pbuf_free(p); +} + +/** + * Create a DHCP request, fill in common headers + * + * @param netif the netif under DHCP control + * @param dhcp dhcp control struct + * @param message_type message type of the request + */ +static err_t +dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) +{ + u16_t i; +#ifndef DHCP_GLOBAL_XID + /** default global transaction identifier starting value (easy to match + * with a packet analyser). We simply increment for each new request. + * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one + * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + static u32_t xid; +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + static u32_t xid = 0xABCD0000; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ +#else + if (!xid_initialised) { + xid = DHCP_GLOBAL_XID; + xid_initialised = !xid_initialised; + } +#endif + LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); + LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); + LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); + LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); + dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); + if (dhcp->p_out == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_create_msg(): could not allocate pbuf\n")); + return ERR_MEM; + } + LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", + (dhcp->p_out->len >= sizeof(struct dhcp_msg))); + + /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ + if (message_type != DHCP_REQUEST) { + /* reuse transaction identifier in retransmissions */ + if (dhcp->tries == 0) { +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + xid = LWIP_RAND(); +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + xid++; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + } + dhcp->xid = xid; + } + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, + ("transaction id xid(%"X32_F")\n", xid)); + + dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; + + dhcp->msg_out->op = DHCP_BOOTREQUEST; + /* @todo: make link layer independent */ + dhcp->msg_out->htype = DHCP_HTYPE_ETH; + dhcp->msg_out->hlen = netif->hwaddr_len; + dhcp->msg_out->hops = 0; + dhcp->msg_out->xid = lwip_htonl(dhcp->xid); + dhcp->msg_out->secs = 0; + /* we don't need the broadcast flag since we can receive unicast traffic + before being fully configured! */ + dhcp->msg_out->flags = 0; + ip4_addr_set_zero(&dhcp->msg_out->ciaddr); + /* set ciaddr to netif->ip_addr based on message_type and state */ + if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || (message_type == DHCP_RELEASE) || + ((message_type == DHCP_REQUEST) && /* DHCP_STATE_BOUND not used for sending! */ + ((dhcp->state== DHCP_STATE_RENEWING) || dhcp->state== DHCP_STATE_REBINDING))) { + ip4_addr_copy(dhcp->msg_out->ciaddr, *netif_ip4_addr(netif)); + } + ip4_addr_set_zero(&dhcp->msg_out->yiaddr); + ip4_addr_set_zero(&dhcp->msg_out->siaddr); + ip4_addr_set_zero(&dhcp->msg_out->giaddr); + for (i = 0; i < DHCP_CHADDR_LEN; i++) { + /* copy netif hardware address, pad with zeroes */ + dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/; + } + for (i = 0; i < DHCP_SNAME_LEN; i++) { + dhcp->msg_out->sname[i] = 0; + } + for (i = 0; i < DHCP_FILE_LEN; i++) { + dhcp->msg_out->file[i] = 0; + } + dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); + dhcp->options_out_len = 0; + /* fill options field with an incrementing array (for debugging purposes) */ + for (i = 0; i < DHCP_OPTIONS_LEN; i++) { + dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ + } + /* Add option MESSAGE_TYPE */ + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, message_type); + return ERR_OK; +} + +/** + * Free previously allocated memory used to send a DHCP request. + * + * @param dhcp the dhcp struct to free the request from + */ +static void +dhcp_delete_msg(struct dhcp *dhcp) +{ + LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); + LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); + LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); + if (dhcp->p_out != NULL) { + pbuf_free(dhcp->p_out); + } + dhcp->p_out = NULL; + dhcp->msg_out = NULL; +} + +/** + * Add a DHCP message trailer + * + * Adds the END option to the DHCP message, and if + * necessary, up to three padding bytes. + * + * @param dhcp DHCP state structure + */ +static void +dhcp_option_trailer(struct dhcp *dhcp) +{ + LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); + LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); + LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; + /* packet is too small, or not 4 byte aligned? */ + while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && + (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { + /* add a fill/padding byte */ + dhcp->msg_out->options[dhcp->options_out_len++] = 0; + } +} + +/** check if DHCP supplied netif->ip_addr + * + * @param netif the netif to check + * @return 1 if DHCP supplied netif->ip_addr (states BOUND or RENEWING), + * 0 otherwise + */ +u8_t +dhcp_supplied_address(const struct netif *netif) +{ + if ((netif != NULL) && (netif_dhcp_data(netif) != NULL)) { + struct dhcp* dhcp = netif_dhcp_data(netif); + return (dhcp->state == DHCP_STATE_BOUND) || (dhcp->state == DHCP_STATE_RENEWING); + } + return 0; +} + +#endif /* LWIP_IPV4 && LWIP_DHCP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/etharp.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/etharp.c new file mode 100644 index 0000000000..3f48a9975f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/etharp.c @@ -0,0 +1,1206 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_gratuitous(our_netif) upon address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET + +#include "lwip/etharp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "netif/ethernet.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +/** Re-request a used ARP entry 1 minute before it would expire to prevent + * breaking a steadily used connection because the ARP entry timed out. */ +#define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30) +#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15) + +/** the time an ARP entry stays pending after first request, + * for ARP_TMR_INTERVAL = 1000, this is + * 10 seconds. + * + * @internal Keep this number at least 2, otherwise it might + * run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 5 + +/** ARP states */ +enum etharp_state { + ETHARP_STATE_EMPTY = 0, + ETHARP_STATE_PENDING, + ETHARP_STATE_STABLE, + ETHARP_STATE_STABLE_REREQUESTING_1, + ETHARP_STATE_STABLE_REREQUESTING_2 +#if ETHARP_SUPPORT_STATIC_ENTRIES + ,ETHARP_STATE_STATIC +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +}; + +struct etharp_entry { +#if ARP_QUEUEING + /** Pointer to queue of pending outgoing packets on this ARP entry. */ + struct etharp_q_entry *q; +#else /* ARP_QUEUEING */ + /** Pointer to a single pending outgoing packet on this ARP entry. */ + struct pbuf *q; +#endif /* ARP_QUEUEING */ + ip4_addr_t ipaddr; + struct netif *netif; + struct eth_addr ethaddr; + u16_t ctime; + u8_t state; +}; + +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; + +#if !LWIP_NETIF_HWADDRHINT +static u8_t etharp_cached_entry; +#endif /* !LWIP_NETIF_HWADDRHINT */ + +/** Try hard to create a new entry - we want the IP address to appear in + the cache (even if this means removing an active entry or so). */ +#define ETHARP_FLAG_TRY_HARD 1 +#define ETHARP_FLAG_FIND_ONLY 2 +#if ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_FLAG_STATIC_ENTRY 4 +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#if LWIP_NETIF_HWADDRHINT +#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ + *((netif)->addr_hint) = (hint); +#else /* LWIP_NETIF_HWADDRHINT */ +#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) +#endif /* LWIP_NETIF_HWADDRHINT */ + + +/* Some checks, instead of etharp_init(): */ +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) + #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" +#endif + + +static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr); +static err_t etharp_raw(struct netif *netif, + const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, + const u16_t opcode); + +#if ARP_QUEUEING +/** + * Free a complete queue of etharp entries + * + * @param q a qeueue of etharp_q_entry's to free + */ +static void +free_etharp_q(struct etharp_q_entry *q) +{ + struct etharp_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ARP_QUEUE, r); + } +} +#else /* ARP_QUEUEING */ + +/** Compatibility define: free the queued pbuf */ +#define free_etharp_q(q) pbuf_free(q) + +#endif /* ARP_QUEUEING */ + +/** Clean up ARP table entries */ +static void +etharp_free_entry(int i) +{ + /* remove from SNMP ARP index tree */ + mib2_remove_arp_entry(arp_table[i].netif, &arp_table[i].ipaddr); + /* and empty packet queue */ + if (arp_table[i].q != NULL) { + /* remove all queued packets */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + free_etharp_q(arp_table[i].q); + arp_table[i].q = NULL; + } + /* recycle entry for re-use */ + arp_table[i].state = ETHARP_STATE_EMPTY; +#ifdef LWIP_DEBUG + /* for debugging, clean out the complete entry */ + arp_table[i].ctime = 0; + arp_table[i].netif = NULL; + ip4_addr_set_zero(&arp_table[i].ipaddr); + arp_table[i].ethaddr = ethzero; +#endif /* LWIP_DEBUG */ +} + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ARP_TMR_INTERVAL milliseconds (1 second), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ + u8_t i; + + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); + /* remove expired entries from the ARP table */ + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if (state != ETHARP_STATE_EMPTY +#if ETHARP_SUPPORT_STATIC_ENTRIES + && (state != ETHARP_STATE_STATIC) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + ) { + arp_table[i].ctime++; + if ((arp_table[i].ctime >= ARP_MAXAGE) || + ((arp_table[i].state == ETHARP_STATE_PENDING) && + (arp_table[i].ctime >= ARP_MAXPENDING))) { + /* pending or stable entry has become old! */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", + arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); + /* clean up entries that have just been expired */ + etharp_free_entry(i); + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) { + /* Don't send more than one request every 2 seconds. */ + arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2; + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) { + /* Reset state to stable, so that the next transmitted packet will + re-send an ARP request. */ + arp_table[i].state = ETHARP_STATE_STABLE; + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* still pending, resend an ARP query */ + etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); + } + } + } +} + +/** + * Search the ARP table for a matching or new entry. + * + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + * + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + * + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags See @ref etharp_state + * @param netif netif related to this address (used for NETIF_HWADDRHINT) + * + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s8_t +etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif) +{ + s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; + s8_t empty = ARP_TABLE_SIZE; + u8_t i = 0; + /* oldest entry with packets on queue */ + s8_t old_queue = ARP_TABLE_SIZE; + /* its age */ + u16_t age_queue = 0, age_pending = 0, age_stable = 0; + + LWIP_UNUSED_ARG(netif); + + /** + * a) do a search through the cache, remember candidates + * b) select candidate entry + * c) create new entry + */ + + /* a) in a single search sweep, do all of this + * 1) remember the first empty entry (if any) + * 2) remember the oldest stable entry (if any) + * 3) remember the oldest pending entry without queued packets (if any) + * 4) remember the oldest pending entry with queued packets (if any) + * 5) search for a matching IP entry, either pending or stable + * until 5 matches, or all entries are searched for. + */ + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + /* no empty entry found yet and now we do find one? */ + if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); + /* remember first empty entry */ + empty = i; + } else if (state != ETHARP_STATE_EMPTY) { + LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", + state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); + /* if given, does IP address match IP address in ARP entry? */ + if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) +#if ETHARP_TABLE_MATCH_NETIF + && ((netif == NULL) || (netif == arp_table[i].netif)) +#endif /* ETHARP_TABLE_MATCH_NETIF */ + ) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); + /* found exact IP address match, simply bail out */ + return i; + } + /* pending entry? */ + if (state == ETHARP_STATE_PENDING) { + /* pending with queued packets? */ + if (arp_table[i].q != NULL) { + if (arp_table[i].ctime >= age_queue) { + old_queue = i; + age_queue = arp_table[i].ctime; + } + } else + /* pending without queued packets? */ + { + if (arp_table[i].ctime >= age_pending) { + old_pending = i; + age_pending = arp_table[i].ctime; + } + } + /* stable entry? */ + } else if (state >= ETHARP_STATE_STABLE) { +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* don't record old_stable for static entries since they never expire */ + if (state < ETHARP_STATE_STATIC) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* remember entry with oldest stable entry in oldest, its age in maxtime */ + if (arp_table[i].ctime >= age_stable) { + old_stable = i; + age_stable = arp_table[i].ctime; + } + } + } + } + } + /* { we have no match } => try to create a new entry */ + + /* don't create new entry, only search? */ + if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || + /* or no empty entry found and not allowed to recycle? */ + ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); + return (s8_t)ERR_MEM; + } + + /* b) choose the least destructive entry to recycle: + * 1) empty entry + * 2) oldest stable entry + * 3) oldest pending entry without queued packets + * 4) oldest pending entry with queued packets + * + * { ETHARP_FLAG_TRY_HARD is set at this point } + */ + + /* 1) empty entry available? */ + if (empty < ARP_TABLE_SIZE) { + i = empty; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); + } else { + /* 2) found recyclable stable entry? */ + if (old_stable < ARP_TABLE_SIZE) { + /* recycle oldest stable*/ + i = old_stable; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); + /* no queued packets should exist on stable entries */ + LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); + /* 3) found recyclable pending entry without queued packets? */ + } else if (old_pending < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_pending; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); + /* 4) found recyclable pending entry with queued packets? */ + } else if (old_queue < ARP_TABLE_SIZE) { + /* recycle oldest pending (queued packets are free in etharp_free_entry) */ + i = old_queue; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); + /* no empty or recyclable entries found */ + } else { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); + return (s8_t)ERR_MEM; + } + + /* { empty or recyclable entry found } */ + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + etharp_free_entry(i); + } + + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", + arp_table[i].state == ETHARP_STATE_EMPTY); + + /* IP address given? */ + if (ipaddr != NULL) { + /* set IP address */ + ip4_addr_copy(arp_table[i].ipaddr, *ipaddr); + } + arp_table[i].ctime = 0; +#if ETHARP_TABLE_MATCH_NETIF + arp_table[i].netif = netif; +#endif /* ETHARP_TABLE_MATCH_NETIF*/ + return (err_t)i; +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + * + * @param netif netif related to this entry (used for NETIF_ADDRHINT) + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags See @ref etharp_state + * + * @return + * - ERR_OK Successfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t +etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ + s8_t i; + LWIP_ASSERT("netif->hwaddr_len == ETH_HWADDR_LEN", netif->hwaddr_len == ETH_HWADDR_LEN); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], + (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); + /* non-unicast address? */ + if (ip4_addr_isany(ipaddr) || + ip4_addr_isbroadcast(ipaddr, netif) || + ip4_addr_ismulticast(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + /* find or create ARP entry */ + i = etharp_find_entry(ipaddr, flags, netif); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + +#if ETHARP_SUPPORT_STATIC_ENTRIES + if (flags & ETHARP_FLAG_STATIC_ENTRY) { + /* record static type */ + arp_table[i].state = ETHARP_STATE_STATIC; + } else if (arp_table[i].state == ETHARP_STATE_STATIC) { + /* found entry is a static type, don't overwrite it */ + return ERR_VAL; + } else +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* mark it stable */ + arp_table[i].state = ETHARP_STATE_STABLE; + } + + /* record network interface */ + arp_table[i].netif = netif; + /* insert in SNMP ARP index tree */ + mib2_add_arp_entry(netif, &arp_table[i].ipaddr); + + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + /* update address */ + ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); + /* reset time stamp */ + arp_table[i].ctime = 0; + /* this is where we will send out queued packets! */ +#if ARP_QUEUEING + while (arp_table[i].q != NULL) { + struct pbuf *p; + /* remember remainder of queue */ + struct etharp_q_entry *q = arp_table[i].q; + /* pop first item off the queue */ + arp_table[i].q = q->next; + /* get the packet pointer */ + p = q->p; + /* now queue entry can be freed */ + memp_free(MEMP_ARP_QUEUE, q); +#else /* ARP_QUEUEING */ + if (arp_table[i].q != NULL) { + struct pbuf *p = arp_table[i].q; + arp_table[i].q = NULL; +#endif /* ARP_QUEUEING */ + /* send the queued IP packet */ + ethernet_output(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr, ETHTYPE_IP); + /* free the queued IP packet */ + pbuf_free(p); + } + return ERR_OK; +} + +#if ETHARP_SUPPORT_STATIC_ENTRIES +/** Add a new static entry to the ARP table. If an entry exists for the + * specified IP address, this entry is overwritten. + * If packets are queued for the specified IP address, they are sent out. + * + * @param ipaddr IP address for the new static entry + * @param ethaddr ethernet address for the new static entry + * @return See return values of etharp_add_static_entry + */ +err_t +etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) +{ + struct netif *netif; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], + (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); + + netif = ip4_route(ipaddr); + if (netif == NULL) { + return ERR_RTE; + } + + return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); +} + +/** Remove a static entry from the ARP table previously added with a call to + * etharp_add_static_entry. + * + * @param ipaddr IP address of the static entry to remove + * @return ERR_OK: entry removed + * ERR_MEM: entry wasn't found + * ERR_ARG: entry wasn't a static entry but a dynamic one + */ +err_t +etharp_remove_static_entry(const ip4_addr_t *ipaddr) +{ + s8_t i; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); + + /* find or create ARP entry */ + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + + if (arp_table[i].state != ETHARP_STATE_STATIC) { + /* entry wasn't a static entry, cannot remove it */ + return ERR_ARG; + } + /* entry found, free it */ + etharp_free_entry(i); + return ERR_OK; +} +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +/** + * Remove all ARP table entries of the specified netif. + * + * @param netif points to a network interface + */ +void +etharp_cleanup_netif(struct netif *netif) +{ + u8_t i; + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { + etharp_free_entry(i); + } + } +} + +/** + * Finds (stable) ethernet/IP address pair from ARP table + * using interface and IP address index. + * @note the addresses in the ARP table are in network order! + * + * @param netif points to interface index + * @param ipaddr points to the (network order) IP address index + * @param eth_ret points to return pointer + * @param ip_ret points to return pointer + * @return table index if found, -1 otherwise + */ +s8_t +etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, + struct eth_addr **eth_ret, const ip4_addr_t **ip_ret) +{ + s8_t i; + + LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", + eth_ret != NULL && ip_ret != NULL); + + LWIP_UNUSED_ARG(netif); + + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif); + if ((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { + *eth_ret = &arp_table[i].ethaddr; + *ip_ret = &arp_table[i].ipaddr; + return i; + } + return -1; +} + +/** + * Possibility to iterate over stable ARP table entries + * + * @param i entry number, 0 to ARP_TABLE_SIZE + * @param ipaddr return value: IP address + * @param netif return value: points to interface + * @param eth_ret return value: ETH address + * @return 1 on valid index, 0 otherwise + */ +u8_t +etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret) +{ + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("eth_ret != NULL", eth_ret != NULL); + + if((i < ARP_TABLE_SIZE) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { + *ipaddr = &arp_table[i].ipaddr; + *netif = arp_table[i].netif; + *eth_ret = &arp_table[i].ethaddr; + return 1; + } else { + return 0; + } +} + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param p The ARP packet that arrived on netif. Is freed by this function. + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * + * @see pbuf_free() + */ +void +etharp_input(struct pbuf *p, struct netif *netif) +{ + struct etharp_hdr *hdr; + /* these are aligned properly, whereas the ARP header fields might not be */ + ip4_addr_t sipaddr, dipaddr; + u8_t for_us; + + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + hdr = (struct etharp_hdr *)p->payload; + + /* RFC 826 "Packet Reception": */ + if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || + (hdr->hwlen != ETH_HWADDR_LEN) || + (hdr->protolen != sizeof(ip4_addr_t)) || + (hdr->proto != PP_HTONS(ETHTYPE_IP))) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", + hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen)); + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + pbuf_free(p); + return; + } + ETHARP_STATS_INC(etharp.recv); + +#if LWIP_AUTOIP + /* We have to check if a host already has configured our random + * created link local address and continuously check if there is + * a host with this IP-address so we can detect collisions */ + autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + + /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without + * structure packing (not using structure copy which breaks strict-aliasing rules). */ + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); + + /* this interface is not configured? */ + if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { + for_us = 0; + } else { + /* ARP packet directed to us? */ + for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); + } + + /* ARP message directed to us? + -> add IP address in ARP cache; assume requester wants to talk to us, + can result in directly sending the queued packets for this host. + ARP message not directed to us? + -> update the source IP address in the cache, if present */ + etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), + for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); + + /* now act on the message itself */ + switch (hdr->opcode) { + /* ARP request? */ + case PP_HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + * reply. In any case, we time-stamp any existing ARP entry, + * and possibly send out an IP packet that was queued on it. */ + + LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n")); + /* ARP request for our address? */ + if (for_us) { + /* send ARP response */ + etharp_raw(netif, + (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, + (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), + &hdr->shwaddr, &sipaddr, + ARP_REPLY); + /* we are not configured? */ + } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* { for_us == 0 and netif->ip_addr.addr == 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n")); + /* request was not directed to us */ + } else { + /* { for_us == 0 and netif->ip_addr.addr != 0 } */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n")); + } + break; + case PP_HTONS(ARP_REPLY): + /* ARP reply. We already updated the ARP cache earlier. */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) + /* DHCP wants to know about ARP replies from any host with an + * IP address also offered to us by the DHCP server. We do not + * want to take a duplicate IP address on a single network. + * @todo How should we handle redundant (fail-over) interfaces? */ + dhcp_arp_reply(netif, &sipaddr); +#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ + break; + default: + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode))); + ETHARP_STATS_INC(etharp.err); + break; + } + /* free ARP packet */ + pbuf_free(p); +} + +/** Just a small helper function that sends a pbuf to an ethernet address + * in the arp_table specified by the index 'arp_idx'. + */ +static err_t +etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) +{ + LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", + arp_table[arp_idx].state >= ETHARP_STATE_STABLE); + /* if arp table entry is about to expire: re-request it, + but only if its state is ETHARP_STATE_STABLE to prevent flooding the + network with ARP requests if this address is used frequently. */ + if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) { + if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) { + /* issue a standard request using broadcast */ + if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } + } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) { + /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */ + if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } + } + } + + return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or ethernet_output(). + */ +err_t +etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) +{ + const struct eth_addr *dest; + struct eth_addr mcastaddr; + const ip4_addr_t *dst_addr = ipaddr; + + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); + + /* Determine on destination hardware address. Broadcasts and multicasts + * are special, other IP addresses are looked up in the ARP table. */ + + /* broadcast destination IP address? */ + if (ip4_addr_isbroadcast(ipaddr, netif)) { + /* broadcast on Ethernet also */ + dest = (const struct eth_addr *)ðbroadcast; + /* multicast destination IP address? */ + } else if (ip4_addr_ismulticast(ipaddr)) { + /* Hash IP multicast address to MAC address.*/ + mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0; + mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1; + mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2; + mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; + mcastaddr.addr[4] = ip4_addr3(ipaddr); + mcastaddr.addr[5] = ip4_addr4(ipaddr); + /* destination Ethernet address is multicast */ + dest = &mcastaddr; + /* unicast destination IP address? */ + } else { + s8_t i; + /* outside local network? if so, this can neither be a global broadcast nor + a subnet broadcast. */ + if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && + !ip4_addr_islinklocal(ipaddr)) { +#if LWIP_AUTOIP + struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr*, q->payload); + /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with + a link-local source address must always be "directly to its destination + on the same physical link. The host MUST NOT send the packet to any + router for forwarding". */ + if (!ip4_addr_islinklocal(&iphdr->src)) +#endif /* LWIP_AUTOIP */ + { +#ifdef LWIP_HOOK_ETHARP_GET_GW + /* For advanced routing, a single default gateway might not be enough, so get + the IP address of the gateway to handle the current destination address. */ + dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); + if (dst_addr == NULL) +#endif /* LWIP_HOOK_ETHARP_GET_GW */ + { + /* interface has default gateway? */ + if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) { + /* send to hardware address of default gateway IP address */ + dst_addr = netif_ip4_gw(netif); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + } + } +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t etharp_cached_entry = *(netif->addr_hint); + if (etharp_cached_entry < ARP_TABLE_SIZE) { +#endif /* LWIP_NETIF_HWADDRHINT */ + if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && +#if ETHARP_TABLE_MATCH_NETIF + (arp_table[etharp_cached_entry].netif == netif) && +#endif + (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { + /* the per-pcb-cached entry is stable and the right one! */ + ETHARP_STATS_INC(etharp.cachehit); + return etharp_output_to_arp_index(netif, q, etharp_cached_entry); + } +#if LWIP_NETIF_HWADDRHINT + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* find stable entry: do this here since this is a critical path for + throughput and etharp_find_entry() is kind of slow */ + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if ((arp_table[i].state >= ETHARP_STATE_STABLE) && +#if ETHARP_TABLE_MATCH_NETIF + (arp_table[i].netif == netif) && +#endif + (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { + /* found an existing, stable entry */ + ETHARP_SET_HINT(netif, i); + return etharp_output_to_arp_index(netif, q, i); + } + } + /* no stable entry found, use the (slower) query function: + queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, dst_addr, q); + } + + /* continuation for multicast/broadcast destinations */ + /* obtain source Ethernet address of the given interface */ + /* send packet directly on the link */ + return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), dest, ETHTYPE_IP); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out. + * + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + * + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + * to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) +{ + struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; + err_t result = ERR_MEM; + int is_new_entry = 0; + s8_t i; /* ARP entry index */ + + /* non-unicast address? */ + if (ip4_addr_isbroadcast(ipaddr, netif) || + ip4_addr_ismulticast(ipaddr) || + ip4_addr_isany(ipaddr)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); + return ERR_ARG; + } + + /* find entry in ARP cache, ask to create entry if queueing packet */ + i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif); + + /* could not find or create entry? */ + if (i < 0) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); + if (q) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); + ETHARP_STATS_INC(etharp.memerr); + } + return (err_t)i; + } + + /* mark a fresh entry as pending (we just sent a request) */ + if (arp_table[i].state == ETHARP_STATE_EMPTY) { + is_new_entry = 1; + arp_table[i].state = ETHARP_STATE_PENDING; + /* record network interface for re-sending arp request in etharp_tmr */ + arp_table[i].netif = netif; + } + + /* { i is either a STABLE or (new or existing) PENDING entry } */ + LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", + ((arp_table[i].state == ETHARP_STATE_PENDING) || + (arp_table[i].state >= ETHARP_STATE_STABLE))); + + /* do we have a new entry? or an implicit query request? */ + if (is_new_entry || (q == NULL)) { + /* try to resolve it; send out ARP request */ + result = etharp_request(netif, ipaddr); + if (result != ERR_OK) { + /* ARP request couldn't be sent */ + /* We don't re-send arp request in etharp_tmr, but we still queue packets, + since this failure could be temporary, and the next packet calling + etharp_query again could lead to sending the queued packets. */ + } + if (q == NULL) { + return result; + } + } + + /* packet given? */ + LWIP_ASSERT("q != NULL", q != NULL); + /* stable entry? */ + if (arp_table[i].state >= ETHARP_STATE_STABLE) { + /* we have a valid IP->Ethernet address mapping */ + ETHARP_SET_HINT(netif, i); + /* send the packet */ + result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* entry is still pending, queue the given packet 'q' */ + struct pbuf *p; + int copy_needed = 0; + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); + if (p->type != PBUF_ROM) { + copy_needed = 1; + break; + } + p = p->next; + } + if (copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet could be taken over? */ + if (p != NULL) { + /* queue packet ... */ +#if ARP_QUEUEING + struct etharp_q_entry *new_entry; + /* allocate a new arp queue entry */ + new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); + if (new_entry != NULL) { + unsigned int qlen = 0; + new_entry->next = 0; + new_entry->p = p; + if (arp_table[i].q != NULL) { + /* queue was already existent, append the new entry to the end */ + struct etharp_q_entry *r; + r = arp_table[i].q; + qlen++; + while (r->next != NULL) { + r = r->next; + qlen++; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + arp_table[i].q = new_entry; + } +#if ARP_QUEUE_LEN + if (qlen >= ARP_QUEUE_LEN) { + struct etharp_q_entry *old; + old = arp_table[i].q; + arp_table[i].q = arp_table[i].q->next; + pbuf_free(old->p); + memp_free(MEMP_ARP_QUEUE, old); + } +#endif + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + result = ERR_OK; + } else { + /* the pool MEMP_ARP_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } +#else /* ARP_QUEUEING */ + /* always queue one packet per ARP request only, freeing a previously queued packet */ + if (arp_table[i].q != NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + pbuf_free(arp_table[i].q); + } + arp_table[i].q = p; + result = ERR_OK; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +#endif /* ARP_QUEUEING */ + } else { + ETHARP_STATS_INC(etharp.memerr); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; + } + } + return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +static err_t +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, + const struct eth_addr *ethdst_addr, + const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, + const u16_t opcode) +{ + struct pbuf *p; + err_t result = ERR_OK; + struct etharp_hdr *hdr; + + LWIP_ASSERT("netif != NULL", netif != NULL); + + /* allocate a pbuf for the outgoing ARP request packet */ + p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM); + /* could allocate a pbuf for an ARP request? */ + if (p == NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_raw: could not allocate pbuf for ARP request.\n")); + ETHARP_STATS_INC(etharp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", + (p->len >= SIZEOF_ETHARP_HDR)); + + hdr = (struct etharp_hdr *)p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); + hdr->opcode = lwip_htons(opcode); + + LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", + (netif->hwaddr_len == ETH_HWADDR_LEN)); + + /* Write the ARP MAC-Addresses */ + ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); + ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); + /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without + * structure packing. */ + IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); + IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); + + hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); + hdr->proto = PP_HTONS(ETHTYPE_IP); + /* set hwlen and protolen */ + hdr->hwlen = ETH_HWADDR_LEN; + hdr->protolen = sizeof(ip4_addr_t); + + /* send ARP query */ +#if LWIP_AUTOIP + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + if(ip4_addr_islinklocal(ipsrc_addr)) { + ethernet_output(netif, p, ethsrc_addr, ðbroadcast, ETHTYPE_ARP); + } else +#endif /* LWIP_AUTOIP */ + { + ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP); + } + + ETHARP_STATS_INC(etharp.xmit); + /* free ARP query packet */ + pbuf_free(p); + p = NULL; + /* could not allocate pbuf for ARP request */ + + return result; +} + +/** + * Send an ARP request packet asking for ipaddr to a specific eth address. + * Used to send unicast request to refresh the ARP table just before an entry + * times out + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @param hw_dst_addr the ethernet address to send this packet to + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +static err_t +etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr, + (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), ðzero, + ipaddr, ARP_REQUEST); +} + +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, const ip4_addr_t *ipaddr) +{ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); + return etharp_request_dst(netif, ipaddr, ðbroadcast); +} +#endif /* LWIP_IPV4 && LWIP_ARP */ + +#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/icmp.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/icmp.c new file mode 100644 index 0000000000..5ee24eedfa --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/icmp.c @@ -0,0 +1,397 @@ +/** + * @file + * ICMP - Internet Control Message Protocol + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This + is not implemented. */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/stats.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be + * used to modify and send a response packet (and to 1 if this is not the case, + * e.g. when link header is stripped of when receiving) */ +#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + +/* The amount of data from the original packet to return in a dest-unreachable */ +#define ICMP_DEST_UNREACH_DATASIZE 8 + +static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); + +/** + * Processes ICMP input packets, called from ip_input(). + * + * Currently only processes icmp echo requests and sends + * out the echo response. + * + * @param p the icmp echo request packet, p->payload pointing to the icmp header + * @param inp the netif on which this packet was received + */ +void +icmp_input(struct pbuf *p, struct netif *inp) +{ + u8_t type; +#ifdef LWIP_DEBUG + u8_t code; +#endif /* LWIP_DEBUG */ + struct icmp_echo_hdr *iecho; + const struct ip_hdr *iphdr_in; + u16_t hlen; + const ip4_addr_t* src; + + ICMP_STATS_INC(icmp.recv); + MIB2_STATS_INC(mib2.icmpinmsgs); + + iphdr_in = ip4_current_header(); + hlen = IPH_HL(iphdr_in) * 4; + if (hlen < IP_HLEN) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen)); + goto lenerr; + } + if (p->len < sizeof(u16_t)*2) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); + goto lenerr; + } + + type = *((u8_t *)p->payload); +#ifdef LWIP_DEBUG + code = *(((u8_t *)p->payload)+1); +#endif /* LWIP_DEBUG */ + switch (type) { + case ICMP_ER: + /* This is OK, echo reply might have been parsed by a raw PCB + (as obviously, an echo request has been sent, too). */ + MIB2_STATS_INC(mib2.icmpinechoreps); + break; + case ICMP_ECHO: + MIB2_STATS_INC(mib2.icmpinechos); + src = ip4_current_dest_addr(); + /* multicast destination address? */ + if (ip4_addr_ismulticast(ip4_current_dest_addr())) { +#if LWIP_MULTICAST_PING + /* For multicast, use address of receiving interface as source address */ + src = netif_ip4_addr(inp); +#else /* LWIP_MULTICAST_PING */ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n")); + goto icmperr; +#endif /* LWIP_MULTICAST_PING */ + } + /* broadcast destination address? */ + if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) { +#if LWIP_BROADCAST_PING + /* For broadcast, use address of receiving interface as source address */ + src = netif_ip4_addr(inp); +#else /* LWIP_BROADCAST_PING */ + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n")); + goto icmperr; +#endif /* LWIP_BROADCAST_PING */ + } + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + if (p->tot_len < sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + goto lenerr; + } +#if CHECKSUM_CHECK_ICMP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) { + if (inet_chksum_pbuf(p) != 0) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.chkerr); + MIB2_STATS_INC(mib2.icmpinerrors); + return; + } + } +#endif +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + if (pbuf_header(p, (s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) { + /* p is not big enough to contain link headers + * allocate a new one and copy p into it + */ + struct pbuf *r; + /* allocate new packet buffer with space for link headers */ + r = pbuf_alloc(PBUF_LINK, p->tot_len + hlen, PBUF_RAM); + if (r == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); + goto icmperr; + } + if (r->len < hlen + sizeof(struct icmp_echo_hdr)) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header")); + pbuf_free(r); + goto icmperr; + } + /* copy the ip header */ + MEMCPY(r->payload, iphdr_in, hlen); + /* switch r->payload back to icmp header (cannot fail) */ + if (pbuf_header(r, (s16_t)-hlen)) { + LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0); + pbuf_free(r); + goto icmperr; + } + /* copy the rest of the packet without ip header */ + if (pbuf_copy(r, p) != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed")); + pbuf_free(r); + goto icmperr; + } + /* free the original p */ + pbuf_free(p); + /* we now have an identical copy of p that has room for link headers */ + p = r; + } else { + /* restore p->payload to point to icmp header (cannot fail) */ + if (pbuf_header(p, -(s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) { + LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); + goto icmperr; + } + } +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + /* At this point, all checks are OK. */ + /* We generate an answer by switching the dest and src ip addresses, + * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ + iecho = (struct icmp_echo_hdr *)p->payload; + if (pbuf_header(p, (s16_t)hlen)) { + LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet")); + } else { + err_t ret; + struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; + ip4_addr_copy(iphdr->src, *src); + ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); + ICMPH_TYPE_SET(iecho, ICMP_ER); +#if CHECKSUM_GEN_ICMP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { + /* adjust the checksum */ + if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; + } else { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8); + } + } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + iecho->chksum = 0; + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#else /* CHECKSUM_GEN_ICMP */ + iecho->chksum = 0; +#endif /* CHECKSUM_GEN_ICMP */ + + /* Set the correct TTL and recalculate the header checksum. */ + IPH_TTL_SET(iphdr, ICMP_TTL); + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen)); + } +#endif /* CHECKSUM_GEN_IP */ + + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + MIB2_STATS_INC(mib2.icmpoutmsgs); + /* increase number of echo replies attempted to send */ + MIB2_STATS_INC(mib2.icmpoutechoreps); + + /* send an ICMP packet */ + ret = ip4_output_if(p, src, LWIP_IP_HDRINCL, + ICMP_TTL, 0, IP_PROTO_ICMP, inp); + if (ret != ERR_OK) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret))); + } + } + break; + default: + if (type == ICMP_DUR) { + MIB2_STATS_INC(mib2.icmpindestunreachs); + } else if (type == ICMP_TE) { + MIB2_STATS_INC(mib2.icmpintimeexcds); + } else if (type == ICMP_PP) { + MIB2_STATS_INC(mib2.icmpinparmprobs); + } else if (type == ICMP_SQ) { + MIB2_STATS_INC(mib2.icmpinsrcquenchs); + } else if (type == ICMP_RD) { + MIB2_STATS_INC(mib2.icmpinredirects); + } else if (type == ICMP_TS) { + MIB2_STATS_INC(mib2.icmpintimestamps); + } else if (type == ICMP_TSR) { + MIB2_STATS_INC(mib2.icmpintimestampreps); + } else if (type == ICMP_AM) { + MIB2_STATS_INC(mib2.icmpinaddrmasks); + } else if (type == ICMP_AMR) { + MIB2_STATS_INC(mib2.icmpinaddrmaskreps); + } + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", + (s16_t)type, (s16_t)code)); + ICMP_STATS_INC(icmp.proterr); + ICMP_STATS_INC(icmp.drop); + } + pbuf_free(p); + return; +lenerr: + pbuf_free(p); + ICMP_STATS_INC(icmp.lenerr); + MIB2_STATS_INC(mib2.icmpinerrors); + return; +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING +icmperr: + pbuf_free(p); + ICMP_STATS_INC(icmp.err); + MIB2_STATS_INC(mib2.icmpinerrors); + return; +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ +} + +/** + * Send an icmp 'destination unreachable' packet, called from ip_input() if + * the transport layer protocol is unknown and from udp_input() if the local + * port is not bound. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'unreachable' packet + */ +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ + MIB2_STATS_INC(mib2.icmpoutdestunreachs); + icmp_send_response(p, ICMP_DUR, t); +} + +#if IP_FORWARD || IP_REASSEMBLY +/** + * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. + * + * @param p the input packet for which the 'time exceeded' should be sent, + * p->payload pointing to the IP header + * @param t type of the 'time exceeded' packet + */ +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ + MIB2_STATS_INC(mib2.icmpouttimeexcds); + icmp_send_response(p, ICMP_TE, t); +} + +#endif /* IP_FORWARD || IP_REASSEMBLY */ + +/** + * Send an icmp packet in response to an incoming packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IP header + * @param type Type of the ICMP header + * @param code Code of the ICMP header + */ +static void +icmp_send_response(struct pbuf *p, u8_t type, u8_t code) +{ + struct pbuf *q; + struct ip_hdr *iphdr; + /* we can use the echo header here */ + struct icmp_echo_hdr *icmphdr; + ip4_addr_t iphdr_src; + struct netif *netif; + + /* increase number of messages attempted to send */ + MIB2_STATS_INC(mib2.icmpoutmsgs); + + /* ICMP header + IP header + 8 bytes of data */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, + PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); + MIB2_STATS_INC(mib2.icmpouterrors); + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp message", + (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); + + iphdr = (struct ip_hdr *)p->payload; + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); + ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src); + LWIP_DEBUGF(ICMP_DEBUG, (" to ")); + ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest); + LWIP_DEBUGF(ICMP_DEBUG, ("\n")); + + icmphdr = (struct icmp_echo_hdr *)q->payload; + icmphdr->type = type; + icmphdr->code = code; + icmphdr->id = 0; + icmphdr->seqno = 0; + + /* copy fields from original packet */ + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); + + ip4_addr_copy(iphdr_src, iphdr->src); +#ifdef LWIP_HOOK_IP4_ROUTE_SRC + { + ip4_addr_t iphdr_dst; + ip4_addr_copy(iphdr_dst, iphdr->dest); + netif = ip4_route_src(&iphdr_src, &iphdr_dst); + } +#else + netif = ip4_route(&iphdr_src); +#endif + if (netif != NULL) { + /* calculate checksum */ + icmphdr->chksum = 0; +#if CHECKSUM_GEN_ICMP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { + icmphdr->chksum = inet_chksum(icmphdr, q->len); + } +#endif + ICMP_STATS_INC(icmp.xmit); + ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); + } + pbuf_free(q); +} + +#endif /* LWIP_IPV4 && LWIP_ICMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/igmp.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/igmp.c new file mode 100644 index 0000000000..74a6c37731 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/igmp.c @@ -0,0 +1,800 @@ +/** + * @file + * IGMP - Internet Group Management Protocol + * + * @defgroup igmp IGMP + * @ingroup ip4 + * To be called from TCPIP thread + */ + +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +/*------------------------------------------------------------- +Note 1) +Although the rfc requires V1 AND V2 capability +we will only support v2 since now V1 is very old (August 1989) +V1 can be added if required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 2) +A query for a specific group address (as opposed to ALLHOSTS) +has now been implemented as I am unsure if it is required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 3) +The router alert rfc 2113 is implemented in outgoing packets +but not checked rigorously incoming +------------------------------------------------------------- +Steve Reynolds +------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * RFC 988 - Host extensions for IP multicasting - V0 + * RFC 1054 - Host extensions for IP multicasting - + * RFC 1112 - Host extensions for IP multicasting - V1 + * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) + * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 + * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ + * RFC 2113 - IP Router Alert Option - + *----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/igmp.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/stats.h" +#include "lwip/prot/igmp.h" + +#include "string.h" + +static struct igmp_group *igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr); +static err_t igmp_remove_group(struct netif* netif, struct igmp_group *group); +static void igmp_timeout(struct netif *netif, struct igmp_group *group); +static void igmp_start_timer(struct igmp_group *group, u8_t max_time); +static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); +static err_t igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif); +static void igmp_send(struct netif *netif, struct igmp_group *group, u8_t type); + +static ip4_addr_t allsystems; +static ip4_addr_t allrouters; + +/** + * Initialize the IGMP module + */ +void +igmp_init(void) +{ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); + + IP4_ADDR(&allsystems, 224, 0, 0, 1); + IP4_ADDR(&allrouters, 224, 0, 0, 2); +} + +/** + * Start IGMP processing on interface + * + * @param netif network interface on which start IGMP processing + */ +err_t +igmp_start(struct netif *netif) +{ + struct igmp_group* group; + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", (void*)netif)); + + group = igmp_lookup_group(netif, &allsystems); + + if (group != NULL) { + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->use++; + + /* Allow the igmp messages at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); + ip4_addr_debug_print_val(IGMP_DEBUG, allsystems); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); + netif->igmp_mac_filter(netif, &allsystems, NETIF_ADD_MAC_FILTER); + } + + return ERR_OK; + } + + return ERR_MEM; +} + +/** + * Stop IGMP processing on interface + * + * @param netif network interface on which stop IGMP processing + */ +err_t +igmp_stop(struct netif *netif) +{ + struct igmp_group *group = netif_igmp_data(netif); + + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL); + + while (group != NULL) { + struct igmp_group *next = group->next; /* avoid use-after-free below */ + + /* disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); + ip4_addr_debug_print(IGMP_DEBUG, &group->group_address); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); + netif->igmp_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); + } + + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report IGMP memberships for this interface + * + * @param netif network interface on which report IGMP memberships + */ +void +igmp_report_groups(struct netif *netif) +{ + struct igmp_group *group = netif_igmp_data(netif); + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", (void*)netif)); + + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + if(group != NULL) { + group = group->next; + } + + while (group != NULL) { + igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + group = group->next; + } +} + +/** + * Search for a group in the global igmp_group_list + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search for + * @return a struct igmp_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct igmp_group * +igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr) +{ + struct igmp_group *group = netif_igmp_data(ifp); + + while (group != NULL) { + if (ip4_addr_cmp(&(group->group_address), addr)) { + return group; + } + group = group->next; + } + + /* to be clearer, we return NULL here instead of + * 'group' (which is also NULL at this point). + */ + return NULL; +} + +/** + * Search for a specific igmp group and create a new one if not found- + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search + * @return a struct igmp_group*, + * NULL on memory error. + */ +static struct igmp_group * +igmp_lookup_group(struct netif *ifp, const ip4_addr_t *addr) +{ + struct igmp_group *group; + struct igmp_group *list_head = netif_igmp_data(ifp); + + /* Search if the group already exists */ + group = igmp_lookfor_group(ifp, addr); + if (group != NULL) { + /* Group already exists. */ + return group; + } + + /* Group doesn't exist yet, create a new one */ + group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); + if (group != NULL) { + ip4_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = IGMP_GROUP_NON_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + + /* Ensure allsystems group is always first in list */ + if (list_head == NULL) { + /* this is the first entry in linked list */ + LWIP_ASSERT("igmp_lookup_group: first group must be allsystems", + (ip4_addr_cmp(addr, &allsystems) != 0)); + group->next = NULL; + netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group); + } else { + /* append _after_ first entry */ + LWIP_ASSERT("igmp_lookup_group: all except first group must not be allsystems", + (ip4_addr_cmp(addr, &allsystems) == 0)); + group->next = list_head->next; + list_head->next = group; + } + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); + ip4_addr_debug_print(IGMP_DEBUG, addr); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)ifp)); + + return group; +} + +/** + * Remove a group in the global igmp_group_list, but don't free it yet + * + * @param group the group to remove from the global igmp_group_list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +igmp_remove_group(struct netif* netif, struct igmp_group *group) +{ + err_t err = ERR_OK; + struct igmp_group *tmp_group; + + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) { + if (tmp_group->next == group) { + tmp_group->next = group->next; + break; + } + } + /* Group not found in the global igmp_group_list */ + if (tmp_group == NULL) { + err = ERR_ARG; + } + + return err; +} + +/** + * Called from ip_input() if a new IGMP packet is received. + * + * @param p received igmp packet, p->payload pointing to the igmp header + * @param inp network interface on which the packet was received + * @param dest destination ip address of the igmp packet + */ +void +igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest) +{ + struct igmp_msg* igmp; + struct igmp_group* group; + struct igmp_group* groupref; + + IGMP_STATS_INC(igmp.recv); + + /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ + if (p->len < IGMP_MINLEN) { + pbuf_free(p); + IGMP_STATS_INC(igmp.lenerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); + return; + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); + ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->src)); + LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); + ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->dest)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)inp)); + + /* Now calculate and check the checksum */ + igmp = (struct igmp_msg *)p->payload; + if (inet_chksum(igmp, p->len)) { + pbuf_free(p); + IGMP_STATS_INC(igmp.chkerr); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); + return; + } + + /* Packet is ok so find an existing group */ + group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ + + /* If group can be found or create... */ + if (!group) { + pbuf_free(p); + IGMP_STATS_INC(igmp.drop); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); + return; + } + + /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ + switch (igmp->igmp_msgtype) { + case IGMP_MEMB_QUERY: + /* IGMP_MEMB_QUERY to the "all systems" address ? */ + if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) { + /* THIS IS THE GENERAL QUERY */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + + if (igmp->igmp_maxresp == 0) { + IGMP_STATS_INC(igmp.rx_v1); + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); + igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; + } else { + IGMP_STATS_INC(igmp.rx_general); + } + + groupref = netif_igmp_data(inp); + + /* Do not send messages on the all systems group address! */ + /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */ + if(groupref != NULL) { + groupref = groupref->next; + } + + while (groupref) { + igmp_delaying_member(groupref, igmp->igmp_maxresp); + groupref = groupref->next; + } + } else { + /* IGMP_MEMB_QUERY to a specific group ? */ + if (!ip4_addr_isany(&igmp->igmp_group_address)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); + ip4_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); + if (ip4_addr_cmp(dest, &allsystems)) { + ip4_addr_t groupaddr; + LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + /* we first need to re-look for the group since we used dest last time */ + ip4_addr_copy(groupaddr, igmp->igmp_group_address); + group = igmp_lookfor_group(inp, &groupaddr); + } else { + LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + } + + if (group != NULL) { + IGMP_STATS_INC(igmp.rx_group); + igmp_delaying_member(group, igmp->igmp_maxresp); + } else { + IGMP_STATS_INC(igmp.drop); + } + } else { + IGMP_STATS_INC(igmp.proterr); + } + } + break; + case IGMP_V2_MEMB_REPORT: + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); + IGMP_STATS_INC(igmp.rx_report); + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { + /* This is on a specific group we have already looked up */ + group->timer = 0; /* stopped */ + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + break; + default: + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", + igmp->igmp_msgtype, group->group_state, (void*)&group, (void*)inp)); + IGMP_STATS_INC(igmp.proterr); + break; + } + + pbuf_free(p); + return; +} + +/** + * @ingroup igmp + * Join a group on one network interface. + * + * @param ifaddr ip address of the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we join this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + err = igmp_joingroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Return an error even if some network interfaces are joined */ + /** @todo undo any other netif already joined */ + return err; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * @ingroup igmp + * Join a group on one network interface. + * + * @param netif the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif, an err_t otherwise + */ +err_t +igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) +{ + struct igmp_group *group; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* make sure it is an igmp-enabled netif */ + LWIP_ERROR("igmp_joingroup_netif: attempt to join on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); + + /* find group or create a new one if not found */ + group = igmp_lookup_group(netif, groupaddr); + + if (group != NULL) { + /* This should create a new group, check the state to make sure */ + if (group->group_state != IGMP_GROUP_NON_MEMBER) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n")); + } else { + /* OK - it was new group */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: join to new group: ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If first use of the group, allow the group at the MAC level */ + if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: igmp_mac_filter(ADD ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); + netif->igmp_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); + } + + IGMP_STATS_INC(igmp.tx_join); + igmp_send(netif, group, IGMP_V2_MEMB_REPORT); + + igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + + /* Need to work out where this timer comes from */ + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } + /* Increment group use */ + group->use++; + /* Join on this interface */ + return ERR_OK; + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup_netif: Not enough memory to join to group\n")); + return ERR_MEM; + } +} + +/** + * @ingroup igmp + * Leave a group on one network interface. + * + * @param ifaddr ip address of the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we leave this interface ? */ + if ((netif->flags & NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) { + err_t res = igmp_leavegroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Store this result if we have not yet gotten a success */ + err = res; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * @ingroup igmp + * Leave a group on one network interface. + * + * @param netif the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif, an err_t otherwise + */ +err_t +igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr) +{ + struct igmp_group *group; + + /* make sure it is multicast address */ + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + + /* make sure it is an igmp-enabled netif */ + LWIP_ERROR("igmp_leavegroup_netif: attempt to leave on non-IGMP netif", netif->flags & NETIF_FLAG_IGMP, return ERR_VAL;); + + /* find group */ + group = igmp_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Only send a leave if the flag is set according to the state diagram */ + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: Leaving group: ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* If there is no other use of the group */ + if (group->use <= 1) { + /* Remove the group from the list */ + igmp_remove_group(netif, group); + + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: sending leaving group\n")); + IGMP_STATS_INC(igmp.tx_leave); + igmp_send(netif, group, IGMP_LEAVE_GROUP); + } + + /* Disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: igmp_mac_filter(DEL ")); + ip4_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", (void*)netif)); + netif->igmp_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); + } + + /* Free group struct */ + memp_free(MEMP_IGMP_GROUP, group); + } else { + /* Decrement group use */ + group->use--; + } + return ERR_OK; + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup_netif: not member of group\n")); + return ERR_VAL; + } +} + +/** + * The igmp timer function (both for NO_SYS=1 and =0) + * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). + */ +void +igmp_tmr(void) +{ + struct netif *netif = netif_list; + + while (netif != NULL) { + struct igmp_group *group = netif_igmp_data(netif); + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + igmp_timeout(netif, group); + } + } + group = group->next; + } + netif = netif->next; + } +} + +/** + * Called if a timeout for one group is reached. + * Sends a report for this group. + * + * @param group an igmp_group for which a timeout is reached + */ +static void +igmp_timeout(struct netif *netif, struct igmp_group *group) +{ + /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group + (unless it is the allsystems group) */ + if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); + ip4_addr_debug_print(IGMP_DEBUG, &(group->group_address)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)netif)); + + group->group_state = IGMP_GROUP_IDLE_MEMBER; + + IGMP_STATS_INC(igmp.tx_report); + igmp_send(netif, group, IGMP_V2_MEMB_REPORT); + } +} + +/** + * Start a timer for an igmp group + * + * @param group the igmp_group for which to start a timer + * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with + * every call to igmp_tmr()) + */ +static void +igmp_start_timer(struct igmp_group *group, u8_t max_time) +{ +#ifdef LWIP_RAND + group->timer = max_time > 2 ? (LWIP_RAND() % max_time) : 1; +#else /* LWIP_RAND */ + /* ATTENTION: use this only if absolutely necessary! */ + group->timer = max_time / 2; +#endif /* LWIP_RAND */ + + if (group->timer == 0) { + group->timer = 1; + } +} + +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +static void +igmp_delaying_member(struct igmp_group *group, u8_t maxresp) +{ + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + igmp_start_timer(group, maxresp); + group->group_state = IGMP_GROUP_DELAYING_MEMBER; + } +} + + +/** + * Sends an IP packet on a network interface. This function constructs the IP header + * and calculates the IP header checksum. If the source IP address is NULL, + * the IP address of the outgoing network interface is filled in as source address. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + */ +static err_t +igmp_ip_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, struct netif *netif) +{ + /* This is the "router alert" option */ + u16_t ra[2]; + ra[0] = PP_HTONS(ROUTER_ALERT); + ra[1] = 0x0000; /* Router shall examine packet */ + IGMP_STATS_INC(igmp.xmit); + return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); +} + +/** + * Send an igmp packet to a specific group. + * + * @param group the group to which to send the packet + * @param type the type of igmp packet to send + */ +static void +igmp_send(struct netif *netif, struct igmp_group *group, u8_t type) +{ + struct pbuf* p = NULL; + struct igmp_msg* igmp = NULL; + ip4_addr_t src = *IP4_ADDR_ANY4; + ip4_addr_t* dest = NULL; + + /* IP header + "router alert" option + IGMP header */ + p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); + + if (p) { + igmp = (struct igmp_msg *)p->payload; + LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", + (p->len >= sizeof(struct igmp_msg))); + ip4_addr_copy(src, *netif_ip4_addr(netif)); + + if (type == IGMP_V2_MEMB_REPORT) { + dest = &(group->group_address); + ip4_addr_copy(igmp->igmp_group_address, group->group_address); + group->last_reporter_flag = 1; /* Remember we were the last to report */ + } else { + if (type == IGMP_LEAVE_GROUP) { + dest = &allrouters; + ip4_addr_copy(igmp->igmp_group_address, group->group_address); + } + } + + if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { + igmp->igmp_msgtype = type; + igmp->igmp_maxresp = 0; + igmp->igmp_checksum = 0; + igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); + + igmp_ip_output_if(p, &src, dest, netif); + } + + pbuf_free(p); + } else { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); + IGMP_STATS_INC(igmp.memerr); + } +} + +#endif /* LWIP_IPV4 && LWIP_IGMP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4.c new file mode 100644 index 0000000000..4e4eb61146 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4.c @@ -0,0 +1,1086 @@ +/** + * @file + * This is the IPv4 layer implementation for incoming and outgoing IP traffic. + * + * @see ip_frag.c + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip4_frag.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/igmp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/autoip.h" +#include "lwip/stats.h" +#include "lwip/prot/dhcp.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** Set this to 0 in the rare case of wanting to call an extra function to + * generate the IP checksum (in contrast to calculating it on-the-fly). */ +#ifndef LWIP_INLINE_IP_CHKSUM +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define LWIP_INLINE_IP_CHKSUM 0 +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define LWIP_INLINE_IP_CHKSUM 1 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#endif + +#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP_INLINE 1 +#else +#define CHECKSUM_GEN_IP_INLINE 0 +#endif + +#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 + +/** Some defines for DHCP to let link-layer-addressed packets through while the + * netif is down. + * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT(port) + * to return 1 if the port is accepted and 0 if the port is not accepted. + */ +#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) +/* accept DHCP client port and custom port */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ + || (LWIP_IP_ACCEPT_UDP_PORT(port))) +#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept custom port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) +#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept DHCP client port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) +#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ + +#else /* LWIP_DHCP */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 +#endif /* LWIP_DHCP */ + +/** The IP header ID of the next outgoing IP packet */ +static u16_t ip_id; + +#if LWIP_MULTICAST_TX_OPTIONS +/** The default netif used for multicast */ +static struct netif* ip4_default_multicast_netif; + +/** + * @ingroup ip4 + * Set a default netif for IPv4 multicast. */ +void +ip4_set_default_multicast_netif(struct netif* default_multicast_netif) +{ + ip4_default_multicast_netif = default_multicast_netif; +} +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +/** + * Source based IPv4 routing must be fully implemented in + * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides he parameters. + */ +struct netif * +ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src) +{ + if (src != NULL) { + /* when src==NULL, the hook is called from ip4_route(dest) */ + struct netif *netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, src); + if (netif != NULL) { + return netif; + } + } + return ip4_route(dest); +} +#endif /* LWIP_HOOK_IP4_ROUTE_SRC */ + +/** + * Finds the appropriate network interface for a given IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + * + * @param dest the destination IP address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip4_route(const ip4_addr_t *dest) +{ + struct netif *netif; + +#if LWIP_MULTICAST_TX_OPTIONS + /* Use administratively selected interface for multicast by default */ + if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) { + return ip4_default_multicast_netif; + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + /* iterate through netifs */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + /* is the netif up, does it have a link and a valid address? */ + if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* network mask matches? */ + if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { + /* return netif on which to forward IP packet */ + return netif; + } + /* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */ + if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) { + /* return netif on which to forward IP packet */ + return netif; + } + } + } + +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + /* loopif is disabled, looopback traffic is passed through any netif */ + if (ip4_addr_isloopback(dest)) { + /* don't check for link on loopback traffic */ + if (netif_default != NULL && netif_is_up(netif_default)) { + return netif_default; + } + /* default netif is not up, just use any netif for loopback traffic */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (netif_is_up(netif)) { + return netif; + } + } + return NULL; + } +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC + netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, NULL); + if (netif != NULL) { + return netif; + } +#elif defined(LWIP_HOOK_IP4_ROUTE) + netif = LWIP_HOOK_IP4_ROUTE(dest); + if (netif != NULL) { + return netif; + } +#endif + + if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || + ip4_addr_isany_val(*netif_ip4_addr(netif_default))) { + /* No matching netif found and default netif is not usable. + If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + MIB2_STATS_INC(mib2.ipoutnoroutes); + return NULL; + } + + return netif_default; +} + +#if IP_FORWARD +/** + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + * @param p the packet to forward + * @return 1: can forward 0: discard + */ +static int +ip4_canforward(struct pbuf *p) +{ + u32_t addr = lwip_htonl(ip4_addr_get_u32(ip4_current_dest_addr())); + + if (p->flags & PBUF_FLAG_LLBCAST) { + /* don't route link-layer broadcasts */ + return 0; + } + if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) { + /* don't route link-layer multicasts unless the destination address is an IP + multicast address */ + return 0; + } + if (IP_EXPERIMENTAL(addr)) { + return 0; + } + if (IP_CLASSA(addr)) { + u32_t net = addr & IP_CLASSA_NET; + if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { + /* don't route loopback packets */ + return 0; + } + } + return 1; +} + +/** + * Forwards an IP packet. It finds an appropriate route for the + * packet, decrements the TTL value of the packet, adjusts the + * checksum and outputs the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IP header of the input packet + * @param inp the netif on which this packet was received + */ +static void +ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + PERF_START; + LWIP_UNUSED_ARG(inp); + + if (!ip4_canforward(p)) { + goto return_noroute; + } + + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip4_addr_islinklocal(ip4_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + goto return_noroute; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip4_route_src(ip4_current_dest_addr(), ip4_current_src_addr()); + if (netif == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + /* @todo: send ICMP_DUR_NET? */ + goto return_noroute; + } +#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not bouncing packets back on incoming interface.\n")); + goto return_noroute; + } +#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ + + /* decrement TTL */ + IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); + /* send ICMP if TTL == 0 */ + if (IPH_TTL(iphdr) == 0) { + MIB2_STATS_INC(mib2.ipinhdrerrors); +#if LWIP_ICMP + /* Don't send ICMP messages in response to ICMP messages */ + if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { + icmp_time_exceeded(p, ICMP_TE_TTL); + } +#endif /* LWIP_ICMP */ + return; + } + + /* Incrementally update the IP checksum. */ + if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); + } else { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); + } + + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), + ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); + + IP_STATS_INC(ip.fw); + MIB2_STATS_INC(mib2.ipforwdatagrams); + IP_STATS_INC(ip.xmit); + + PERF_STOP("ip4_forward"); + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) { + if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { +#if IP_FRAG + ip4_frag(p, netif, ip4_current_dest_addr()); +#else /* IP_FRAG */ + /* @todo: send ICMP Destination Unreachable code 13 "Communication administratively prohibited"? */ +#endif /* IP_FRAG */ + } else { +#if LWIP_ICMP + /* send ICMP Destination Unreachable code 4: "Fragmentation Needed and DF Set" */ + icmp_dest_unreach(p, ICMP_DUR_FRAG); +#endif /* LWIP_ICMP */ + } + return; + } + /* transmit pbuf on chosen interface */ + netif->output(netif, p, ip4_current_dest_addr()); + return; +return_noroute: + MIB2_STATS_INC(mib2.ipoutnoroutes); +} +#endif /* IP_FORWARD */ + +/** + * This function is called by the network interface device driver when + * an IP packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * @param p the received IP packet (p->payload points to IP header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + * processed, but currently always returns ERR_OK) + */ +err_t +ip4_input(struct pbuf *p, struct netif *inp) +{ + struct ip_hdr *iphdr; + struct netif *netif; + u16_t iphdr_hlen; + u16_t iphdr_len; +#if IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP + int check_ip_src = 1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP */ + + IP_STATS_INC(ip.recv); + MIB2_STATS_INC(mib2.ipinreceives); + + /* identify the IP header */ + iphdr = (struct ip_hdr *)p->payload; + if (IPH_V(iphdr) != 4) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", (u16_t)IPH_V(iphdr))); + ip4_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.err); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinhdrerrors); + return ERR_OK; + } + +#ifdef LWIP_HOOK_IP4_INPUT + if (LWIP_HOOK_IP4_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + + /* obtain IP header length in number of 32-bit words */ + iphdr_hlen = IPH_HL(iphdr); + /* calculate IP header length in bytes */ + iphdr_hlen *= 4; + /* obtain ip length in bytes */ + iphdr_len = lwip_ntohs(IPH_LEN(iphdr)); + + /* Trim pbuf. This is especially required for packets < 60 bytes. */ + if (iphdr_len < p->tot_len) { + pbuf_realloc(p, iphdr_len); + } + + /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ + if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len) || (iphdr_hlen < IP_HLEN)) { + if (iphdr_hlen < IP_HLEN) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("ip4_input: short IP header (%"U16_F" bytes) received, IP packet dropped\n", iphdr_hlen)); + } + if (iphdr_hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_hlen, p->len)); + } + if (iphdr_len > p->tot_len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", + iphdr_len, p->tot_len)); + } + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.lenerr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipindiscards); + return ERR_OK; + } + + /* verify checksum */ +#if CHECKSUM_CHECK_IP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) { + if (inet_chksum(iphdr, iphdr_hlen) != 0) { + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); + ip4_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.chkerr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinhdrerrors); + return ERR_OK; + } + } +#endif + + /* copy IP addresses to aligned ip_addr_t */ + ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest); + ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src); + + /* match packet against an interface, i.e. is this packet for us? */ + if (ip4_addr_ismulticast(ip4_current_dest_addr())) { +#if LWIP_IGMP + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip4_current_dest_addr()))) { + /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */ + ip4_addr_t allsystems; + IP4_ADDR(&allsystems, 224, 0, 0, 1); + if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) && + ip4_addr_isany(ip4_current_src_addr())) { + check_ip_src = 0; + } + netif = inp; + } else { + netif = NULL; + } +#else /* LWIP_IGMP */ + if ((netif_is_up(inp)) && (!ip4_addr_isany_val(*netif_ip4_addr(inp)))) { + netif = inp; + } else { + netif = NULL; + } +#endif /* LWIP_IGMP */ + } else { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. + 'first' is used as a boolean to mark whether we started walking the list */ + int first = 1; + netif = inp; + do { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", + ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(netif_ip4_addr(netif)), + ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(netif_ip4_netmask(netif)), + ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)), + ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(netif_ip4_netmask(netif)))); + + /* interface is up and configured? */ + if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) { + /* unicast to this interface address? */ + if (ip4_addr_cmp(ip4_current_dest_addr(), netif_ip4_addr(netif)) || + /* or broadcast on this interface network address? */ + ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + || (ip4_addr_get_u32(ip4_current_dest_addr()) == PP_HTONL(IPADDR_LOOPBACK)) +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ + ) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } +#if LWIP_AUTOIP + /* connections to link-local addresses must persist after changing + the netif's address (RFC3927 ch. 1.9) */ + if (autoip_accept_packet(netif, ip4_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } +#endif /* LWIP_AUTOIP */ + } + if (first) { +#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF + /* Packets sent to the loopback address must not be accepted on an + * interface that does not have the loopback address assigned to it, + * unless a non-loopback interface is used for loopback traffic. */ + if (ip4_addr_isloopback(ip4_current_dest_addr())) { + netif = NULL; + break; + } +#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ + first = 0; + netif = netif_list; + } else { + netif = netif->next; + } + if (netif == inp) { + netif = netif->next; + } + } while (netif != NULL); + } + +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed + * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. + * According to RFC 1542 section 3.1.1, referred by RFC 2131). + * + * If you want to accept private broadcast communication while a netif is down, + * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: + * + * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) + */ + if (netif == NULL) { + /* remote port is DHCP server? */ + if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n", + lwip_ntohs(udphdr->dest))); + if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n")); + netif = inp; + check_ip_src = 0; + } + } + } +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + + /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ +#if LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING + if (check_ip_src +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ + && !ip4_addr_isany_val(*ip4_current_src_addr()) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + ) +#endif /* LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { + if ((ip4_addr_isbroadcast(ip4_current_src_addr(), inp)) || + (ip4_addr_ismulticast(ip4_current_src_addr()))) { + /* packet source is not valid */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip4_input: packet source is not valid.\n")); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinaddrerrors); + MIB2_STATS_INC(mib2.ipindiscards); + return ERR_OK; + } + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: packet not for us.\n")); +#if IP_FORWARD + /* non-broadcast packet? */ + if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), inp)) { + /* try to forward IP packet on (other) interfaces */ + ip4_forward(p, iphdr, inp); + } else +#endif /* IP_FORWARD */ + { + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinaddrerrors); + MIB2_STATS_INC(mib2.ipindiscards); + } + pbuf_free(p); + return ERR_OK; + } + /* packet consists of multiple fragments? */ + if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { +#if IP_REASSEMBLY /* packet fragment reassembly code present? */ + LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip4_reass()\n", + lwip_ntohs(IPH_ID(iphdr)), p->tot_len, lwip_ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8))); + /* reassemble the packet*/ + p = ip4_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + return ERR_OK; + } + iphdr = (struct ip_hdr *)p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ + pbuf_free(p); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", + lwip_ntohs(IPH_OFFSET(iphdr)))); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + MIB2_STATS_INC(mib2.ipinunknownprotos); + return ERR_OK; +#endif /* IP_REASSEMBLY */ + } + +#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ + +#if LWIP_IGMP + /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ + if ((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { +#else + if (iphdr_hlen > IP_HLEN) { +#endif /* LWIP_IGMP */ + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); + pbuf_free(p); + IP_STATS_INC(ip.opterr); + IP_STATS_INC(ip.drop); + /* unsupported protocol feature */ + MIB2_STATS_INC(mib2.ipinunknownprotos); + return ERR_OK; + } +#endif /* IP_OPTIONS_ALLOWED == 0 */ + + /* send to upper layers */ + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: \n")); + ip4_debug_print(p); + LWIP_DEBUGF(IP_DEBUG, ("ip4_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + + ip_data.current_netif = netif; + ip_data.current_input_netif = inp; + ip_data.current_ip4_header = iphdr; + ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4; + +#if LWIP_RAW + /* raw input did not eat the packet? */ + if (raw_input(p, inp) == 0) +#endif /* LWIP_RAW */ + { + pbuf_header(p, -(s16_t)iphdr_hlen); /* Move to payload, no check necessary. */ + + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP + case IP_PROTO_UDP: +#if LWIP_UDPLITE + case IP_PROTO_UDPLITE: +#endif /* LWIP_UDPLITE */ + MIB2_STATS_INC(mib2.ipindelivers); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP_PROTO_TCP: + MIB2_STATS_INC(mib2.ipindelivers); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP + case IP_PROTO_ICMP: + MIB2_STATS_INC(mib2.ipindelivers); + icmp_input(p, inp); + break; +#endif /* LWIP_ICMP */ +#if LWIP_IGMP + case IP_PROTO_IGMP: + igmp_input(p, inp, ip4_current_dest_addr()); + break; +#endif /* LWIP_IGMP */ + default: +#if LWIP_ICMP + /* send ICMP destination protocol unreachable unless is was a broadcast */ + if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) && + !ip4_addr_ismulticast(ip4_current_dest_addr())) { + pbuf_header_force(p, iphdr_hlen); /* Move to ip header, no check necessary. */ + p->payload = iphdr; + icmp_dest_unreach(p, ICMP_DUR_PROTO); + } +#endif /* LWIP_ICMP */ + pbuf_free(p); + + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", (u16_t)IPH_PROTO(iphdr))); + + IP_STATS_INC(ip.proterr); + IP_STATS_INC(ip.drop); + MIB2_STATS_INC(mib2.ipinunknownprotos); + } + } + + /* @todo: this is not really necessary... */ + ip_data.current_netif = NULL; + ip_data.current_input_netif = NULL; + ip_data.current_ip4_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip4_addr_set_any(ip4_current_src_addr()); + ip4_addr_set_any(ip4_current_dest_addr()); + + return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + * If the destination IP address is LWIP_IP_HDRINCL, p is assumed to already + * include an IP header and p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IP/LINK headers + * returns errors returned by netif->output + * + * @note ip_id: RFC791 "some host may be able to simply use + * unique identifiers independent of destination" + */ +err_t +ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip4_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +err_t +ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ + const ip4_addr_t *src_used = src; + if (dest != LWIP_IP_HDRINCL) { + if (ip4_addr_isany(src)) { + src_used = netif_ip4_addr(netif); + } + } + +#if IP_OPTIONS_SEND + return ip4_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif, + ip_options, optlen); +#else /* IP_OPTIONS_SEND */ + return ip4_output_if_src(p, src_used, dest, ttl, tos, proto, netif); +#endif /* IP_OPTIONS_SEND */ +} + +/** + * Same as ip_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip4_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if_opt() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ + struct ip_hdr *iphdr; + ip4_addr_t dest_addr; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum = 0; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + MIB2_STATS_INC(mib2.ipoutrequests); + + /* Should the IP header be generated or is it already included in p? */ + if (dest != LWIP_IP_HDRINCL) { + u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND + u16_t optlen_aligned = 0; + if (optlen != 0) { +#if CHECKSUM_GEN_IP_INLINE + int i; +#endif /* CHECKSUM_GEN_IP_INLINE */ + /* round up to a multiple of 4 */ + optlen_aligned = ((optlen + 3) & ~3); + ip_hlen += optlen_aligned; + /* First write in the IP options */ + if (pbuf_header(p, optlen_aligned)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: not enough room for IP options in pbuf\n")); + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_BUF; + } + MEMCPY(p->payload, ip_options, optlen); + if (optlen < optlen_aligned) { + /* zero the remaining bytes */ + memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); + } +#if CHECKSUM_GEN_IP_INLINE + for (i = 0; i < optlen_aligned/2; i++) { + chk_sum += ((u16_t*)p->payload)[i]; + } +#endif /* CHECKSUM_GEN_IP_INLINE */ + } +#endif /* IP_OPTIONS_SEND */ + /* generate IP header */ + if (pbuf_header(p, IP_HLEN)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: not enough room for IP header in pbuf\n")); + + IP_STATS_INC(ip.err); + MIB2_STATS_INC(mib2.ipoutdiscards); + return ERR_BUF; + } + + iphdr = (struct ip_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", + (p->len >= sizeof(struct ip_hdr))); + + IPH_TTL_SET(iphdr, ttl); + IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += PP_NTOHS(proto | (ttl << 8)); +#endif /* CHECKSUM_GEN_IP_INLINE */ + + /* dest cannot be NULL here */ + ip4_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + IPH_VHL_SET(iphdr, 4, ip_hlen / 4); + IPH_TOS_SET(iphdr, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += PP_NTOHS(tos | (iphdr->_v_hl << 8)); +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_LEN_SET(iphdr, lwip_htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ + IPH_OFFSET_SET(iphdr, 0); + IPH_ID_SET(iphdr, lwip_htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ + ++ip_id; + + if (src == NULL) { + ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY4); + } else { + /* src cannot be NULL here */ + ip4_addr_copy(iphdr->src, *src); + } + +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; + chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); + chk_sum = (chk_sum >> 16) + chk_sum; + chk_sum = ~chk_sum; + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + iphdr->_chksum = (u16_t)chk_sum; /* network order */ + } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + IPH_CHKSUM_SET(iphdr, 0); + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ +#else /* CHECKSUM_GEN_IP_INLINE */ + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); + } +#endif /* CHECKSUM_GEN_IP */ +#endif /* CHECKSUM_GEN_IP_INLINE */ + } else { + /* IP header already included in p */ + iphdr = (struct ip_hdr *)p->payload; + ip4_addr_copy(dest_addr, iphdr->dest); + dest = &dest_addr; + } + + IP_STATS_INC(ip.xmit); + + LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); + ip4_debug_print(p); + +#if ENABLE_LOOPBACK + if (ip4_addr_cmp(dest, netif_ip4_addr(netif)) +#if !LWIP_HAVE_LOOPIF + || ip4_addr_isloopback(dest) +#endif /* !LWIP_HAVE_LOOPIF */ + ) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); + return netif_loop_output(netif, p); + } +#if LWIP_MULTICAST_TX_OPTIONS + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p); + } +#endif /* LWIP_MULTICAST_TX_OPTIONS */ +#endif /* ENABLE_LOOPBACK */ +#if IP_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > netif->mtu)) { + return ip4_frag(p, netif, dest); + } +#endif /* IP_FRAG */ + + LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n")); + return netif->output(netif, p, dest); +} + +/** + * Simple interface to ip_output_if. It finds the outgoing network + * interface and calls upon ip_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto) +{ + struct netif *netif; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if ((netif = ip4_route_src(dest, src)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + return ip4_output_if(p, src, dest, ttl, tos, proto, netif); +} + +#if LWIP_NETIF_HWADDRHINT +/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IP header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP4_ADDR_ANY, the + * IP address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param addr_hint address hint pointer set to netif->addr_hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ + struct netif *netif; + err_t err; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if ((netif = ip4_route_src(dest, src)) == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); + IP_STATS_INC(ip.rterr); + return ERR_RTE; + } + + NETIF_SET_HWADDRHINT(netif, addr_hint); + err = ip4_output_if(p, src, dest, ttl, tos, proto, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if IP_DEBUG +/* Print an IP header by using LWIP_DEBUGF + * @param p an IP packet, p->payload pointing to the IP header + */ +void +ip4_debug_print(struct pbuf *p) +{ + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; + + LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", + (u16_t)IPH_V(iphdr), + (u16_t)IPH_HL(iphdr), + (u16_t)IPH_TOS(iphdr), + lwip_ntohs(IPH_LEN(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", + lwip_ntohs(IPH_ID(iphdr)), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 15 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 14 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) >> 13 & 1), + (u16_t)(lwip_ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", + (u16_t)IPH_TTL(iphdr), + (u16_t)IPH_PROTO(iphdr), + lwip_ntohs(IPH_CHKSUM(iphdr)))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", + ip4_addr1_16(&iphdr->src), + ip4_addr2_16(&iphdr->src), + ip4_addr3_16(&iphdr->src), + ip4_addr4_16(&iphdr->src))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", + ip4_addr1_16(&iphdr->dest), + ip4_addr2_16(&iphdr->dest), + ip4_addr3_16(&iphdr->dest), + ip4_addr4_16(&iphdr->dest))); + LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ + +#endif /* LWIP_IPV4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_addr.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_addr.c new file mode 100644 index 0000000000..2d479923bd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_addr.c @@ -0,0 +1,331 @@ +/** + * @file + * This is the IPv4 address tools implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); +const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST); + +/** + * Determine if an address is a broadcast address on a network interface + * + * @param addr address to be checked + * @param netif the network interface against which the address is checked + * @return returns non-zero if the address is a broadcast address + */ +u8_t +ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif) +{ + ip4_addr_t ipaddr; + ip4_addr_set_u32(&ipaddr, addr); + + /* all ones (broadcast) or all zeroes (old skool broadcast) */ + if ((~addr == IPADDR_ANY) || + (addr == IPADDR_ANY)) { + return 1; + /* no broadcast support on this network interface? */ + } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { + /* the given address cannot be a broadcast address + * nor can we check against any broadcast addresses */ + return 0; + /* address matches network interface address exactly? => no broadcast */ + } else if (addr == ip4_addr_get_u32(netif_ip4_addr(netif))) { + return 0; + /* on the same (sub) network... */ + } else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) + /* ...and host identifier bits are all ones? =>... */ + && ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) == + (IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) { + /* => network broadcast address */ + return 1; + } else { + return 0; + } +} + +/** Checks if a netmask is valid (starting with ones, then only zeros) + * + * @param netmask the IPv4 netmask to check (in network byte order!) + * @return 1 if the netmask is valid, 0 if it is not + */ +u8_t +ip4_addr_netmask_valid(u32_t netmask) +{ + u32_t mask; + u32_t nm_hostorder = lwip_htonl(netmask); + + /* first, check for the first zero */ + for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) == 0) { + break; + } + } + /* then check that there is no one */ + for (; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) != 0) { + /* there is a one after the first zero -> invalid */ + return 0; + } + } + /* no one after the first zero -> valid */ + return 1; +} + +/* Here for now until needed in other places in lwIP */ +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif + +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @return ip address in network order + */ +u32_t +ipaddr_addr(const char *cp) +{ + ip4_addr_t val; + + if (ip4addr_aton(cp, &val)) { + return ip4_addr_get_u32(&val); + } + return (IPADDR_NONE); +} + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip4addr_aton(const char *cp, ip4_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) { + return 0; + } + val = 0; + base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') { + base = 16; + c = *++cp; + } else { + base = 8; + } + } + for (;;) { + if (isdigit(c)) { + val = (val * base) + (u32_t)(c - '0'); + c = *++cp; + } else if (base == 16 && isxdigit(c)) { + val = (val << 4) | (u32_t)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else { + break; + } + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) { + return 0; + } + *pp++ = val; + c = *++cp; + } else { + break; + } + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) { + return 0; + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + + case 0: + return 0; /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) { + return 0; + } + if (parts[0] > 0xff) { + return 0; + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff)) { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + LWIP_ASSERT("unhandled", 0); + break; + } + if (addr) { + ip4_addr_set_u32(addr, lwip_htonl(val)); + } + return 1; +} + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char* +ip4addr_ntoa(const ip4_addr_t *addr) +{ + static char str[IP4ADDR_STRLEN_MAX]; + return ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX); +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char* +ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen) +{ + u32_t s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + int len = 0; + + s_addr = ip4_addr_get_u32(addr); + + rp = buf; + ap = (u8_t *)&s_addr; + for (n = 0; n < 4; n++) { + i = 0; + do { + rem = *ap % (u8_t)10; + *ap /= (u8_t)10; + inv[i++] = (char)('0' + rem); + } while (*ap); + while (i--) { + if (len++ >= buflen) { + return NULL; + } + *rp++ = inv[i]; + } + if (len++ >= buflen) { + return NULL; + } + *rp++ = '.'; + ap++; + } + *--rp = 0; + return buf; +} + +#endif /* LWIP_IPV4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_frag.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_frag.c new file mode 100644 index 0000000000..57fb44cbb3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv4/ip4_frag.c @@ -0,0 +1,831 @@ +/** + * @file + * This is the IPv4 packet segmentation and reassembly implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * Simon Goldschmidt + * original reassembly code by Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/ip4_frag.h" +#include "lwip/def.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/stats.h" +#include "lwip/icmp.h" + +#include + +#if IP_REASSEMBLY +/** + * The IP reassembly code currently has the following limitations: + * - IP header options are not supported + * - fragments must not overlap (e.g. due to different routes), + * currently, overlapping or duplicate fragments are thrown away + * if IP_REASS_CHECK_OVERLAP=1 (the default)! + * + * @todo: work with IP header options + */ + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IP header, since it replaces + * the IP header in memory in incoming fragments (after copying it) to keep + * track of the various fragments. (-> If the IP header doesn't need packing, + * this struct doesn't need packing, too.) + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ + (ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ + ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ + IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 + +/* global variables */ +static struct ip_reassdata *reassdatagrams; +static u16_t ip_reass_pbufcount; + +/* function prototypes */ +static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); +static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). + */ +void +ip_reass_tmr(void) +{ + struct ip_reassdata *r, *prev = NULL; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); + prev = r; + r = r->next; + } else { + /* reassembly timed out */ + struct ip_reassdata *tmp; + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip_reass_free_complete_datagram(tmp, prev); + } + } +} + +/** + * Free a datagram (struct ip_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip_reass_pbufcount), + * SNMP counters and sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + * @param prev the previous datagram in the linked list + * @return the number of pbufs freed + */ +static int +ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + u16_t pbufs_freed = 0; + u16_t clen; + struct pbuf *p; + struct ip_reass_helper *iprh; + + LWIP_ASSERT("prev != ipr", prev != ipr); + if (prev != NULL) { + LWIP_ASSERT("prev->next == ipr", prev->next == ipr); + } + + MIB2_STATS_INC(mib2.ipreasmfails); +#if LWIP_ICMP + iprh = (struct ip_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, copy the original header into it. */ + SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); + icmp_time_exceeded(p, ICMP_TE_FRAG); + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(p); + } +#endif /* LWIP_ICMP */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(pcur); + } + /* Then, unchain the struct ip_reassdata from the list and free it. */ + ip_reass_dequeue_datagram(ipr, prev); + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); + ip_reass_pbufcount -= pbufs_freed; + + return pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram 'fraghdr' belongs to is not freed! + * + * @param fraghdr IP header of the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + * @return the number of pbufs freed + */ +static int +ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) +{ + /* @todo Can't we simply remove the last datagram in the + * linked list behind reassdatagrams? + */ + struct ip_reassdata *r, *oldest, *prev, *oldest_prev; + int pbufs_freed = 0, pbufs_freed_current; + int other_datagrams; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the datagram that 'fraghdr' belongs to! */ + do { + oldest = NULL; + prev = NULL; + oldest_prev = NULL; + other_datagrams = 0; + r = reassdatagrams; + while (r != NULL) { + if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { + /* Not the same datagram as fraghdr */ + other_datagrams++; + if (oldest == NULL) { + oldest = r; + oldest_prev = prev; + } else if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + oldest_prev = prev; + } + } + if (r->next != NULL) { + prev = r; + } + r = r->next; + } + if (oldest != NULL) { + pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev); + pbufs_freed += pbufs_freed_current; + } + } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); + return pbufs_freed; +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Enqueues a new fragment into the fragment queue + * @param fraghdr points to the new fragments IP hdr + * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) + * @return A pointer to the queue location into which the fragment was enqueued + */ +static struct ip_reassdata* +ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) +{ + struct ip_reassdata* ipr; +#if ! IP_REASS_FREE_OLDEST + LWIP_UNUSED_ARG(clen); +#endif + + /* No matching previous fragment found, allocate a new reassdata struct */ + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); + } + if (ipr == NULL) +#endif /* IP_REASS_FREE_OLDEST */ + { + IPFRAG_STATS_INC(ip_frag.memerr); + LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); + return NULL; + } + } + memset(ipr, 0, sizeof(struct ip_reassdata)); + ipr->timer = IP_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + /* copy the ip header for later tests and input */ + /* @todo: no ip options supported? */ + SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); + return ipr; +} + +/** + * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. + * @param ipr points to the queue entry to dequeue + */ +static void +ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ + /* dequeue the reass struct */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", prev != NULL); + prev->next = ipr->next; + } + + /* now we can free the ip_reassdata struct */ + memp_free(MEMP_REASSDATA, ipr); +} + +/** + * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list + * will grow over time as new pbufs are rx. + * Also checks that the datagram passes basic continuity checks (if the last + * fragment was received at least once). + * @param ipr points to the reassembly state + * @param new_p points to the pbuf for the current fragment + * @return 0 if invalid, >0 otherwise + */ +static int +ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) +{ + struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct pbuf *q; + u16_t offset, len; + struct ip_hdr *fraghdr; + int valid = 1; + + /* Extract length and fragment offset from current fragment */ + fraghdr = (struct ip_hdr*)new_p->payload; + len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + + /* overwrite the fragment's ip header from the pbuf with our helper struct, + * and setup the embedded helper structure. */ + /* make sure the struct ip_reass_helper fits into the IP header */ + LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", + sizeof(struct ip_reass_helper) <= IP_HLEN); + iprh = (struct ip_reass_helper*)new_p->payload; + iprh->next_pbuf = NULL; + iprh->start = offset; + iprh->end = offset + len; + + /* Iterate through until we either get to the end of the list (append), + * or we find one with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip_reass_helper*)q->payload; + if (iprh->start < iprh_tmp->start) { + /* the new pbuf should be inserted before this */ + iprh->next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ +#if IP_REASS_CHECK_OVERLAP + if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { + /* fragment overlaps with previous or following, throw away */ + goto freepbuf; + } +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + } else { + /* fragment with the lowest offset */ + ipr->p = new_p; + } + break; + } else if (iprh->start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + goto freepbuf; +#if IP_REASS_CHECK_OVERLAP + } else if (iprh->start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + goto freepbuf; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no holes. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = new_p; + if (iprh_prev->end != iprh->start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = new_p; + } + } + + /* At this point, the validation part begins: */ + /* If we already received the last fragment */ + if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { + /* and had no holes so far */ + if (valid) { + /* then check if the rest of the fragments is here */ + /* Check if the queue starts with the first datagram */ + if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) { + valid = 0; + } else { + /* and check that there are no holes after this datagram */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while (q != NULL) { + iprh = (struct ip_reass_helper*)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + /* if still valid, all fragments are received + * (because to the MF==0 already arrived */ + if (valid) { + LWIP_ASSERT("sanity check", ipr->p != NULL); + LWIP_ASSERT("sanity check", + ((struct ip_reass_helper*)ipr->p->payload) != iprh); + LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", + iprh->next_pbuf == NULL); + LWIP_ASSERT("validate_datagram:datagram end!=datagram len", + iprh->end == ipr->datagram_len); + } + } + } + /* If valid is 0 here, there are some fragments missing in the middle + * (since MF == 0 has already arrived). Such datagrams simply time out if + * no more fragments are received... */ + return valid; + } + /* If we come here, not all fragments were received, yet! */ + return 0; /* not yet valid! */ +#if IP_REASS_CHECK_OVERLAP +freepbuf: + ip_reass_pbufcount -= pbuf_clen(new_p); + pbuf_free(new_p); + return 0; +#endif /* IP_REASS_CHECK_OVERLAP */ +} + +/** + * Reassembles incoming IP fragments into an IP datagram. + * + * @param p points to a pbuf chain of the fragment + * @return NULL if reassembly is incomplete, ? otherwise + */ +struct pbuf * +ip4_reass(struct pbuf *p) +{ + struct pbuf *r; + struct ip_hdr *fraghdr; + struct ip_reassdata *ipr; + struct ip_reass_helper *iprh; + u16_t offset, len, clen; + + IPFRAG_STATS_INC(ip_frag.recv); + MIB2_STATS_INC(mib2.ipreasmreqds); + + fraghdr = (struct ip_hdr*)p->payload; + + if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n")); + IPFRAG_STATS_INC(ip_frag.err); + goto nullreturn; + } + + offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + + /* Check if we are allowed to enqueue more datagrams. */ + clen = pbuf_clen(p); + if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || + ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) +#endif /* IP_REASS_FREE_OLDEST */ + { + /* No datagram could be freed and still too many pbufs enqueued */ + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", + ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); + IPFRAG_STATS_INC(ip_frag.memerr); + /* @todo: send ICMP time exceeded here? */ + /* drop this pbuf */ + goto nullreturn; + } + } + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n", + lwip_ntohs(IPH_ID(fraghdr)))); + IPFRAG_STATS_INC(ip_frag.cachehit); + break; + } + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); + /* Bail if unable to enqueue */ + if (ipr == NULL) { + goto nullreturn; + } + } else { + if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && + ((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { + /* ipr->iphdr is not the header from the first fragment, but fraghdr is + * -> copy fraghdr into ipr->iphdr since we want to have the header + * of the first fragment (for ICMP time exceeded and later, for copying + * all options, if supported)*/ + SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); + } + } + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time */ + ip_reass_pbufcount += clen; + + /* At this point, we have either created a new entry or pointing + * to an existing one */ + + /* check for 'no more fragments', and update queue entry*/ + if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { + ipr->flags |= IP_REASS_FLAG_LASTFRAG; + ipr->datagram_len = offset + len; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip4_reass: last fragment seen, total len %"S16_F"\n", + ipr->datagram_len)); + } + /* find the right place to insert this pbuf */ + /* @todo: trim pbufs if fragments are overlapping */ + if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { + struct ip_reassdata *ipr_prev; + /* the totally last fragment (flag more fragments = 0) was received at least + * once AND all fragments are received */ + ipr->datagram_len += IP_HLEN; + + /* save the second pbuf before copying the header over the pointer */ + r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; + + /* copy the original ip header back to the first pbuf */ + fraghdr = (struct ip_hdr*)(ipr->p->payload); + SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); + IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len)); + IPH_OFFSET_SET(fraghdr, 0); + IPH_CHKSUM_SET(fraghdr, 0); + /* @todo: do we need to set/calculate the correct checksum? */ +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + } +#endif /* CHECKSUM_GEN_IP */ + + p = ipr->p; + + /* chain together the pbufs contained within the reass_data list. */ + while (r != NULL) { + iprh = (struct ip_reass_helper*)r->payload; + + /* hide the ip header for every succeeding fragment */ + pbuf_header(r, -IP_HLEN); + pbuf_cat(p, r); + r = iprh->next_pbuf; + } + + /* find the previous entry in the linked list */ + if (ipr == reassdatagrams) { + ipr_prev = NULL; + } else { + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } + + /* release the sources allocate for the fragment queue entry */ + ip_reass_dequeue_datagram(ipr, ipr_prev); + + /* and adjust the number of pbufs currently queued for reassembly. */ + ip_reass_pbufcount -= pbuf_clen(p); + + MIB2_STATS_INC(mib2.ipreasmoks); + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); + return NULL; + +nullreturn: + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n")); + IPFRAG_STATS_INC(ip_frag.drop); + pbuf_free(p); + return NULL; +} +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ipfrag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p. + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) +{ + struct pbuf *rambuf; +#if !LWIP_NETIF_TX_SINGLE_PBUF + struct pbuf *newpbuf; + u16_t newpbuflen = 0; + u16_t left_to_copy; +#endif + struct ip_hdr *original_iphdr; + struct ip_hdr *iphdr; + const u16_t nfb = (netif->mtu - IP_HLEN) / 8; + u16_t left, fragsize; + u16_t ofo; + int last; + u16_t poff = IP_HLEN; + u16_t tmp; + + original_iphdr = (struct ip_hdr *)p->payload; + iphdr = original_iphdr; + LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL); + + /* Save original offset */ + tmp = lwip_ntohs(IPH_OFFSET(iphdr)); + ofo = tmp & IP_OFFMASK; + LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL); + + left = p->tot_len - IP_HLEN; + + while (left) { + /* Fill this fragment */ + fragsize = LWIP_MIN(left, nfb * 8); + +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM); + if (rambuf == NULL) { + goto memerr; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff); + /* make room for the IP header */ + if (pbuf_header(rambuf, IP_HLEN)) { + pbuf_free(rambuf); + goto memerr; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = (struct ip_hdr*)rambuf->payload; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link and IP header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); + if (rambuf == NULL) { + goto memerr; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (p->len >= (IP_HLEN))); + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = (struct ip_hdr *)rambuf->payload; + + left_to_copy = fragsize; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + u16_t plen = p->len - poff; + newpbuflen = LWIP_MIN(left_to_copy, plen); + /* Is this pbuf already empty? */ + if (!newpbuflen) { + poff = 0; + p = p->next; + continue; + } + pcr = ip_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + goto memerr; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, + (u8_t*)p->payload + poff, newpbuflen); + if (newpbuf == NULL) { + ip_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + goto memerr; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) { + poff = 0; + p = p->next; + } + } + poff += newpbuflen; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + /* Correct header */ + last = (left <= netif->mtu - IP_HLEN); + + /* Set new offset and MF flag */ + tmp = (IP_OFFMASK & (ofo)); + if (!last) { + tmp = tmp | IP_MF; + } + IPH_OFFSET_SET(iphdr, lwip_htons(tmp)); + IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN)); + IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + } +#endif /* CHECKSUM_GEN_IP */ + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + netif->output(netif, rambuf, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left -= fragsize; + ofo += nfb; + } + MIB2_STATS_INC(mib2.ipfragoks); + return ERR_OK; +memerr: + MIB2_STATS_INC(mib2.ipfragfails); + return ERR_MEM; +} +#endif /* IP_FRAG */ + +#endif /* LWIP_IPV4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/dhcp6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/dhcp6.c new file mode 100644 index 0000000000..f27a725e3a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/dhcp6.c @@ -0,0 +1,50 @@ +/** + * @file + * + * DHCPv6. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + + +#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ethip6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ethip6.c new file mode 100644 index 0000000000..8f9a91b5f7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ethip6.c @@ -0,0 +1,118 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET + +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/prot/ethernet.h" +#include "netif/ethernet.h" + +#include + +/** + * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. + * + * For IPv6 multicast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, ask the ND6 module what to do. It will either let us + * send the the packet right away, or queue the packet for later itself, unless + * an error occurs. + * + * @todo anycast addresses + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return + * - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue. + */ +err_t +ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) +{ + struct eth_addr dest; + const u8_t *hwaddr; + err_t result; + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + /* Hash IP multicast address to MAC address.*/ + dest.addr[0] = 0x33; + dest.addr[1] = 0x33; + dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0]; + dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1]; + dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2]; + dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3]; + + /* Send out. */ + return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); + } + + /* We have a unicast destination IP address */ + /* @todo anycast? */ + + /* Ask ND6 what to do with the packet. */ + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); + if (result != ERR_OK) { + return result; + } + + /* If no hardware address is returned, nd6 has queued the packet for later. */ + if (hwaddr == NULL) { + return ERR_OK; + } + + /* Send out the packet using the returned hardware address. */ + SMEMCPY(dest.addr, hwaddr, 6); + return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); +} + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/icmp6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/icmp6.c new file mode 100644 index 0000000000..323b69a2ab --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/icmp6.c @@ -0,0 +1,350 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp6.h" +#include "lwip/prot/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" + +#include + +#ifndef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE 8 +#endif +#if LWIP_ICMP6_DATASIZE == 0 +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/* Forward declarations */ +static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); + + +/** + * Process an input ICMPv6 message. Called by ip6_input. + * + * Will generate a reply for echo requests. Other messages are forwarded + * to nd6_input, or mld6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +icmp6_input(struct pbuf *p, struct netif *inp) +{ + struct icmp6_hdr *icmp6hdr; + struct pbuf *r; + const ip6_addr_t *reply_src; + + ICMP6_STATS_INC(icmp6.recv); + + /* Check that ICMPv6 header fits in payload */ + if (p->len < sizeof(struct icmp6_hdr)) { + /* drop short packets */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.lenerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + +#if CHECKSUM_CHECK_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { + if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), + ip6_current_dest_addr()) != 0) { + /* Checksum failed */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.chkerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } + } +#endif /* CHECKSUM_CHECK_ICMP6 */ + + switch (icmp6hdr->type) { + case ICMP6_TYPE_NA: /* Neighbor advertisement */ + case ICMP6_TYPE_NS: /* Neighbor solicitation */ + case ICMP6_TYPE_RA: /* Router advertisement */ + case ICMP6_TYPE_RD: /* Redirect */ + case ICMP6_TYPE_PTB: /* Packet too big */ + nd6_input(p, inp); + return; + break; + case ICMP6_TYPE_RS: +#if LWIP_IPV6_FORWARD + /* @todo implement router functionality */ +#endif + break; +#if LWIP_IPV6_MLD + case ICMP6_TYPE_MLQ: + case ICMP6_TYPE_MLR: + case ICMP6_TYPE_MLD: + mld6_input(p, inp); + return; + break; +#endif + case ICMP6_TYPE_EREQ: +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* drop */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.drop); + return; + } +#endif /* LWIP_MULTICAST_PING */ + + /* Allocate reply. */ + r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); + if (r == NULL) { + /* drop */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.memerr); + return; + } + + /* Copy echo request. */ + if (pbuf_copy(r, p) != ERR_OK) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.err); + return; + } + + /* Determine reply source IPv6 address. */ +#if LWIP_MULTICAST_PING + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); + if (reply_src == NULL) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + } + else +#endif /* LWIP_MULTICAST_PING */ + { + reply_src = ip6_current_dest_addr(); + } + + /* Set fields in reply. */ + ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send reply. */ + ICMP6_STATS_INC(icmp6.xmit); + ip6_output_if(r, reply_src, ip6_current_src_addr(), + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); + pbuf_free(r); + + break; + default: + ICMP6_STATS_INC(icmp6.proterr); + ICMP6_STATS_INC(icmp6.drop); + break; + } + + pbuf_free(p); +} + + +/** + * Send an icmpv6 'destination unreachable' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the unreachable type + */ +void +icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) +{ + icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); +} + +/** + * Send an icmpv6 'packet too big' packet. + * + * @param p the input packet for which the 'packet too big' should be sent, + * p->payload pointing to the IPv6 header + * @param mtu the maximum mtu that we can accept + */ +void +icmp6_packet_too_big(struct pbuf *p, u32_t mtu) +{ + icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); +} + +/** + * Send an icmpv6 'time exceeded' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the time exceeded type + */ +void +icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) +{ + icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); +} + +/** + * Send an icmpv6 'parameter problem' packet. + * + * @param p the input packet for which the 'param problem' should be sent, + * p->payload pointing to the IP header + * @param c ICMPv6 code for the param problem type + * @param pointer the pointer to the byte where the parameter is found + */ +void +icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) +{ + icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); +} + +/** + * Send an ICMPv6 packet in response to an incoming packet. + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + * @param type Type of the ICMPv6 header + */ +static void +icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) +{ + struct pbuf *q; + struct icmp6_hdr *icmp6hdr; + const ip6_addr_t *reply_src; + ip6_addr_t *reply_dest; + ip6_addr_t reply_src_local, reply_dest_local; + struct ip6_hdr *ip6hdr; + struct netif *netif; + + /* ICMPv6 header + IPv6 header + data */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, + PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); + ICMP6_STATS_INC(icmp6.memerr); + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp 6message", + (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); + + icmp6hdr = (struct icmp6_hdr *)q->payload; + icmp6hdr->type = type; + icmp6hdr->code = code; + icmp6hdr->data = data; + + /* copy fields from original packet */ + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, + IP6_HLEN + LWIP_ICMP6_DATASIZE); + + /* Get the destination address and netif for this ICMP message. */ + if ((ip_current_netif() == NULL) || + ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { + /* Special case, as ip6_current_xxx is either NULL, or points + * to a different packet than the one that expired. + * We must use the addresses that are stored in the expired packet. */ + ip6hdr = (struct ip6_hdr *)p->payload; + /* copy from packed address to aligned address */ + ip6_addr_copy(reply_dest_local, ip6hdr->src); + ip6_addr_copy(reply_src_local, ip6hdr->dest); + reply_dest = &reply_dest_local; + reply_src = &reply_src_local; + netif = ip6_route(reply_src, reply_dest); + if (netif == NULL) { + /* drop */ + pbuf_free(q); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + } + else { + netif = ip_current_netif(); + reply_dest = ip6_current_src_addr(); + + /* Select an address to use as source. */ + reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); + if (reply_src == NULL) { + /* drop */ + pbuf_free(q); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + } + + /* calculate checksum */ + icmp6hdr->chksum = 0; +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, + reply_src, reply_dest); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + ICMP6_STATS_INC(icmp6.xmit); + ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(q); +} + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/inet6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/inet6.c new file mode 100644 index 0000000000..d9a992c22a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/inet6.c @@ -0,0 +1,53 @@ +/** + * @file + * + * INET v6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/inet.h" + +/** This variable is initialized by the system to contain the wildcard IPv6 address. + */ +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6.c new file mode 100644 index 0000000000..f14e33424f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6.c @@ -0,0 +1,1122 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_frag.h" +#include "lwip/icmp6.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/dhcp6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" +#include "lwip/debug.h" +#include "lwip/stats.h" + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +/** + * Finds the appropriate network interface for a given IPv6 address. It tries to select + * a netif following a sequence of heuristics: + * 1) if there is only 1 netif, return it + * 2) if the destination is a link-local address, try to match the src address to a netif. + * this is a tricky case because with multiple netifs, link-local addresses only have + * meaning within a particular subnet/link. + * 3) tries to match the destination subnet to a configured address + * 4) tries to find a router + * 5) tries to match the source address to the netif + * 6) returns the default netif, if configured + * + * @param src the source IPv6 address, if known + * @param dest the destination IPv6 address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) +{ + struct netif *netif; + s8_t i; + + /* If single netif configuration, fast return. */ + if ((netif_list != NULL) && (netif_list->next == NULL)) { + if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list)) { + return NULL; + } + return netif_list; + } + + /* Special processing for link-local addresses. */ + if (ip6_addr_islinklocal(dest)) { + if (ip6_addr_isany(src)) { + /* Use default netif, if Up. */ + if (netif_default == NULL || !netif_is_up(netif_default) || + !netif_is_link_up(netif_default)) { + return NULL; + } + return netif_default; + } + + /* Try to find the netif for the source address, checking that link is up. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + + /* netif not found, use default netif, if up */ + if (netif_default == NULL || !netif_is_up(netif_default) || + !netif_is_link_up(netif_default)) { + return NULL; + } + return netif_default; + } + + /* we come here for non-link-local addresses */ +#ifdef LWIP_HOOK_IP6_ROUTE + netif = LWIP_HOOK_IP6_ROUTE(src, dest); + if (netif != NULL) { + return netif; + } +#endif + + /* See if the destination subnet matches a configured address. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + + /* Get the netif for a suitable router. */ + netif = nd6_find_route(dest); + if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) { + return netif; + } + + /* try with the netif that matches the source address. */ + if (!ip6_addr_isany(src)) { + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (!netif_is_up(netif) || !netif_is_link_up(netif)) { + continue; + } + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { + return netif; + } + } + } + } + +#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF + /* loopif is disabled, loopback traffic is passed through any netif */ + if (ip6_addr_isloopback(dest)) { + /* don't check for link on loopback traffic */ + if (netif_default != NULL && netif_is_up(netif_default)) { + return netif_default; + } + /* default netif is not up, just use any netif for loopback traffic */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (netif_is_up(netif)) { + return netif; + } + } + return NULL; + } +#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */ + + /* no matching netif found, use default netif, if up */ + if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default)) { + return NULL; + } + return netif_default; +} + +/** + * @ingroup ip6 + * Select the best IPv6 source address for a given destination + * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior + * is assumed. + * + * @param netif the netif on which to send a packet + * @param dest the destination we are trying to reach + * @return the most suitable source address to use, or NULL if no suitable + * source address is found + */ +const ip_addr_t * +ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) +{ + const ip_addr_t *src = NULL; + u8_t i; + + /* If dest is link-local, choose a link-local source. */ + if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_islinklocal(netif_ip6_addr(netif, i))) { + return netif_ip_addr6(netif, i); + } + } + } + + /* Choose a site-local with matching prefix. */ + if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_issitelocal(netif_ip6_addr(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { + return netif_ip_addr6(netif, i); + } + } + } + + /* Choose a unique-local with matching prefix. */ + if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { + return netif_ip_addr6(netif, i); + } + } + } + + /* Choose a global with best matching prefix. */ + if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_isglobal(netif_ip6_addr(netif, i))) { + if (src == NULL) { + src = netif_ip_addr6(netif, i); + } + else { + /* Replace src only if we find a prefix match. */ + /* @todo find longest matching prefix. */ + if ((!(ip6_addr_netcmp(ip_2_ip6(src), dest))) && + ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) { + src = netif_ip_addr6(netif, i); + } + } + } + } + if (src != NULL) { + return src; + } + } + + /* Last resort: see if arbitrary prefix matches. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { + return netif_ip_addr6(netif, i); + } + } + + return NULL; +} + +#if LWIP_IPV6_FORWARD +/** + * Forwards an IPv6 packet. It finds an appropriate route for the + * packet, decrements the HL value of the packet, and outputs + * the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IPv6 header of the input packet + * @param inp the netif on which this packet was received + */ +static void +ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) +{ + struct netif *netif; + + /* do not forward link-local or loopback addresses */ + if (ip6_addr_islinklocal(ip6_current_dest_addr()) || + ip6_addr_isloopback(ip6_current_dest_addr())) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + + /* Find network interface where to forward this IP packet to. */ + netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr()); + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(ip6_current_dest_addr()), + IP6_ADDR_BLOCK2(ip6_current_dest_addr()), + IP6_ADDR_BLOCK3(ip6_current_dest_addr()), + IP6_ADDR_BLOCK4(ip6_current_dest_addr()), + IP6_ADDR_BLOCK5(ip6_current_dest_addr()), + IP6_ADDR_BLOCK6(ip6_current_dest_addr()), + IP6_ADDR_BLOCK7(ip6_current_dest_addr()), + IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); + IP6_STATS_INC(ip6.rterr); + IP6_STATS_INC(ip6.drop); + return; + } + + /* decrement HL */ + IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); + /* send ICMP6 if HL == 0 */ + if (IP6H_HOPLIM(iphdr) == 0) { +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_time_exceeded(p, ICMP6_TE_HL); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.drop); + return; + } + + if (netif->mtu && (p->tot_len > netif->mtu)) { +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_packet_too_big(p, netif->mtu); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.drop); + return; + } + + LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(ip6_current_dest_addr()), + IP6_ADDR_BLOCK2(ip6_current_dest_addr()), + IP6_ADDR_BLOCK3(ip6_current_dest_addr()), + IP6_ADDR_BLOCK4(ip6_current_dest_addr()), + IP6_ADDR_BLOCK5(ip6_current_dest_addr()), + IP6_ADDR_BLOCK6(ip6_current_dest_addr()), + IP6_ADDR_BLOCK7(ip6_current_dest_addr()), + IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); + + /* transmit pbuf on chosen interface */ + netif->output_ip6(netif, p, ip6_current_dest_addr()); + IP6_STATS_INC(ip6.fw); + IP6_STATS_INC(ip6.xmit); + return; +} +#endif /* LWIP_IPV6_FORWARD */ + +/** + * This function is called by the network interface device driver when + * an IPv6 packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip6_forward). + * + * Finally, the packet is sent to the upper layer protocol input function. + * + * @param p the received IPv6 packet (p->payload points to IPv6 header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + * processed, but currently always returns ERR_OK) + */ +err_t +ip6_input(struct pbuf *p, struct netif *inp) +{ + struct ip6_hdr *ip6hdr; + struct netif *netif; + u8_t nexth; + u16_t hlen; /* the current header length */ + u8_t i; +#if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ + @todo + int check_ip_src=1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + + IP6_STATS_INC(ip6.recv); + + /* identify the IP header */ + ip6hdr = (struct ip6_hdr *)p->payload; + if (IP6H_V(ip6hdr) != 6) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", + IP6H_V(ip6hdr))); + pbuf_free(p); + IP6_STATS_INC(ip6.err); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + +#ifdef LWIP_HOOK_IP6_INPUT + if (LWIP_HOOK_IP6_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + + /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ + if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) { + if (IP6_HLEN > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", + (u16_t)IP6_HLEN, p->len)); + } + if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", + (u16_t)(IP6H_PLEN(ip6hdr) + IP6_HLEN), p->tot_len)); + } + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + + /* Trim pbuf. This should have been done at the netif layer, + * but we'll do it anyway just to be sure that its done. */ + pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr)); + + /* copy IP addresses to aligned ip6_addr_t */ + ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); + ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); + + /* Don't accept virtual IPv4 mapped IPv6 addresses. + * Don't accept multicast source addresses. */ + if (ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_dest)) || + ip6_addr_isipv4mappedipv6(ip_2_ip6(&ip_data.current_iphdr_src)) || + ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_src))) { + IP6_STATS_INC(ip6.err); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + + /* current header pointer. */ + ip_data.current_ip6_header = ip6hdr; + + /* In netif, used in case we need to send ICMPv6 packets back. */ + ip_data.current_netif = inp; + ip_data.current_input_netif = inp; + + /* match packet against an interface, i.e. is this packet for us? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* Always joined to multicast if-local and link-local all-nodes group. */ + if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || + ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { + netif = inp; + } +#if LWIP_IPV6_MLD + else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { + netif = inp; + } +#else /* LWIP_IPV6_MLD */ + else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { + /* Filter solicited node packets when MLD is not enabled + * (for Neighbor discovery). */ + netif = NULL; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + netif = inp; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + break; + } + } + } +#endif /* LWIP_IPV6_MLD */ + else { + netif = NULL; + } + } else { + /* start trying with inp. if that's not acceptable, start walking the + list of configured netifs. + 'first' is used as a boolean to mark whether we started walking the list */ + int first = 1; + netif = inp; + do { + /* interface is up? */ + if (netif_is_up(netif)) { + /* unicast to this interface address? address configured? */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) { + /* exit outer loop */ + goto netif_found; + } + } + } + if (first) { + if (ip6_addr_islinklocal(ip6_current_dest_addr()) +#if !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF + || ip6_addr_isloopback(ip6_current_dest_addr()) +#endif /* !LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF */ + ) { + /* Do not match link-local addresses to other netifs. The loopback + * address is to be considered link-local and packets to it should be + * dropped on other interfaces, as per RFC 4291 Sec. 2.5.3. This + * requirement cannot be implemented in the case that loopback + * traffic is sent across a non-loopback interface, however. + */ + netif = NULL; + break; + } + first = 0; + netif = netif_list; + } else { + netif = netif->next; + } + if (netif == inp) { + netif = netif->next; + } + } while (netif != NULL); +netif_found: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", + netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); + } + + /* "::" packet source address? (used in duplicate address detection) */ + if (ip6_addr_isany(ip6_current_src_addr()) && + (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { + /* packet source is not valid */ + /* free (drop) packet pbufs */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + /* packet not for us? */ + if (netif == NULL) { + /* packet not for us, route or discard */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); +#if LWIP_IPV6_FORWARD + /* non-multicast packet? */ + if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* try to forward IP packet on (other) interfaces */ + ip6_forward(p, ip6hdr, inp); + } +#endif /* LWIP_IPV6_FORWARD */ + pbuf_free(p); + goto ip6_input_cleanup; + } + + /* current netif pointer. */ + ip_data.current_netif = netif; + + /* Save next header type. */ + nexth = IP6H_NEXTH(ip6hdr); + + /* Init header length. */ + hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; + + /* Move to payload. */ + pbuf_header(p, -IP6_HLEN); + + /* Process known option extension headers, if present. */ + while (nexth != IP6_NEXTH_NONE) + { + switch (nexth) { + case IP6_NEXTH_HOPBYHOP: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload + 1)); + ip_data.current_ip_header_tot_len += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + pbuf_header(p, -(s16_t)hlen); + break; + case IP6_NEXTH_DESTOPTS: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload + 1)); + ip_data.current_ip_header_tot_len += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + pbuf_header(p, -(s16_t)hlen); + break; + case IP6_NEXTH_ROUTING: + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload + 1)); + ip_data.current_ip_header_tot_len += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; + } + + pbuf_header(p, -(s16_t)hlen); + break; + + case IP6_NEXTH_FRAGMENT: + { + struct ip6_frag_hdr *frag_hdr; + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); + + frag_hdr = (struct ip6_frag_hdr *)p->payload; + + /* Get next header type. */ + nexth = frag_hdr->_nexth; + + /* Fragment Header length. */ + hlen = 8; + ip_data.current_ip_header_tot_len += hlen; + + /* Make sure this header fits in current pbuf. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", + hlen, p->len)); + /* free (drop) packet pbufs */ + pbuf_free(p); + IP6_FRAG_STATS_INC(ip6_frag.lenerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto ip6_input_cleanup; + } + + /* Offset == 0 and more_fragments == 0? */ + if ((frag_hdr->_fragment_offset & + PP_HTONS(IP6_FRAG_OFFSET_MASK | IP6_FRAG_MORE_FLAG)) == 0) { + /* This is a 1-fragment packet, usually a packet that we have + * already reassembled. Skip this header anc continue. */ + pbuf_header(p, -(s16_t)hlen); + } else { +#if LWIP_IPV6_REASS + + /* reassemble the packet */ + p = ip6_reass(p); + /* packet not fully reassembled yet? */ + if (p == NULL) { + goto ip6_input_cleanup; + } + + /* Returned p point to IPv6 header. + * Update all our variables and pointers and continue. */ + ip6hdr = (struct ip6_hdr *)p->payload; + nexth = IP6H_NEXTH(ip6hdr); + hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; + pbuf_header(p, -IP6_HLEN); + +#else /* LWIP_IPV6_REASS */ + /* free (drop) packet pbufs */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); + pbuf_free(p); + IP6_STATS_INC(ip6.opterr); + IP6_STATS_INC(ip6.drop); + goto ip6_input_cleanup; +#endif /* LWIP_IPV6_REASS */ + } + break; + } + default: + goto options_done; + break; + } + } +options_done: + + /* p points to IPv6 header again. */ + pbuf_header_force(p, (s16_t)ip_data.current_ip_header_tot_len); + + /* send to upper layers */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); + ip6_debug_print(p); + LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + +#if LWIP_RAW + /* raw input did not eat the packet? */ + if (raw_input(p, inp) == 0) +#endif /* LWIP_RAW */ + { + switch (nexth) { + case IP6_NEXTH_NONE: + pbuf_free(p); + break; +#if LWIP_UDP + case IP6_NEXTH_UDP: +#if LWIP_UDPLITE + case IP6_NEXTH_UDPLITE: +#endif /* LWIP_UDPLITE */ + /* Point to payload. */ + pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP6_NEXTH_TCP: + /* Point to payload. */ + pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP6 + case IP6_NEXTH_ICMP6: + /* Point to payload. */ + pbuf_header(p, -(s16_t)ip_data.current_ip_header_tot_len); + icmp6_input(p, inp); + break; +#endif /* LWIP_ICMP */ + default: +#if LWIP_ICMP6 + /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ + if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && + (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { + icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen); + } +#endif /* LWIP_ICMP */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", (u16_t)IP6H_NEXTH(ip6hdr))); + pbuf_free(p); + IP6_STATS_INC(ip6.proterr); + IP6_STATS_INC(ip6.drop); + break; + } + } + +ip6_input_cleanup: + ip_data.current_netif = NULL; + ip_data.current_input_netif = NULL; + ip_data.current_ip6_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip6_addr_set_zero(ip6_current_src_addr()); + ip6_addr_set_zero(ip6_current_dest_addr()); + + return ERR_OK; +} + + +/** + * Sends an IPv6 packet on a network interface. This function constructs + * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is + * used as source (usually during network startup). If the source IPv6 address it + * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network + * interface is filled in as source address. If the destination IPv6 address is + * LWIP_IP_HDRINCL, p is assumed to already include an IPv6 header and + * p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IPv6/LINK headers + * returns errors returned by netif->output + */ +err_t +ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) +{ + const ip6_addr_t *src_used = src; + if (dest != LWIP_IP_HDRINCL) { + if (src != NULL && ip6_addr_isany(src)) { + src_used = ip_2_ip6(ip6_select_source_address(netif, dest)); + if ((src_used == NULL) || ip6_addr_isany(src_used)) { + /* No appropriate source address was found for this packet. */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + } + } + return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif); +} + +/** + * Same as ip6_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) +{ + struct ip6_hdr *ip6hdr; + ip6_addr_t dest_addr; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + /* Should the IPv6 header be generated or is it already included in p? */ + if (dest != LWIP_IP_HDRINCL) { + /* generate IPv6 header */ + if (pbuf_header(p, IP6_HLEN)) { + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + ip6hdr = (struct ip6_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", + (p->len >= sizeof(struct ip6_hdr))); + + IP6H_HOPLIM_SET(ip6hdr, hl); + IP6H_NEXTH_SET(ip6hdr, nexth); + + /* dest cannot be NULL here */ + ip6_addr_copy(ip6hdr->dest, *dest); + + IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); + IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); + + if (src == NULL) { + src = IP6_ADDR_ANY6; + } + /* src cannot be NULL here */ + ip6_addr_copy(ip6hdr->src, *src); + + } else { + /* IP header already included in p */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy(dest_addr, ip6hdr->dest); + dest = &dest_addr; + } + + IP6_STATS_INC(ip6.xmit); + + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); + ip6_debug_print(p); + +#if ENABLE_LOOPBACK + { + int i; +#if !LWIP_HAVE_LOOPIF + if (ip6_addr_isloopback(dest)) { + return netif_loop_output(netif, p); + } +#endif /* !LWIP_HAVE_LOOPIF */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); + return netif_loop_output(netif, p); + } + } + } +#endif /* ENABLE_LOOPBACK */ +#if LWIP_IPV6_FRAG + /* don't fragment if interface has mtu set to 0 [loopif] */ + if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { + return ip6_frag(p, netif, dest); + } +#endif /* LWIP_IPV6_FRAG */ + + LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); + return netif->output_ip6(netif, p, dest); +} + +/** + * Simple interface to ip6_output_if. It finds the outgoing network + * interface and calls upon ip6_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth) +{ + struct netif *netif; + struct ip6_hdr *ip6hdr; + ip6_addr_t src_addr, dest_addr; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if (dest != LWIP_IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy(src_addr, ip6hdr->src); + ip6_addr_copy(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + return ip6_output_if(p, src, dest, hl, tc, nexth, netif); +} + + +#if LWIP_NETIF_HWADDRHINT +/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + * before calling ip6_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == LWIP_IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param addr_hint address hint pointer set to netif->addr_hint before + * calling ip_output_if() + * + * @return ERR_RTE if no route is found + * see ip_output_if() for more return values + */ +err_t +ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint) +{ + struct netif *netif; + struct ip6_hdr *ip6hdr; + ip6_addr_t src_addr, dest_addr; + err_t err; + + LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); + + if (dest != LWIP_IP_HDRINCL) { + netif = ip6_route(src, dest); + } else { + /* IP header included in p, read addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip6_addr_copy(src_addr, ip6hdr->src); + ip6_addr_copy(dest_addr, ip6hdr->dest); + netif = ip6_route(&src_addr, &dest_addr); + } + + if (netif == NULL) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", + IP6_ADDR_BLOCK1(dest), + IP6_ADDR_BLOCK2(dest), + IP6_ADDR_BLOCK3(dest), + IP6_ADDR_BLOCK4(dest), + IP6_ADDR_BLOCK5(dest), + IP6_ADDR_BLOCK6(dest), + IP6_ADDR_BLOCK7(dest), + IP6_ADDR_BLOCK8(dest))); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + + NETIF_SET_HWADDRHINT(netif, addr_hint); + err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if LWIP_IPV6_MLD +/** + * Add a hop-by-hop options header with a router alert option and padding. + * + * Used by MLD when sending a Multicast listener report/done message. + * + * @param p the packet to which we will prepend the options header + * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6) + * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD) + * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise + */ +err_t +ip6_options_add_hbh_ra(struct pbuf *p, u8_t nexth, u8_t value) +{ + struct ip6_hbh_hdr *hbh_hdr; + + /* Move pointer to make room for hop-by-hop options header. */ + if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) { + LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); + IP6_STATS_INC(ip6.err); + return ERR_BUF; + } + + hbh_hdr = (struct ip6_hbh_hdr *)p->payload; + + /* Set fields. */ + hbh_hdr->_nexth = nexth; + hbh_hdr->_hlen = 0; + hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION; + hbh_hdr->_ra_opt_dlen = 2; + hbh_hdr->_ra_opt_data = value; + hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION; + hbh_hdr->_padn_opt_dlen = 0; + + return ERR_OK; +} +#endif /* LWIP_IPV6_MLD */ + +#if IP6_DEBUG +/* Print an IPv6 header by using LWIP_DEBUGF + * @param p an IPv6 packet, p->payload pointing to the IPv6 header + */ +void +ip6_debug_print(struct pbuf *p) +{ + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; + + LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", + IP6H_V(ip6hdr), + IP6H_TC(ip6hdr), + IP6H_FL(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", + IP6H_PLEN(ip6hdr), + IP6H_NEXTH(ip6hdr), + IP6H_HOPLIM(ip6hdr))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->src)), + IP6_ADDR_BLOCK2(&(ip6hdr->src)), + IP6_ADDR_BLOCK3(&(ip6hdr->src)), + IP6_ADDR_BLOCK4(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->src)), + IP6_ADDR_BLOCK6(&(ip6hdr->src)), + IP6_ADDR_BLOCK7(&(ip6hdr->src)), + IP6_ADDR_BLOCK8(&(ip6hdr->src)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", + IP6_ADDR_BLOCK1(&(ip6hdr->dest)), + IP6_ADDR_BLOCK2(&(ip6hdr->dest)), + IP6_ADDR_BLOCK3(&(ip6hdr->dest)), + IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", + IP6_ADDR_BLOCK5(&(ip6hdr->dest)), + IP6_ADDR_BLOCK6(&(ip6hdr->dest)), + IP6_ADDR_BLOCK7(&(ip6hdr->dest)), + IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); + LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP6_DEBUG */ + +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_addr.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_addr.c new file mode 100644 index 0000000000..aa06659a02 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_addr.c @@ -0,0 +1,292 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Functions for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/def.h" + +/* used by IP6_ADDR_ANY(6) in ip6_addr.h */ +const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul); + +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) +#endif + +/** + * Check whether "cp" is a valid ascii representation + * of an IPv6 address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * + * @param cp IPv6 address in ascii representation (e.g. "FF01::1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip6addr_aton(const char *cp, ip6_addr_t *addr) +{ + u32_t addr_index, zero_blocks, current_block_index, current_block_value; + const char *s; + + /* Count the number of colons, to count the number of blocks in a "::" sequence + zero_blocks may be 1 even if there are no :: sequences */ + zero_blocks = 8; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + zero_blocks--; + } else if (!isxdigit(*s)) { + break; + } + } + + /* parse each block */ + addr_index = 0; + current_block_index = 0; + current_block_value = 0; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + } + current_block_index++; + current_block_value = 0; + if (current_block_index > 7) { + /* address too long! */ + return 0; + } + if (s[1] == ':') { + if (s[2] == ':') { + /* invalid format: three successive colons */ + return 0; + } + s++; + /* "::" found, set zeros */ + while (zero_blocks > 0) { + zero_blocks--; + if (current_block_index & 0x1) { + addr_index++; + } else { + if (addr) { + addr->addr[addr_index] = 0; + } + } + current_block_index++; + if (current_block_index > 7) { + /* address too long! */ + return 0; + } + } + } + } else if (isxdigit(*s)) { + /* add current digit */ + current_block_value = (current_block_value << 4) + + (isdigit(*s) ? (u32_t)(*s - '0') : + (u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A'))); + } else { + /* unexpected digit, space? CRLF? */ + break; + } + } + + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + } + + /* convert to network byte order. */ + if (addr) { + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]); + } + } + + if (current_block_index != 7) { + return 0; + } + + return 1; +} + +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char * +ip6addr_ntoa(const ip6_addr_t *addr) +{ + static char str[40]; + return ip6addr_ntoa_r(addr, str, 40); +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip6 address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) +{ + u32_t current_block_index, current_block_value, next_block_value; + s32_t i; + u8_t zero_flag, empty_block_flag; + + i = 0; + empty_block_flag = 0; /* used to indicate a zero chain for "::' */ + + for (current_block_index = 0; current_block_index < 8; current_block_index++) { + /* get the current 16-bit block */ + current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + /* Check for empty block. */ + if (current_block_value == 0) { + if (current_block_index == 7 && empty_block_flag == 1) { + /* special case, we must render a ':' for the last block. */ + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + break; + } + if (empty_block_flag == 0) { + /* generate empty block "::", but only if more than one contiguous zero block, + * according to current formatting suggestions RFC 5952. */ + next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]); + if ((current_block_index & 0x1) == 0x01) { + next_block_value = next_block_value >> 16; + } + next_block_value &= 0xffff; + if (next_block_value == 0) { + empty_block_flag = 1; + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + continue; /* move on to next block. */ + } + } else if (empty_block_flag == 1) { + /* move on to next block. */ + continue; + } + } else if (empty_block_flag == 1) { + /* Set this flag value so we don't produce multiple empty blocks. */ + empty_block_flag = 2; + } + + if (current_block_index > 0) { + buf[i++] = ':'; + if (i >= buflen) { + return NULL; + } + } + + if ((current_block_value & 0xf000) == 0) { + zero_flag = 1; + } else { + buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + if (((current_block_value & 0xf00) == 0) && (zero_flag)) { + /* do nothing */ + } else { + buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + if (((current_block_value & 0xf0) == 0) && (zero_flag)) { + /* do nothing */ + } + else { + buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); + zero_flag = 0; + if (i >= buflen) { + return NULL; + } + } + + buf[i++] = xchar((current_block_value & 0xf)); + if (i >= buflen) { + return NULL; + } + } + + buf[i] = 0; + + return buf; +} + +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_frag.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_frag.c new file mode 100644 index 0000000000..ff07f71cd2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/ip6_frag.c @@ -0,0 +1,805 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" +#include "lwip/ip6_frag.h" +#include "lwip/ip6.h" +#include "lwip/icmp6.h" +#include "lwip/nd6.h" +#include "lwip/ip.h" + +#include "lwip/pbuf.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#if IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN)) +#endif + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IPv6 header, since it replaces + * the Fragment Header in memory in incoming fragments to keep + * track of the various fragments. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* static variables */ +static struct ip6_reassdata *reassdatagrams; +static u16_t ip6_reass_pbufcount; + +/* Forward declarations. */ +static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr); +#if IP_REASS_FREE_OLDEST +static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed); +#endif /* IP_REASS_FREE_OLDEST */ + +void +ip6_reass_tmr(void) +{ + struct ip6_reassdata *r, *tmp; + +#if !IPV6_FRAG_COPYHEADER + LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", + sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); +#endif /* !IPV6_FRAG_COPYHEADER */ + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + r = r->next; + } else { + /* reassembly timed out */ + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip6_reass_free_complete_datagram(tmp); + } + } +} + +/** + * Free a datagram (struct ip6_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), + * sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + */ +static void +ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) +{ + struct ip6_reassdata *prev; + u16_t pbufs_freed = 0; + u16_t clen; + struct pbuf *p; + struct ip6_reass_helper *iprh; + +#if LWIP_ICMP6 + iprh = (struct ip6_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). + This cannot fail since we already checked when receiving this fragment. */ + if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)IPV6_FRAG_HDRREF(ipr->iphdr)))) { + LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); + } + else { + icmp6_time_exceeded(p, ICMP6_TE_FRAG); + } + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(p); + } +#endif /* LWIP_ICMP6 */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip6_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(pcur); + } + + /* Then, unchain the struct ip6_reassdata from the list and free it. */ + if (ipr == reassdatagrams) { + reassdatagrams = ipr->next; + } else { + prev = reassdatagrams; + while (prev != NULL) { + if (prev->next == ipr) { + break; + } + prev = prev->next; + } + if (prev != NULL) { + prev->next = ipr->next; + } + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* Finally, update number of pbufs in reassembly queue */ + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); + ip6_reass_pbufcount -= pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram ipr is not freed! + * + * @param ipr ip6_reassdata for the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + */ +static void +ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) +{ + struct ip6_reassdata *r, *oldest; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the current datagram! */ + do { + r = oldest = reassdatagrams; + while (r != NULL) { + if (r != ipr) { + if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + } + } + r = r->next; + } + if (oldest == ipr) { + /* nothing to free, ipr is the only element on the list */ + return; + } + if (oldest != NULL) { + ip6_reass_free_complete_datagram(oldest); + } + } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Reassembles incoming IPv6 fragments into an IPv6 datagram. + * + * @param p points to the IPv6 Fragment Header + * @return NULL if reassembly is incomplete, pbuf pointing to + * IPv6 Header if reassembly is complete + */ +struct pbuf * +ip6_reass(struct pbuf *p) +{ + struct ip6_reassdata *ipr, *ipr_prev; + struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct ip6_frag_hdr *frag_hdr; + u16_t offset, len; + u16_t clen; + u8_t valid = 1; + struct pbuf *q; + + IP6_FRAG_STATS_INC(ip6_frag.recv); + + if ((const void*)ip6_current_header() != ((u8_t*)p->payload) - IP6_HLEN) { + /* ip6_frag_hdr must be in the first pbuf, not chained */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + + frag_hdr = (struct ip6_frag_hdr *) p->payload; + + clen = pbuf_clen(p); + + offset = lwip_ntohs(frag_hdr->_fragment_offset); + + /* Calculate fragment length from IPv6 payload length. + * Adjust for headers before Fragment Header. + * And finally adjust by Fragment Header length. */ + len = lwip_ntohs(ip6_current_header()->_plen); + len -= (u16_t)(((u8_t*)p->payload - (const u8_t*)ip6_current_header()) - IP6_HLEN); + len -= IP6_FRAG_HLEN; + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if ((frag_hdr->_identification == ipr->identification) && + ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) && + ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) { + IP6_FRAG_STATS_INC(ip6_frag.cachehit); + break; + } + ipr_prev = ipr; + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + /* Make room and try again. */ + ip6_reass_remove_oldest_datagram(ipr, clen); + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr != NULL) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else +#endif /* IP_REASS_FREE_OLDEST */ + { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } + + memset(ipr, 0, sizeof(struct ip6_reassdata)); + ipr->timer = IP_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + + /* Use the current IPv6 header for src/dest address reference. + * Eventually, we will replace it when we get the first fragment + * (it might be this one, in any case, it is done later). */ +#if IPV6_FRAG_COPYHEADER + MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN); +#else /* IPV6_FRAG_COPYHEADER */ + /* need to use the none-const pointer here: */ + ipr->iphdr = ip_data.current_ip6_header; +#endif /* IPV6_FRAG_COPYHEADER */ + + /* copy the fragmented packet id. */ + ipr->identification = frag_hdr->_identification; + + /* copy the nexth field */ + ipr->nexth = frag_hdr->_nexth; + } + + /* Check if we are allowed to enqueue more datagrams. */ + if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + ip6_reass_remove_oldest_datagram(ipr, clen); + if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else +#endif /* IP_REASS_FREE_OLDEST */ + { + /* @todo: send ICMPv6 time exceeded here? */ + /* drop this pbuf */ + IP6_FRAG_STATS_INC(ip6_frag.memerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } + + /* Overwrite Fragment Header with our own helper struct. */ +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + /* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4). + This cannot fail since we already checked when receiving this fragment. */ + u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } +#else /* IPV6_FRAG_COPYHEADER */ + LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1", + sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); +#endif /* IPV6_FRAG_COPYHEADER */ + iprh = (struct ip6_reass_helper *)p->payload; + iprh->next_pbuf = NULL; + iprh->start = (offset & IP6_FRAG_OFFSET_MASK); + iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; + + /* find the right place to insert this pbuf */ + /* Iterate through until we either get to the end of the list (append), + * or we find on with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip6_reass_helper*)q->payload; + if (iprh->start < iprh_tmp->start) { +#if IP_REASS_CHECK_OVERLAP + if (iprh->end > iprh_tmp->start) { + /* fragment overlaps with following, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + if (iprh_prev != NULL) { + if (iprh->start < iprh_prev->end) { + /* fragment overlaps with previous, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } +#endif /* IP_REASS_CHECK_OVERLAP */ + /* the new pbuf should be inserted before this */ + iprh->next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ + iprh_prev->next_pbuf = p; + } else { + /* fragment with the lowest offset */ + ipr->p = p; + } + break; + } else if (iprh->start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; +#if IP_REASS_CHECK_OVERLAP + } else if (iprh->start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no gaps. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = p; + if (iprh_prev->end != iprh->start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = p; + } + } + + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time */ + ip6_reass_pbufcount += clen; + + /* Remember IPv6 header if this is the first fragment. */ + if (iprh->start == 0) { +#if IPV6_FRAG_COPYHEADER + if (iprh->next_pbuf != NULL) { + MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN); + } +#else /* IPV6_FRAG_COPYHEADER */ + /* need to use the none-const pointer here: */ + ipr->iphdr = ip_data.current_ip6_header; +#endif /* IPV6_FRAG_COPYHEADER */ + } + + /* If this is the last fragment, calculate total packet length. */ + if ((offset & IP6_FRAG_MORE_FLAG) == 0) { + ipr->datagram_len = iprh->end; + } + + /* Additional validity tests: we have received first and last fragment. */ + iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; + if (iprh_tmp->start != 0) { + valid = 0; + } + if (ipr->datagram_len == 0) { + valid = 0; + } + + /* Final validity test: no gaps between current and last fragment. */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while ((q != NULL) && valid) { + iprh = (struct ip6_reass_helper*)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + + if (valid) { + /* All fragments have been received */ + struct ip6_hdr* iphdr_ptr; + + /* chain together the pbufs contained within the ip6_reassdata list. */ + iprh = (struct ip6_reass_helper*) ipr->p->payload; + while (iprh != NULL) { + struct pbuf* next_pbuf = iprh->next_pbuf; + if (next_pbuf != NULL) { + /* Save next helper struct (will be hidden in next step). */ + iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload; + + /* hide the fragment header for every succeeding fragment */ + pbuf_header(next_pbuf, -IP6_FRAG_HLEN); +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + /* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */ + u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM)); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } +#endif + pbuf_cat(ipr->p, next_pbuf); + } + else { + iprh_tmp = NULL; + } + + iprh = iprh_tmp; + } + +#if IPV6_FRAG_COPYHEADER + if (IPV6_FRAG_REQROOM > 0) { + /* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */ + u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM)); + LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0); + } + iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN); + MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN); +#else + iphdr_ptr = ipr->iphdr; +#endif + + /* Adjust datagram length by adding header lengths. */ + ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr) + + IP6_FRAG_HLEN + - IP6_HLEN); + + /* Set payload length in ip header. */ + iphdr_ptr->_plen = lwip_htons(ipr->datagram_len); + + /* Get the first pbuf. */ + p = ipr->p; + + /* Restore Fragment Header in first pbuf. Mark as "single fragment" + * packet. Restore nexth. */ + frag_hdr = (struct ip6_frag_hdr *) p->payload; + frag_hdr->_nexth = ipr->nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = 0; + frag_hdr->_identification = 0; + + /* release the sources allocate for the fragment queue entry */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); + ipr_prev->next = ipr->next; + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* adjust the number of pbufs currently queued for reassembly. */ + ip6_reass_pbufcount -= pbuf_clen(p); + + /* Move pbuf back to IPv6 header. + This cannot fail since we already checked when receiving this fragment. */ + if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) { + LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); + pbuf_free(p); + return NULL; + } + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + return NULL; + +nullreturn: + pbuf_free(p); + return NULL; +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG + +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip6_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ip6_frag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip6_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * Fragment an IPv6 datagram if too large for the netif or path MTU. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p + * + * @param p ipv6 packet to send + * @param netif the netif on which to send + * @param dest destination ipv6 address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) +{ + struct ip6_hdr *original_ip6hdr; + struct ip6_hdr *ip6hdr; + struct ip6_frag_hdr *frag_hdr; + struct pbuf *rambuf; +#if !LWIP_NETIF_TX_SINGLE_PBUF + struct pbuf *newpbuf; + u16_t newpbuflen = 0; + u16_t left_to_copy; +#endif + static u32_t identification; + u16_t nfb; + u16_t left, cop; + u16_t mtu; + u16_t fragment_offset = 0; + u16_t last; + u16_t poff = IP6_HLEN; + + identification++; + + original_ip6hdr = (struct ip6_hdr *)p->payload; + + mtu = nd6_get_destination_mtu(dest, netif); + + /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ + left = p->tot_len - IP6_HLEN; + + nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; + + while (left) { + last = (left <= nfb); + + /* Fill this fragment */ + cop = last ? left : nfb; + +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff); + /* make room for the IP header */ + if (pbuf_header(rambuf, IP6_HLEN)) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); +#else + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (p->len >= (IP6_HLEN))); + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len -= poff; + p->tot_len -= poff; + + left_to_copy = cop; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + pcr = ip6_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip6_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) { + p = p->next; + } + } + poff = newpbuflen; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + /* Set headers */ + frag_hdr->_nexth = original_ip6hdr->_nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); + frag_hdr->_identification = lwip_htonl(identification); + + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); + IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + IP6_FRAG_STATS_INC(ip6_frag.xmit); + netif->output_ip6(netif, rambuf, dest); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left -= cop; + fragment_offset += cop; + } + return ERR_OK; +} + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/mld6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/mld6.c new file mode 100644 index 0000000000..9acb82fe24 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/mld6.c @@ -0,0 +1,588 @@ +/** + * @file + * Multicast listener discovery + * + * @defgroup mld6 MLD6 + * @ingroup ip6 + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2.\n + * To be called from TCPIP thread + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/* Based on igmp.c implementation of igmp v2 protocol */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mld6.h" +#include "lwip/prot/mld6.h" +#include "lwip/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip.h" +#include "lwip/inet_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + + +/* + * MLD constants + */ +#define MLD6_HL 1 +#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) + +#define MLD6_GROUP_NON_MEMBER 0 +#define MLD6_GROUP_DELAYING_MEMBER 1 +#define MLD6_GROUP_IDLE_MEMBER 2 + +/* Forward declarations. */ +static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr); +static err_t mld6_remove_group(struct netif *netif, struct mld_group *group); +static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); +static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type); + + +/** + * Stop MLD processing on interface + * + * @param netif network interface on which stop MLD processing + */ +err_t +mld6_stop(struct netif *netif) +{ + struct mld_group *group = netif_mld6_data(netif); + + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL); + + while (group != NULL) { + struct mld_group *next = group->next; /* avoid use-after-free below */ + + /* disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER); + } + + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report MLD memberships for this interface + * + * @param netif network interface on which report MLD memberships + */ +void +mld6_report_groups(struct netif *netif) +{ + struct mld_group *group = netif_mld6_data(netif); + + while (group != NULL) { + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + group = group->next; + } +} + +/** + * Search for a group that is joined on a netif + * + * @param ifp the network interface for which to look + * @param addr the group ipv6 address to search for + * @return a struct mld_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct mld_group * +mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr) +{ + struct mld_group *group = netif_mld6_data(ifp); + + while (group != NULL) { + if (ip6_addr_cmp(&(group->group_address), addr)) { + return group; + } + group = group->next; + } + + return NULL; +} + + +/** + * create a new group + * + * @param ifp the network interface for which to create + * @param addr the new group ipv6 + * @return a struct mld_group*, + * NULL on memory error. + */ +static struct mld_group * +mld6_new_group(struct netif *ifp, const ip6_addr_t *addr) +{ + struct mld_group *group; + + group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); + if (group != NULL) { + ip6_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = netif_mld6_data(ifp); + + netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group); + } + + return group; +} + +/** + * Remove a group from the mld_group_list, but do not free it yet + * + * @param group the group to remove + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +mld6_remove_group(struct netif *netif, struct mld_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (netif_mld6_data(netif) == group) { + netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next); + } else { + /* look for group further down the list */ + struct mld_group *tmpGroup; + for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not find group */ + if (tmpGroup == NULL) { + err = ERR_ARG; + } + } + + return err; +} + + +/** + * Process an input MLD message. Called by icmp6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +mld6_input(struct pbuf *p, struct netif *inp) +{ + struct mld_header *mld_hdr; + struct mld_group *group; + + MLD6_STATS_INC(mld6.recv); + + /* Check that mld header fits in packet. */ + if (p->len < sizeof(struct mld_header)) { + /* @todo debug message */ + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + MLD6_STATS_INC(mld6.drop); + return; + } + + mld_hdr = (struct mld_header *)p->payload; + + switch (mld_hdr->type) { + case ICMP6_TYPE_MLQ: /* Multicast listener query. */ + /* Is it a general query? */ + if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && + ip6_addr_isany(&(mld_hdr->multicast_address))) { + MLD6_STATS_INC(mld6.rx_general); + /* Report all groups, except all nodes group, and if-local groups. */ + group = netif_mld6_data(inp); + while (group != NULL) { + if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && + (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + group = group->next; + } + } else { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_group); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* Schedule a report. */ + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + } + break; /* ICMP6_TYPE_MLQ */ + case ICMP6_TYPE_MLR: /* Multicast listener report. */ + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_report); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* If we are waiting to report, cancel it. */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + group->timer = 0; /* stopped */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + } + break; /* ICMP6_TYPE_MLR */ + case ICMP6_TYPE_MLD: /* Multicast listener done. */ + /* Do nothing, router will query us. */ + break; /* ICMP6_TYPE_MLD */ + default: + MLD6_STATS_INC(mld6.proterr); + MLD6_STATS_INC(mld6.drop); + break; + } + + pbuf_free(p); +} + +/** + * @ingroup mld6 + * Join a group on a network interface. + * + * @param srcaddr ipv6 address of the network interface which should + * join a new group. If IP6_ADDR_ANY, join on all netifs + * @param groupaddr the ipv6 address of the group to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we join this interface ? */ + if (ip6_addr_isany(srcaddr) || + netif_get_ip6_addr_match(netif, srcaddr) >= 0) { + err = mld6_joingroup_netif(netif, groupaddr); + if (err != ERR_OK) { + return err; + } + } + + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * @ingroup mld6 + * Join a group on a network interface. + * + * @param netif the network interface which should join a new group. + * @param groupaddr the ipv6 address of the group to join + * @return ERR_OK if group was joined on the netif, an err_t otherwise + */ +err_t +mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) +{ + struct mld_group *group; + + /* find group or create a new one if not found */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group == NULL) { + /* Joining a new group. Create a new group entry. */ + group = mld6_new_group(netif, groupaddr); + if (group == NULL) { + return ERR_MEM; + } + + /* Activate this address on the MAC layer. */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); + } + + /* Report our membership. */ + MLD6_STATS_INC(mld6.tx_report); + mld6_send(netif, group, ICMP6_TYPE_MLR); + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + + /* Increment group use */ + group->use++; + return ERR_OK; +} + +/** + * @ingroup mld6 + * Leave a group on a network interface. + * + * @param srcaddr ipv6 address of the network interface which should + * leave the group. If IP6_ISANY, leave on all netifs + * @param groupaddr the ipv6 address of the group to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct netif *netif; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we leave this interface ? */ + if (ip6_addr_isany(srcaddr) || + netif_get_ip6_addr_match(netif, srcaddr) >= 0) { + err_t res = mld6_leavegroup_netif(netif, groupaddr); + if (err != ERR_OK) { + /* Store this result if we have not yet gotten a success */ + err = res; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * @ingroup mld6 + * Leave a group on a network interface. + * + * @param netif the network interface which should leave the group. + * @param groupaddr the ipv6 address of the group to leave + * @return ERR_OK if group was left on the netif, an err_t otherwise + */ +err_t +mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) +{ + struct mld_group *group; + + /* find group */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Leave if there is no other use of the group */ + if (group->use <= 1) { + /* Remove the group from the list */ + mld6_remove_group(netif, group); + + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + MLD6_STATS_INC(mld6.tx_leave); + mld6_send(netif, group, ICMP6_TYPE_MLD); + } + + /* Disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); + } + + /* free group struct */ + memp_free(MEMP_MLD6_GROUP, group); + } else { + /* Decrement group use */ + group->use--; + } + + /* Left group */ + return ERR_OK; + } + + /* Group not found */ + return ERR_VAL; +} + + +/** + * Periodic timer for mld processing. Must be called every + * MLD6_TMR_INTERVAL milliseconds (100). + * + * When a delaying member expires, a membership report is sent. + */ +void +mld6_tmr(void) +{ + struct netif *netif = netif_list; + + while (netif != NULL) { + struct mld_group *group = netif_mld6_data(netif); + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + MLD6_STATS_INC(mld6.tx_report); + mld6_send(netif, group, ICMP6_TYPE_MLR); + group->group_state = MLD6_GROUP_IDLE_MEMBER; + } + } + } + group = group->next; + } + netif = netif->next; + } +} + +/** + * Schedule a delayed membership report for a group + * + * @param group the mld_group for which "delaying" membership report + * should be sent + * @param maxresp the max resp delay provided in the query + */ +static void +mld6_delayed_report(struct mld_group *group, u16_t maxresp) +{ + /* Convert maxresp from milliseconds to tmr ticks */ + maxresp = maxresp / MLD6_TMR_INTERVAL; + if (maxresp == 0) { + maxresp = 1; + } + +#ifdef LWIP_RAND + /* Randomize maxresp. (if LWIP_RAND is supported) */ + maxresp = LWIP_RAND() % maxresp; + if (maxresp == 0) { + maxresp = 1; + } +#endif /* LWIP_RAND */ + + /* Apply timer value if no report has been scheduled already. */ + if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || + ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + group->timer = maxresp; + group->group_state = MLD6_GROUP_DELAYING_MEMBER; + } +} + +/** + * Send a MLD message (report or done). + * + * An IPv6 hop-by-hop options header with a router alert option + * is prepended. + * + * @param group the group to report or quit + * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) + */ +static void +mld6_send(struct netif *netif, struct mld_group *group, u8_t type) +{ + struct mld_header *mld_hdr; + struct pbuf *p; + const ip6_addr_t *src_addr; + + /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); + if (p == NULL) { + MLD6_STATS_INC(mld6.memerr); + return; + } + + /* Move to make room for Hop-by-hop options header. */ + if (pbuf_header(p, -IP6_HBH_HLEN)) { + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + return; + } + + /* Select our source address. */ + if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { + /* This is a special case, when we are performing duplicate address detection. + * We must join the multicast group, but we don't have a valid address yet. */ + src_addr = IP6_ADDR_ANY6; + } else { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(netif, 0); + } + + /* MLD message header pointer. */ + mld_hdr = (struct mld_header *)p->payload; + + /* Set fields. */ + mld_hdr->type = type; + mld_hdr->code = 0; + mld_hdr->chksum = 0; + mld_hdr->max_resp_delay = 0; + mld_hdr->reserved = 0; + ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, + src_addr, &(group->group_address)); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Add hop-by-hop headers options: router alert with MLD value. */ + ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); + + if (type == ICMP6_TYPE_MLR) { + /* Remember we were the last to report */ + group->last_reporter_flag = 1; + } + + /* Send the packet out. */ + MLD6_STATS_INC(mld6.xmit); + ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), + MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif); + pbuf_free(p); +} + +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/nd6.c b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/nd6.c new file mode 100644 index 0000000000..0b367181b2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/ipv6/nd6.c @@ -0,0 +1,2102 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/nd6.h" +#include "lwip/priv/nd6_priv.h" +#include "lwip/prot/nd6.h" +#include "lwip/prot/icmp6.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/mld6.h" +#include "lwip/ip.h" +#include "lwip/stats.h" +#include "lwip/dns.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK +#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK +#endif + +/* Router tables. */ +struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; +struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; +struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; +struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; + +/* Default values, can be updated by a RA message. */ +u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; +u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ + +/* Index for cache entries. */ +static u8_t nd6_cached_neighbor_index; +static u8_t nd6_cached_destination_index; + +/* Multicast address holder. */ +static ip6_addr_t multicast_address; + +/* Static buffer to parse RA packet options (size of a prefix option, biggest option) */ +static u8_t nd6_ra_buffer[sizeof(struct prefix_option)]; + +/* Forward declarations. */ +static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr); +static s8_t nd6_new_neighbor_cache_entry(void); +static void nd6_free_neighbor_cache_entry(s8_t i); +static s8_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr); +static s8_t nd6_new_destination_cache_entry(void); +static s8_t nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif); +static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif); +static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif); +static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif); +static s8_t nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif); +static s8_t nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif); +static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); +static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q); + +#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 +#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 +static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); +static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); +static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags); +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +static err_t nd6_send_rs(struct netif *netif); +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +#if LWIP_ND6_QUEUEING +static void nd6_free_q(struct nd6_q_entry *q); +#else /* LWIP_ND6_QUEUEING */ +#define nd6_free_q(q) pbuf_free(q) +#endif /* LWIP_ND6_QUEUEING */ +static void nd6_send_q(s8_t i); + + +/** + * Process an incoming neighbor discovery message + * + * @param p the nd packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +nd6_input(struct pbuf *p, struct netif *inp) +{ + u8_t msg_type; + s8_t i; + + ND6_STATS_INC(nd6.recv); + + msg_type = *((u8_t *)p->payload); + switch (msg_type) { + case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ + { + struct na_header *na_hdr; + struct lladdr_option *lladdr_opt; + + /* Check that na header fits in packet. */ + if (p->len < (sizeof(struct na_header))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + na_hdr = (struct na_header *)p->payload; + + /* Unsolicited NA?*/ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + ip6_addr_t target_address; + + /* This is an unsolicited NA. + * link-layer changed? + * part of DAD mechanism? */ + + /* Create an aligned copy. */ + ip6_addr_set(&target_address, &(na_hdr->target_address)); + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* If the target address matches this netif, it is a DAD response. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { + /* We are using a duplicate address. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + +#if LWIP_IPV6_AUTOCONFIG + /* Check to see if this address was autoconfigured. */ + if (!ip6_addr_islinklocal(&target_address)) { + i = nd6_get_onlink_prefix(&target_address, inp); + if (i >= 0) { + /* Mark this prefix as duplicate, so that we don't use it + * to generate this address again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + + pbuf_free(p); + return; + } + } +#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ + + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + 2)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + /* This is an unsolicited NA, most likely there was a LLADDR change. */ + i = nd6_find_neighbor_cache_entry(&target_address); + if (i >= 0) { + if (na_hdr->flags & ND6_FLAG_OVERRIDE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + } + } else { + ip6_addr_t target_address; + + /* This is a solicited NA. + * neighbor address resolution response? + * neighbor unreachability detection response? */ + + /* Create an aligned copy. */ + ip6_addr_set(&target_address, &(na_hdr->target_address)); + + /* Find the cache entry corresponding to this na. */ + i = nd6_find_neighbor_cache_entry(&target_address); + if (i < 0) { + /* We no longer care about this target address. drop it. */ + pbuf_free(p); + return; + } + + /* Update cache entry. */ + if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || + (neighbor_cache[i].state == ND6_INCOMPLETE)) { + /* Check that link-layer address option also fits in packet. */ + if (p->len < (sizeof(struct na_header) + 2)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + + neighbor_cache[i].netif = inp; + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; + + /* Send queued packets, if any. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + } + + break; /* ICMP6_TYPE_NA */ + } + case ICMP6_TYPE_NS: /* Neighbor solicitation. */ + { + struct ns_header *ns_hdr; + struct lladdr_option *lladdr_opt; + u8_t accepted; + + /* Check that ns header fits in packet. */ + if (p->len < sizeof(struct ns_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ns_hdr = (struct ns_header *)p->payload; + + /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ + if (p->len >= (sizeof(struct ns_header) + 2)) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { + lladdr_opt = NULL; + } + } else { + lladdr_opt = NULL; + } + + /* Check if the target address is configured on the receiving netif. */ + accepted = 0; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || + (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && + ip6_addr_isany(ip6_current_src_addr()))) && + ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { + accepted = 1; + break; + } + } + + /* NS not for us? */ + if (!accepted) { + pbuf_free(p); + return; + } + + /* Check for ANY address in src (DAD algorithm). */ + if (ip6_addr_isany(ip6_current_src_addr())) { + /* Sender is validating this address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && + ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { + /* Send a NA back so that the sender does not use this address. */ + nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); + if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { + /* We shouldn't use this address either. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + } + } + } + } else { + ip6_addr_t target_address; + + /* Sender is trying to resolve our address. */ + /* Verify that they included their own link-layer address. */ + if (lladdr_opt == NULL) { + /* Not a valid message. */ + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if (i>= 0) { + /* We already have a record for the solicitor. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + + /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } else { + /* Add their IPv6 address and link-layer address to neighbor cache. + * We will need it at least to send a unicast NA message, but most + * likely we will also be communicating with this node soon. */ + i = nd6_new_neighbor_cache_entry(); + if (i < 0) { + /* We couldn't assign a cache entry for this neighbor. + * we won't be able to reply. drop it. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + + /* Create an aligned copy. */ + ip6_addr_set(&target_address, &(ns_hdr->target_address)); + + /* Send back a NA for us. Allocate the reply pbuf. */ + nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); + } + + break; /* ICMP6_TYPE_NS */ + } + case ICMP6_TYPE_RA: /* Router Advertisement. */ + { + struct ra_header *ra_hdr; + u8_t *buffer; /* Used to copy options. */ + u16_t offset; +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS + /* There can by multiple RDNSS options per RA */ + u8_t rdnss_server_idx = 0; +#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ + + /* Check that RA header fits in packet. */ + if (p->len < sizeof(struct ra_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ra_hdr = (struct ra_header *)p->payload; + + /* If we are sending RS messages, stop. */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* ensure at least one solicitation is sent */ + if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || + (nd6_send_rs(inp) == ERR_OK)) { + inp->rs_count = 0; + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + + /* Get the matching default router entry. */ + i = nd6_get_router(ip6_current_src_addr(), inp); + if (i < 0) { + /* Create a new router entry. */ + i = nd6_new_router(ip6_current_src_addr(), inp); + } + + if (i < 0) { + /* Could not create a new router entry. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Re-set invalidation timer. */ + default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime); + + /* Re-set default timer values. */ +#if LWIP_ND6_ALLOW_RA_UPDATES + if (ra_hdr->retrans_timer > 0) { + retrans_timer = lwip_htonl(ra_hdr->retrans_timer); + } + if (ra_hdr->reachable_time > 0) { + reachable_time = lwip_htonl(ra_hdr->reachable_time); + } +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + + /* @todo set default hop limit... */ + /* ra_hdr->current_hop_limit;*/ + + /* Update flags in local entry (incl. preference). */ + default_router_list[i].flags = ra_hdr->flags; + + /* Offset to options. */ + offset = sizeof(struct ra_header); + + /* Process each option. */ + while ((p->tot_len - offset) > 0) { + if (p->len == p->tot_len) { + /* no need to copy from contiguous pbuf */ + buffer = &((u8_t*)p->payload)[offset]; + } else { + buffer = nd6_ra_buffer; + if (pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset) != sizeof(struct prefix_option)) { + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + } + if (buffer[1] == 0) { + /* zero-length extension. drop packet */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + switch (buffer[0]) { + case ND6_OPTION_TYPE_SOURCE_LLADDR: + { + struct lladdr_option *lladdr_opt; + lladdr_opt = (struct lladdr_option *)buffer; + if ((default_router_list[i].neighbor_entry != NULL) && + (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { + SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); + default_router_list[i].neighbor_entry->state = ND6_REACHABLE; + default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; + } + break; + } + case ND6_OPTION_TYPE_MTU: + { + struct mtu_option *mtu_opt; + mtu_opt = (struct mtu_option *)buffer; + if (lwip_htonl(mtu_opt->mtu) >= 1280) { +#if LWIP_ND6_ALLOW_RA_UPDATES + inp->mtu = (u16_t)lwip_htonl(mtu_opt->mtu); +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + } + break; + } + case ND6_OPTION_TYPE_PREFIX_INFO: + { + struct prefix_option *prefix_opt; + prefix_opt = (struct prefix_option *)buffer; + + if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) && + (prefix_opt->prefix_length == 64) && + !ip6_addr_islinklocal(&(prefix_opt->prefix))) { + /* Add to on-link prefix list. */ + s8_t prefix; + ip6_addr_t prefix_addr; + + /* Get a memory-aligned copy of the prefix. */ + ip6_addr_set(&prefix_addr, &(prefix_opt->prefix)); + + /* find cache entry for this prefix. */ + prefix = nd6_get_onlink_prefix(&prefix_addr, inp); + if (prefix < 0) { + /* Create a new cache entry. */ + prefix = nd6_new_onlink_prefix(&prefix_addr, inp); + } + if (prefix >= 0) { + prefix_list[prefix].invalidation_timer = lwip_htonl(prefix_opt->valid_lifetime); + +#if LWIP_IPV6_AUTOCONFIG + if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { + /* Mark prefix as autonomous, so that address autoconfiguration can take place. + * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/ + prefix_list[prefix].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + + break; + } + case ND6_OPTION_TYPE_ROUTE_INFO: + /* @todo implement preferred routes. + struct route_option * route_opt; + route_opt = (struct route_option *)buffer;*/ + + break; +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS + case ND6_OPTION_TYPE_RDNSS: + { + u8_t num, n; + struct rdnss_option * rdnss_opt; + + rdnss_opt = (struct rdnss_option *)buffer; + num = (rdnss_opt->length - 1) / 2; + for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) { + ip_addr_t rdnss_address; + + /* Get a memory-aligned copy of the prefix. */ + ip_addr_copy_from_ip6(rdnss_address, rdnss_opt->rdnss_address[n]); + + if (htonl(rdnss_opt->lifetime) > 0) { + /* TODO implement Lifetime > 0 */ + dns_setserver(rdnss_server_idx++, &rdnss_address); + } else { + /* TODO implement DNS removal in dns.c */ + u8_t s; + for (s = 0; s < DNS_MAX_SERVERS; s++) { + const ip_addr_t *addr = dns_getserver(s); + if(ip_addr_cmp(addr, &rdnss_address)) { + dns_setserver(s, NULL); + } + } + } + } + break; + } +#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ + default: + /* Unrecognized option, abort. */ + ND6_STATS_INC(nd6.proterr); + break; + } + /* option length is checked earlier to be non-zero to make sure loop ends */ + offset += 8 * ((u16_t)buffer[1]); + } + + break; /* ICMP6_TYPE_RA */ + } + case ICMP6_TYPE_RD: /* Redirect */ + { + struct redirect_header *redir_hdr; + struct lladdr_option *lladdr_opt; + ip6_addr_t tmp; + + /* Check that Redir header fits in packet. */ + if (p->len < sizeof(struct redirect_header)) { + /* @todo debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + redir_hdr = (struct redirect_header *)p->payload; + + if (p->len >= (sizeof(struct redirect_header) + 2)) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); + if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { + lladdr_opt = NULL; + } + } else { + lladdr_opt = NULL; + } + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(&tmp, &(redir_hdr->destination_address)); + + /* Find dest address in cache */ + i = nd6_find_destination_cache_entry(&tmp); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Set the new target address. */ + ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address)); + + /* If Link-layer address of other router is given, try to add to neighbor cache. */ + if (lladdr_opt != NULL) { + if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { + /* Copy target address to current source address, to have an aligned copy. */ + ip6_addr_set(&tmp, &(redir_hdr->target_address)); + + i = nd6_find_neighbor_cache_entry(&tmp); + if (i < 0) { + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), &tmp); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } + if (i >= 0) { + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + } + } + } + break; /* ICMP6_TYPE_RD */ + } + case ICMP6_TYPE_PTB: /* Packet too big */ + { + struct icmp6_hdr *icmp6hdr; /* Packet too big message */ + struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ + u32_t pmtu; + ip6_addr_t tmp; + + /* Check that ICMPv6 header + IPv6 header fit in payload */ + if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { + /* drop short packets */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(&tmp, &(ip6hdr->dest)); + + /* Look for entry in destination cache. */ + i = nd6_find_destination_cache_entry(&tmp); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Change the Path MTU. */ + pmtu = lwip_htonl(icmp6hdr->data); + destination_cache[i].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); + + break; /* ICMP6_TYPE_PTB */ + } + + default: + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + break; /* default */ + } + + pbuf_free(p); +} + + +/** + * Periodic timer for Neighbor discovery functions: + * + * - Update neighbor reachability states + * - Update destination cache entries age + * - Update invalidation timers of default routers and on-link prefixes + * - Perform duplicate address detection (DAD) for our addresses + * - Send router solicitations + */ +void +nd6_tmr(void) +{ + s8_t i; + struct netif *netif; + + /* Process neighbor entries. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + switch (neighbor_cache[i].state) { + case ND6_INCOMPLETE: + if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && + (!neighbor_cache[i].isrouter)) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); + } + break; + case ND6_REACHABLE: + /* Send queued packets, if any are left. Should have been sent already. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } + if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { + /* Change to stale state. */ + neighbor_cache[i].state = ND6_STALE; + neighbor_cache[i].counter.stale_time = 0; + } else { + neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_STALE: + neighbor_cache[i].counter.stale_time++; + break; + case ND6_DELAY: + if (neighbor_cache[i].counter.delay_time <= 1) { + /* Change to PROBE state. */ + neighbor_cache[i].state = ND6_PROBE; + neighbor_cache[i].counter.probes_sent = 0; + } else { + neighbor_cache[i].counter.delay_time--; + } + break; + case ND6_PROBE: + if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && + (!neighbor_cache[i].isrouter)) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0); + } + break; + case ND6_NO_ENTRY: + default: + /* Do nothing. */ + break; + } + } + + /* Process destination entries. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + destination_cache[i].age++; + } + + /* Process router entries. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (default_router_list[i].neighbor_entry != NULL) { + /* Active entry. */ + if (default_router_list[i].invalidation_timer > 0) { + default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + /* Less than 1 second remaining. Clear this entry. */ + default_router_list[i].neighbor_entry->isrouter = 0; + default_router_list[i].neighbor_entry = NULL; + default_router_list[i].invalidation_timer = 0; + default_router_list[i].flags = 0; + } + } + } + + /* Process prefix entries. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].netif != NULL) { + if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + /* Entry timed out, remove it */ + prefix_list[i].invalidation_timer = 0; + +#if LWIP_IPV6_AUTOCONFIG + /* If any addresses were configured with this prefix, remove them */ + if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) { + s8_t j; + + for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { + if ((netif_ip6_addr_state(prefix_list[i].netif, j) != IP6_ADDR_INVALID) && + ip6_addr_netcmp(&prefix_list[i].prefix, netif_ip6_addr(prefix_list[i].netif, j))) { + netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_INVALID); + prefix_list[i].flags = 0; + + /* Exit loop. */ + break; + } + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + + prefix_list[i].netif = NULL; + prefix_list[i].flags = 0; + } else { + prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + +#if LWIP_IPV6_AUTOCONFIG + /* Initiate address autoconfiguration for this prefix, if conditions are met. */ + if (prefix_list[i].netif->ip6_autoconfig_enabled && + (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) && + !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) { + s8_t j; + /* Try to get an address on this netif that is invalid. + * Skip 0 index (link-local address) */ + for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { + if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) { + /* Generate an address using this prefix and interface ID from link-local address. */ + netif_ip6_addr_set_parts(prefix_list[i].netif, j, + prefix_list[i].prefix.addr[0], prefix_list[i].prefix.addr[1], + netif_ip6_addr(prefix_list[i].netif, 0)->addr[2], netif_ip6_addr(prefix_list[i].netif, 0)->addr[3]); + + /* Mark it as tentative (DAD will be performed if configured). */ + netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); + + /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; + + /* Exit loop. */ + break; + } + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + } + + + /* Process our own addresses, if DAD configured. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + u8_t addr_state = netif_ip6_addr_state(netif, i); + if (ip6_addr_istentative(addr_state)) { + if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { + /* No NA received in response. Mark address as valid. */ + netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); + /* @todo implement preferred and valid lifetimes. */ + } else if (netif->flags & NETIF_FLAG_UP) { + /* Send a NS for this address. */ + nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); + /* tentative: set next state by increasing by one */ + netif_ip6_addr_set_state(netif, i, addr_state + 1); + /* @todo send max 1 NS per tmr call? enable return*/ + /*return;*/ + } + } + } + } + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send router solicitation messages, if necessary. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP) && + (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)))) { + if (nd6_send_rs(netif) == ERR_OK) { + netif->rs_count--; + } + } + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +} + +/** Send a neighbor solicitation message for a specific neighbor cache entry + * + * @param entry the neightbor cache entry for wich to send the message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags) +{ + nd6_send_ns(entry->netif, &entry->next_hop_address, flags); +} + +/** + * Send a neighbor solicitation message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) +{ + struct ns_header *ns_hdr; + struct pbuf *p; + const ip6_addr_t *src_addr; + u16_t lladdr_opt_len; + + if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(netif, 0); + /* calculate option length (in 8-byte-blocks) */ + lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; + } else { + src_addr = IP6_ADDR_ANY6; + /* Option "MUST NOT be included when the source IP address is the unspecified address." */ + lladdr_opt_len = 0; + } + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + ns_hdr = (struct ns_header *)p->payload; + + ns_hdr->type = ICMP6_TYPE_NS; + ns_hdr->code = 0; + ns_hdr->chksum = 0; + ns_hdr->reserved = 0; + ip6_addr_set(&(ns_hdr->target_address), target_addr); + + if (lladdr_opt_len != 0) { + struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + target_addr = &multicast_address; + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + target_addr); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +/** + * Send a neighbor advertisement message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) +{ + struct na_header *na_hdr; + struct lladdr_option *lladdr_opt; + struct pbuf *p; + const ip6_addr_t *src_addr; + const ip6_addr_t *dest_addr; + u16_t lladdr_opt_len; + + /* Use link-local address as source address. */ + /* src_addr = netif_ip6_addr(netif, 0); */ + /* Use target address as source address. */ + src_addr = target_addr; + + /* Allocate a packet. */ + lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + na_hdr->type = ICMP6_TYPE_NA; + na_hdr->code = 0; + na_hdr->chksum = 0; + na_hdr->flags = flags & 0xf0; + na_hdr->reserved[0] = 0; + na_hdr->reserved[1] = 0; + na_hdr->reserved[2] = 0; + ip6_addr_set(&(na_hdr->target_address), target_addr); + + lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + dest_addr = &multicast_address; + } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { + ip6_addr_set_allnodes_linklocal(&multicast_address); + dest_addr = &multicast_address; + } else { + dest_addr = ip6_current_src_addr(); + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + dest_addr); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, src_addr, dest_addr, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +/** + * Send a router solicitation message + * + * @param netif the netif on which to send the message + */ +static err_t +nd6_send_rs(struct netif *netif) +{ + struct rs_header *rs_hdr; + struct lladdr_option *lladdr_opt; + struct pbuf *p; + const ip6_addr_t *src_addr; + err_t err; + u16_t lladdr_opt_len = 0; + + /* Link-local source address, or unspecified address? */ + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { + src_addr = netif_ip6_addr(netif, 0); + } else { + src_addr = IP6_ADDR_ANY6; + } + + /* Generate the all routers target address. */ + ip6_addr_set_allrouters_linklocal(&multicast_address); + + /* Allocate a packet. */ + if (src_addr != IP6_ADDR_ANY6) { + lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + } + p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); + if (p == NULL) { + ND6_STATS_INC(nd6.memerr); + return ERR_BUF; + } + + /* Set fields. */ + rs_hdr = (struct rs_header *)p->payload; + + rs_hdr->type = ICMP6_TYPE_RS; + rs_hdr->code = 0; + rs_hdr->chksum = 0; + rs_hdr->reserved = 0; + + if (src_addr != IP6_ADDR_ANY6) { + /* Include our hw address. */ + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = (u8_t)lladdr_opt_len; + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + +#if CHECKSUM_GEN_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + &multicast_address); + } +#endif /* CHECKSUM_GEN_ICMP6 */ + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + + err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); + + return err; +} +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +/** + * Search for a neighbor cache entry + * + * @param ip6addr the IPv6 address of the neighbor + * @return The neighbor cache entry index that matched, -1 if no + * entry is found + */ +static s8_t +nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { + return i; + } + } + return -1; +} + +/** + * Create a new neighbor cache entry. + * + * If no unused entry is found, will try to recycle an old entry + * according to ad-hoc "age" heuristic. + * + * @return The neighbor cache entry index that was created, -1 if no + * entry could be created + */ +static s8_t +nd6_new_neighbor_cache_entry(void) +{ + s8_t i; + s8_t j; + u32_t time; + + + /* First, try to find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (neighbor_cache[i].state == ND6_NO_ENTRY) { + return i; + } + } + + /* We need to recycle an entry. in general, do not recycle if it is a router. */ + + /* Next, try to find a Stale entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_STALE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Probe entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_PROBE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Delayed entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_DELAY) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find the oldest reachable entry. */ + time = 0xfffffffful; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_REACHABLE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.reachable_time < time) { + j = i; + time = neighbor_cache[i].counter.reachable_time; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry without queued packets. */ + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ( + (neighbor_cache[i].q == NULL) && + (neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry with queued packets. */ + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* No more entries to try. */ + return -1; +} + +/** + * Will free any resources associated with a neighbor cache + * entry, and will mark it as unused. + * + * @param i the neighbor cache entry index to free + */ +static void +nd6_free_neighbor_cache_entry(s8_t i) +{ + if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { + return; + } + if (neighbor_cache[i].isrouter) { + /* isrouter needs to be cleared before deleting a neighbor cache entry */ + return; + } + + /* Free any queued packets. */ + if (neighbor_cache[i].q != NULL) { + nd6_free_q(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } + + neighbor_cache[i].state = ND6_NO_ENTRY; + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = NULL; + neighbor_cache[i].counter.reachable_time = 0; + ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); +} + +/** + * Search for a destination cache entry + * + * @param ip6addr the IPv6 address of the destination + * @return The destination cache entry index that matched, -1 if no + * entry is found + */ +static s8_t +nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { + return i; + } + } + return -1; +} + +/** + * Create a new destination cache entry. If no unused entry is found, + * will recycle oldest entry. + * + * @return The destination cache entry index that was created, -1 if no + * entry was created + */ +static s8_t +nd6_new_destination_cache_entry(void) +{ + s8_t i, j; + u32_t age; + + /* Find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { + return i; + } + } + + /* Find oldest entry. */ + age = 0; + j = LWIP_ND6_NUM_DESTINATIONS - 1; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (destination_cache[i].age > age) { + j = i; + } + } + + return j; +} + +/** + * Clear the destination cache. + * + * This operation may be necessary for consistency in the light of changing + * local addresses and/or use of the gateway hook. + */ +void +nd6_clear_destination_cache(void) +{ + int i; + + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + ip6_addr_set_any(&destination_cache[i].destination_addr); + } +} + +/** + * Determine whether an address matches an on-link prefix. + * + * @param ip6addr the IPv6 address to match + * @return 1 if the address is on-link, 0 otherwise + */ +static s8_t +nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if ((prefix_list[i].netif == netif) && + (prefix_list[i].invalidation_timer > 0) && + ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { + return 1; + } + } + /* Check to see if address prefix matches a (manually?) configured address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { + return 1; + } + } + return 0; +} + +/** + * Select a default router for a destination. + * + * @param ip6addr the destination address + * @param netif the netif for the outgoing packet, if known + * @return the default router entry index, or -1 if no suitable + * router is found + */ +static s8_t +nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) +{ + s8_t i; + /* last_router is used for round-robin router selection (as recommended + * in RFC). This is more robust in case one router is not reachable, + * we are not stuck trying to resolve it. */ + static s8_t last_router; + (void)ip6addr; /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ + + /* @todo: implement default router preference */ + + /* Look for reachable routers. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0) && + (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { + return i; + } + } + + /* Look for router in other reachability states, but still valid according to timer. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0)) { + return i; + } + } + + /* Look for any router for which we have any information at all. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if (default_router_list[i].neighbor_entry != NULL && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { + return i; + } + } + + /* no suitable router found. */ + return -1; +} + +/** + * Find a router-announced route to the given destination. + * + * The caller is responsible for checking whether the returned netif, if any, + * is in a suitable state (up, link up) to be used for packet transmission. + * + * @param ip6addr the destination IPv6 address + * @return the netif to use for the destination, or NULL if none found + */ +struct netif * +nd6_find_route(const ip6_addr_t *ip6addr) +{ + s8_t i; + + i = nd6_select_router(ip6addr, NULL); + if (i >= 0) { + if (default_router_list[i].neighbor_entry != NULL) { + return default_router_list[i].neighbor_entry->netif; /* may be NULL */ + } + } + + return NULL; +} + +/** + * Find an entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is found, if known + * @return the index of the router entry, or -1 if not found + */ +static s8_t +nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) +{ + s8_t i; + + /* Look for router. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if ((default_router_list[i].neighbor_entry != NULL) && + ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && + ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { + return i; + } + } + + /* router not found. */ + return -1; +} + +/** + * Create a new entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is connected, if known + * @return the index on the router table, or -1 if could not be created + */ +static s8_t +nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) +{ + s8_t router_index; + s8_t free_router_index; + s8_t neighbor_index; + + /* Do we have a neighbor entry for this router? */ + neighbor_index = nd6_find_neighbor_cache_entry(router_addr); + if (neighbor_index < 0) { + /* Create a neighbor entry for this router. */ + neighbor_index = nd6_new_neighbor_cache_entry(); + if (neighbor_index < 0) { + /* Could not create neighbor entry for this router. */ + return -1; + } + ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); + neighbor_cache[neighbor_index].netif = netif; + neighbor_cache[neighbor_index].q = NULL; + neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; + neighbor_cache[neighbor_index].counter.probes_sent = 1; + nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST); + } + + /* Mark neighbor as router. */ + neighbor_cache[neighbor_index].isrouter = 1; + + /* Look for empty entry. */ + free_router_index = LWIP_ND6_NUM_ROUTERS; + for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { + /* check if router already exists (this is a special case for 2 netifs on the same subnet + - e.g. wifi and cable) */ + if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ + return router_index; + } + if (default_router_list[router_index].neighbor_entry == NULL) { + /* remember lowest free index to create a new entry */ + free_router_index = router_index; + } + } + if (free_router_index < LWIP_ND6_NUM_ROUTERS) { + default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); + return free_router_index; + } + + /* Could not create a router entry. */ + + /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ + neighbor_cache[neighbor_index].isrouter = 0; + + /* router not found. */ + return -1; +} + +/** + * Find the cached entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not found + */ +static s8_t +nd6_get_onlink_prefix(ip6_addr_t *prefix, struct netif *netif) +{ + s8_t i; + + /* Look for prefix in list. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && + (prefix_list[i].netif == netif)) { + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Creates a new entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not created + */ +static s8_t +nd6_new_onlink_prefix(ip6_addr_t *prefix, struct netif *netif) +{ + s8_t i; + + /* Create new entry. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((prefix_list[i].netif == NULL) || + (prefix_list[i].invalidation_timer == 0)) { + /* Found empty prefix entry. */ + prefix_list[i].netif = netif; + ip6_addr_set(&(prefix_list[i].prefix), prefix); +#if LWIP_IPV6_AUTOCONFIG + prefix_list[i].flags = 0; +#endif /* LWIP_IPV6_AUTOCONFIG */ + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Determine the next hop for a destination. Will determine if the + * destination is on-link, else a suitable on-link router is selected. + * + * The last entry index is cached for fast entry search. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the neighbor cache entry for the next hop, ERR_RTE if no + * suitable next hop was found, ERR_MEM if no cache entry + * could be created + */ +static s8_t +nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) +{ +#ifdef LWIP_HOOK_ND6_GET_GW + const ip6_addr_t *next_hop_addr; +#endif /* LWIP_HOOK_ND6_GET_GW */ + s8_t i; + +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t addr_hint = *(netif->addr_hint); + if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { + nd6_cached_destination_index = addr_hint; + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look for ip6addr in destination cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + /* the cached entry index is the right one! */ + /* do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + /* Search destination cache. */ + i = nd6_find_destination_cache_entry(ip6addr); + if (i >= 0) { + /* found destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } else { + /* Not found. Create a new destination entry. */ + i = nd6_new_destination_cache_entry(); + if (i >= 0) { + /* got new destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } else { + /* Could not create a destination cache entry. */ + return ERR_MEM; + } + + /* Copy dest address to destination cache. */ + ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); + + /* Now find the next hop. is it a neighbor? */ + if (ip6_addr_islinklocal(ip6addr) || + nd6_is_prefix_in_netif(ip6addr, netif)) { + /* Destination in local link. */ + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); +#ifdef LWIP_HOOK_ND6_GET_GW + } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { + /* Next hop for destination provided by hook function. */ + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; + ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); +#endif /* LWIP_HOOK_ND6_GET_GW */ + } else { + /* We need to select a router. */ + i = nd6_select_router(ip6addr, netif); + if (i < 0) { + /* No router found. */ + ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); + return ERR_RTE; + } + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */ + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); + } + } + } + +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + *(netif->addr_hint) = nd6_cached_destination_index; + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look in neighbor cache for the next-hop address. */ + if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), + &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + /* Cache hit. */ + /* Do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); + if (i >= 0) { + /* Found a matching record, make it new cached entry. */ + nd6_cached_neighbor_index = i; + } else { + /* Neighbor not in cache. Make a new entry. */ + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + /* got new neighbor entry. make it our new cached index. */ + nd6_cached_neighbor_index = i; + } else { + /* Could not create a neighbor cache entry. */ + return ERR_MEM; + } + + /* Initialize fields. */ + ip6_addr_copy(neighbor_cache[i].next_hop_address, + destination_cache[nd6_cached_destination_index].next_hop_addr); + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = netif; + neighbor_cache[i].state = ND6_INCOMPLETE; + neighbor_cache[i].counter.probes_sent = 1; + nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); + } + } + + /* Reset this destination's age. */ + destination_cache[nd6_cached_destination_index].age = 0; + + return nd6_cached_neighbor_index; +} + +/** + * Queue a packet for a neighbor. + * + * @param neighbor_index the index in the neighbor cache table + * @param q packet to be queued + * @return ERR_OK if succeeded, ERR_MEM if out of memory + */ +static err_t +nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) +{ + err_t result = ERR_MEM; + struct pbuf *p; + int copy_needed = 0; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *new_entry, *r; +#endif /* LWIP_ND6_QUEUEING */ + + if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { + return ERR_ARG; + } + + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + if (p->type != PBUF_ROM) { + copy_needed = 1; + break; + } + p = p->next; + } + if (copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ +#if LWIP_ND6_QUEUEING + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); +#else /* LWIP_ND6_QUEUEING */ + pbuf_free(neighbor_cache[neighbor_index].q); + neighbor_cache[neighbor_index].q = NULL; +#endif /* LWIP_ND6_QUEUEING */ + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + } + if (p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet was copied/ref'd? */ + if (p != NULL) { + /* queue packet ... */ +#if LWIP_ND6_QUEUEING + /* allocate a new nd6 queue entry */ + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; + nd6_free_q(r); + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + } + if (new_entry != NULL) { + new_entry->next = NULL; + new_entry->p = p; + if (neighbor_cache[neighbor_index].q != NULL) { + /* queue was already existent, append the new entry to the end */ + r = neighbor_cache[neighbor_index].q; + while (r->next != NULL) { + r = r->next; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + neighbor_cache[neighbor_index].q = new_entry; + } + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; + } else { + /* the pool MEMP_ND6_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); + /* { result == ERR_MEM } through initialization */ + } +#else /* LWIP_ND6_QUEUEING */ + /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ + if (neighbor_cache[neighbor_index].q != NULL) { + pbuf_free(neighbor_cache[neighbor_index].q); + } + neighbor_cache[neighbor_index].q = p; + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); + result = ERR_OK; +#endif /* LWIP_ND6_QUEUEING */ + } else { + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } + + return result; +} + +#if LWIP_ND6_QUEUEING +/** + * Free a complete queue of nd6 q entries + * + * @param q a queue of nd6_q_entry to free + */ +static void +nd6_free_q(struct nd6_q_entry *q) +{ + struct nd6_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ND6_QUEUE, r); + } +} +#endif /* LWIP_ND6_QUEUEING */ + +/** + * Send queued packets for a neighbor + * + * @param i the neighbor to send packets to + */ +static void +nd6_send_q(s8_t i) +{ + struct ip6_hdr *ip6hdr; + ip6_addr_t dest; +#if LWIP_ND6_QUEUEING + struct nd6_q_entry *q; +#endif /* LWIP_ND6_QUEUEING */ + + if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { + return; + } + +#if LWIP_ND6_QUEUEING + while (neighbor_cache[i].q != NULL) { + /* remember first in queue */ + q = neighbor_cache[i].q; + /* pop first item off the queue */ + neighbor_cache[i].q = q->next; + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(q->p->payload); + /* Create an aligned copy. */ + ip6_addr_set(&dest, &(ip6hdr->dest)); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest); + /* free the queued IP packet */ + pbuf_free(q->p); + /* now queue entry can be freed */ + memp_free(MEMP_ND6_QUEUE, q); + } +#else /* LWIP_ND6_QUEUEING */ + if (neighbor_cache[i].q != NULL) { + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); + /* Create an aligned copy. */ + ip6_addr_set(&dest, &(ip6hdr->dest)); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest); + /* free the queued IP packet */ + pbuf_free(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } +#endif /* LWIP_ND6_QUEUEING */ +} + +/** + * A packet is to be transmitted to a specific IPv6 destination on a specific + * interface. Check if we can find the hardware address of the next hop to use + * for the packet. If so, give the hardware address to the caller, which should + * use it to send the packet right away. Otherwise, enqueue the packet for + * later transmission while looking up the hardware address, if possible. + * + * As such, this function returns one of three different possible results: + * + * - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now. + * - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later. + * - not ERR_OK: something went wrong; forward the error upward in the stack. + * + * @param netif The lwIP network interface on which the IP packet will be sent. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The destination IPv6 address of the packet. + * @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning + * the packet has been queued). + * @return + * - ERR_OK on success, ERR_RTE if no route was found for the packet, + * or ERR_MEM if low memory conditions prohibit sending the packet at all. + */ +err_t +nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) +{ + s8_t i; + + /* Get next hop record. */ + i = nd6_get_next_hop_entry(ip6addr, netif); + if (i < 0) { + /* failed to get a next hop neighbor record. */ + return i; + } + + /* Now that we have a destination record, send or queue the packet. */ + if (neighbor_cache[i].state == ND6_STALE) { + /* Switch to delay state. */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; + } + /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ + if ((neighbor_cache[i].state == ND6_REACHABLE) || + (neighbor_cache[i].state == ND6_DELAY) || + (neighbor_cache[i].state == ND6_PROBE)) { + + /* Tell the caller to send out the packet now. */ + *hwaddrp = neighbor_cache[i].lladdr; + return ERR_OK; + } + + /* We should queue packet on this interface. */ + *hwaddrp = NULL; + return nd6_queue_packet(i, q); +} + + +/** + * Get the Path MTU for a destination. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the Path MTU, if known, or the netif default MTU + */ +u16_t +nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif) +{ + s8_t i; + + i = nd6_find_destination_cache_entry(ip6addr); + if (i >= 0) { + if (destination_cache[i].pmtu > 0) { + return destination_cache[i].pmtu; + } + } + + if (netif != NULL) { + return netif->mtu; + } + + return 1280; /* Minimum MTU */ +} + + +#if LWIP_ND6_TCP_REACHABILITY_HINTS +/** + * Provide the Neighbor discovery process with a hint that a + * destination is reachable. Called by tcp_receive when ACKs are + * received or sent (as per RFC). This is useful to avoid sending + * NS messages every 30 seconds. + * + * @param ip6addr the destination address which is know to be reachable + * by an upper layer protocol (TCP) + */ +void +nd6_reachability_hint(const ip6_addr_t *ip6addr) +{ + s8_t i; + + /* Find destination in cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + i = nd6_cached_destination_index; + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_destination_cache_entry(ip6addr); + } + if (i < 0) { + return; + } + + /* Find next hop neighbor in cache. */ + if (ip6_addr_cmp(&(destination_cache[i].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + i = nd6_cached_neighbor_index; + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[i].next_hop_addr)); + } + if (i < 0) { + return; + } + + /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { + return; + } + + /* Set reachability state. */ + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; +} +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +/** + * Remove all prefix, neighbor_cache and router entries of the specified netif. + * + * @param netif points to a network interface + */ +void +nd6_cleanup_netif(struct netif *netif) +{ + u8_t i; + s8_t router_index; + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].netif == netif) { + prefix_list[i].netif = NULL; + prefix_list[i].flags = 0; + } + } + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (neighbor_cache[i].netif == netif) { + for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { + if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { + default_router_list[router_index].neighbor_entry = NULL; + default_router_list[router_index].flags = 0; + } + } + neighbor_cache[i].isrouter = 0; + nd6_free_neighbor_cache_entry(i); + } + } +} + +#if LWIP_IPV6_MLD +/** + * The state of a local IPv6 address entry is about to change. If needed, join + * or leave the solicited-node multicast group for the address. + * + * @param netif The netif that owns the address. + * @param addr_idx The index of the address. + * @param new_state The new (IP6_ADDR_) state for the address. + */ +void +nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) +{ + u8_t old_state, old_member, new_member; + + old_state = netif_ip6_addr_state(netif, addr_idx); + + /* Determine whether we were, and should be, a member of the solicited-node + * multicast group for this address. For tentative addresses, the group is + * not joined until the address enters the TENTATIVE_1 (or VALID) state. */ + old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_TENTATIVE); + new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_TENTATIVE); + + if (old_member != new_member) { + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); + + if (new_member) { + mld6_joingroup_netif(netif, &multicast_address); + } else { + mld6_leavegroup_netif(netif, &multicast_address); + } + } +} +#endif /* LWIP_IPV6_MLD */ + +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/mem.c b/Sming/third-party/lwip2/lwip2-src/src/core/mem.c new file mode 100644 index 0000000000..db3b7cc54e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/mem.c @@ -0,0 +1,777 @@ +/** + * @file + * Dynamic memory manager + * + * This is a lightweight replacement for the standard C library malloc(). + * + * If you want to use the standard C library malloc() instead, define + * MEM_LIBC_MALLOC to 1 in your lwipopts.h + * + * To let mem_malloc() use pools (prevents fragmentation and is much faster than + * a heap but might waste some memory), define MEM_USE_POOLS to 1, define + * MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list + * of pools like this (more pools can be added between _START and _END): + * + * Define three pools with sizes 256, 512, and 1512 bytes + * LWIP_MALLOC_MEMPOOL_START + * LWIP_MALLOC_MEMPOOL(20, 256) + * LWIP_MALLOC_MEMPOOL(10, 512) + * LWIP_MALLOC_MEMPOOL(5, 1512) + * LWIP_MALLOC_MEMPOOL_END + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/mem.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/err.h" + +#include + +#if MEM_LIBC_MALLOC +#include /* for malloc()/free() */ +#endif + +#if MEM_LIBC_MALLOC || MEM_USE_POOLS + +/** mem_init is not used when using pools instead of a heap or using + * C library malloc(). + */ +void +mem_init(void) +{ +} + +/** mem_trim is not used when using pools instead of a heap or using + * C library malloc(): we can't free part of a pool element and the stack + * support mem_trim() to return a different pointer + */ +void* +mem_trim(void *mem, mem_size_t size) +{ + LWIP_UNUSED_ARG(size); + return mem; +} +#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */ + +#if MEM_LIBC_MALLOC +/* lwIP heap implemented using C library malloc() */ + +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_clib_free +#define mem_clib_free free +#endif +#ifndef mem_clib_malloc +#define mem_clib_malloc malloc +#endif +#ifndef mem_clib_calloc +#define mem_clib_calloc calloc +#endif + +#if LWIP_STATS && MEM_STATS +#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t)) +#else +#define MEM_LIBC_STATSHELPER_SIZE 0 +#endif + +/** + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size) +{ + void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE); + if (ret == NULL) { + MEM_STATS_INC(err); + } else { + LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret); +#if LWIP_STATS && MEM_STATS + *(mem_size_t*)ret = size; + ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE; + MEM_STATS_INC_USED(used, size); +#endif + } + return ret; +} + +/** Put memory back on the heap + * + * @param rmem is the pointer as returned by a previous call to mem_malloc() + */ +void +mem_free(void *rmem) +{ + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); +#if LWIP_STATS && MEM_STATS + rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE; + MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem); +#endif + mem_clib_free(rmem); +} + +#elif MEM_USE_POOLS + +/* lwIP heap implemented with different sized pools */ + +/** + * Allocate memory: determine the smallest pool that is big enough + * to contain an element of 'size' and get an element from that pool. + * + * @param size the size in bytes of the memory needed + * @return a pointer to the allocated memory or NULL if the pool is empty + */ +void * +mem_malloc(mem_size_t size) +{ + void *ret; + struct memp_malloc_helper *element = NULL; + memp_t poolnr; + mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + + for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { + /* is this pool big enough to hold an element of the required size + plus a struct memp_malloc_helper that saves the pool this element came from? */ + if (required_size <= memp_pools[poolnr]->size) { + element = (struct memp_malloc_helper*)memp_malloc(poolnr); + if (element == NULL) { + /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ +#if MEM_USE_POOLS_TRY_BIGGER_POOL + /** Try a bigger pool if this one is empty! */ + if (poolnr < MEMP_POOL_LAST) { + continue; + } +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ + MEM_STATS_INC(err); + return NULL; + } + break; + } + } + if (poolnr > MEMP_POOL_LAST) { + LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); + MEM_STATS_INC(err); + return NULL; + } + + /* save the pool number this element came from */ + element->poolnr = poolnr; + /* and return a pointer to the memory directly after the struct memp_malloc_helper */ + ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); + +#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) + /* truncating to u16_t is safe because struct memp_desc::size is u16_t */ + element->size = (u16_t)size; + MEM_STATS_INC_USED(used, element->size); +#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ +#if MEMP_OVERFLOW_CHECK + /* initialize unused memory (diff between requested size and selected pool's size) */ + memset((u8_t*)ret + size, 0xcd, memp_pools[poolnr]->size - size); +#endif /* MEMP_OVERFLOW_CHECK */ + return ret; +} + +/** + * Free memory previously allocated by mem_malloc. Loads the pool number + * and calls memp_free with that pool number to put the element back into + * its pool + * + * @param rmem the memory element to free + */ +void +mem_free(void *rmem) +{ + struct memp_malloc_helper *hmem; + + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); + + /* get the original struct memp_malloc_helper */ + /* cast through void* to get rid of alignment warnings */ + hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); + + LWIP_ASSERT("hmem != NULL", (hmem != NULL)); + LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); + LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); + + MEM_STATS_DEC_USED(used, hmem->size); +#if MEMP_OVERFLOW_CHECK + { + u16_t i; + LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size", + hmem->size <= memp_pools[hmem->poolnr]->size); + /* check that unused memory remained untouched (diff between requested size and selected pool's size) */ + for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) { + u8_t data = *((u8_t*)rmem + i); + LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd); + } + } +#endif /* MEMP_OVERFLOW_CHECK */ + + /* and put it in the pool we saved earlier */ + memp_free(hmem->poolnr, hmem); +} + +#else /* MEM_USE_POOLS */ +/* lwIP replacement for your libc malloc() */ + +/** + * The heap is made up as a list of structs of this type. + * This does not have to be aligned since for getting its size, + * we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns. + */ +struct mem { + /** index (-> ram[next]) of the next struct */ + mem_size_t next; + /** index (-> ram[prev]) of the previous struct */ + mem_size_t prev; + /** 1: this area is used; 0: this area is unused */ + u8_t used; +}; + +/** All allocated blocks will be MIN_SIZE bytes big, at least! + * MIN_SIZE can be overridden to suit your needs. Smaller values save space, + * larger values could prevent too small blocks to fragment the RAM too much. */ +#ifndef MIN_SIZE +#define MIN_SIZE 12 +#endif /* MIN_SIZE */ +/* some alignment macros: we define them here for better source code layout */ +#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) +#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) +#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) + +/** If you want to relocate the heap to external memory, simply define + * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. + * If so, make sure the memory at that location is big enough (see below on + * how that space is calculated). */ +#ifndef LWIP_RAM_HEAP_POINTER +/** the heap. we need one struct mem at the end and some room for alignment */ +LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U*SIZEOF_STRUCT_MEM)); +#define LWIP_RAM_HEAP_POINTER ram_heap +#endif /* LWIP_RAM_HEAP_POINTER */ + +/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ +static u8_t *ram; +/** the last entry, always unused! */ +static struct mem *ram_end; +/** pointer to the lowest free block, this is used for faster search */ +static struct mem *lfree; + +/** concurrent access protection */ +#if !NO_SYS +static sys_mutex_t mem_mutex; +#endif + +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + +static volatile u8_t mem_free_count; + +/* Allow mem_free from other (e.g. interrupt) context */ +#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) +#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) +#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) +#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) + +#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/* Protect the heap only by using a semaphore */ +#define LWIP_MEM_FREE_DECL_PROTECT() +#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) +#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) +/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ +#define LWIP_MEM_ALLOC_DECL_PROTECT() +#define LWIP_MEM_ALLOC_PROTECT() +#define LWIP_MEM_ALLOC_UNPROTECT() + +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + +/** + * "Plug holes" by combining adjacent empty struct mems. + * After this function is through, there should not exist + * one empty struct mem pointing to another empty struct mem. + * + * @param mem this points to a struct mem which just has been freed + * @internal this function is only called by mem_free() and mem_trim() + * + * This assumes access to the heap is protected by the calling function + * already. + */ +static void +plug_holes(struct mem *mem) +{ + struct mem *nmem; + struct mem *pmem; + + LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); + LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); + LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); + + /* plug hole forward */ + LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); + + nmem = (struct mem *)(void *)&ram[mem->next]; + if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { + /* if mem->next is unused and not end of ram, combine mem and mem->next */ + if (lfree == nmem) { + lfree = mem; + } + mem->next = nmem->next; + ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); + } + + /* plug hole backward */ + pmem = (struct mem *)(void *)&ram[mem->prev]; + if (pmem != mem && pmem->used == 0) { + /* if mem->prev is unused, combine mem and mem->prev */ + if (lfree == mem) { + lfree = pmem; + } + pmem->next = mem->next; + ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); + } +} + +/** + * Zero the heap and initialize start, end and lowest-free + */ +void +mem_init(void) +{ + struct mem *mem; + + LWIP_ASSERT("Sanity check alignment", + (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); + + /* align the heap */ + ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); + /* initialize the start of the heap */ + mem = (struct mem *)(void *)ram; + mem->next = MEM_SIZE_ALIGNED; + mem->prev = 0; + mem->used = 0; + /* initialize the end of the heap */ + ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; + ram_end->used = 1; + ram_end->next = MEM_SIZE_ALIGNED; + ram_end->prev = MEM_SIZE_ALIGNED; + + /* initialize the lowest-free pointer to the start of the heap */ + lfree = (struct mem *)(void *)ram; + + MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); + + if (sys_mutex_new(&mem_mutex) != ERR_OK) { + LWIP_ASSERT("failed to create mem_mutex", 0); + } +} + +/** + * Put a struct mem back on the heap + * + * @param rmem is the data portion of a struct mem as returned by a previous + * call to mem_malloc() + */ +void +mem_free(void *rmem) +{ + struct mem *mem; + LWIP_MEM_FREE_DECL_PROTECT(); + + if (rmem == NULL) { + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); + return; + } + LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); + + LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + SYS_ARCH_DECL_PROTECT(lev); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); + return; + } + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + /* Get the corresponding struct mem ... */ + /* cast through void* to get rid of alignment warnings */ + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + /* ... which has to be in a used state ... */ + LWIP_ASSERT("mem_free: mem->used", mem->used); + /* ... and is now unused. */ + mem->used = 0; + + if (mem < lfree) { + /* the newly freed struct is now the lowest */ + lfree = mem; + } + + MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); + + /* finally, see if prev or next are free also */ + plug_holes(mem); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); +} + +/** + * Shrink memory returned by mem_malloc(). + * + * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked + * @param newsize required size after shrinking (needs to be smaller than or + * equal to the previous size) + * @return for compatibility reasons: is always == rmem, at the moment + * or NULL if newsize is > old size, in which case rmem is NOT touched + * or freed! + */ +void * +mem_trim(void *rmem, mem_size_t newsize) +{ + mem_size_t size; + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; + /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ + LWIP_MEM_FREE_DECL_PROTECT(); + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + newsize = LWIP_MEM_ALIGN_SIZE(newsize); + + if (newsize < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + newsize = MIN_SIZE_ALIGNED; + } + + if (newsize > MEM_SIZE_ALIGNED) { + return NULL; + } + + LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && + (u8_t *)rmem < (u8_t *)ram_end); + + if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { + SYS_ARCH_DECL_PROTECT(lev); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); + /* protect mem stats from concurrent access */ + SYS_ARCH_PROTECT(lev); + MEM_STATS_INC(illegal); + SYS_ARCH_UNPROTECT(lev); + return rmem; + } + /* Get the corresponding struct mem ... */ + /* cast through void* to get rid of alignment warnings */ + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + /* ... and its offset pointer */ + ptr = (mem_size_t)((u8_t *)mem - ram); + + size = mem->next - ptr - SIZEOF_STRUCT_MEM; + LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); + if (newsize > size) { + /* not supported */ + return NULL; + } + if (newsize == size) { + /* No change in size, simply return */ + return rmem; + } + + /* protect the heap from concurrent access */ + LWIP_MEM_FREE_PROTECT(); + + mem2 = (struct mem *)(void *)&ram[mem->next]; + if (mem2->used == 0) { + /* The next struct is unused, we can simply move it at little */ + mem_size_t next; + /* remember the old next pointer */ + next = mem2->next; + /* create new struct mem which is moved directly after the shrinked mem */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + if (lfree == mem2) { + lfree = (struct mem *)(void *)&ram[ptr2]; + } + mem2 = (struct mem *)(void *)&ram[ptr2]; + mem2->used = 0; + /* restore the next pointer */ + mem2->next = next; + /* link it back to mem */ + mem2->prev = ptr; + /* link mem to it */ + mem->next = ptr2; + /* last thing to restore linked list: as we have moved mem2, + * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not + * the end of the heap */ + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* no need to plug holes, we've already done that */ + } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { + /* Next struct is used but there's room for another struct mem with + * at least MIN_SIZE_ALIGNED of data. + * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem + * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + mem2 = (struct mem *)(void *)&ram[ptr2]; + if (mem2 < lfree) { + lfree = mem2; + } + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + mem->next = ptr2; + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_DEC_USED(used, (size - newsize)); + /* the original mem->next is used, so no need to plug holes! */ + } + /* else { + next struct mem is used but size between mem and mem2 is not big enough + to create another struct mem + -> don't do anyhting. + -> the remaining space stays unused since it is too small + } */ +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_FREE_UNPROTECT(); + return rmem; +} + +/** + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size) +{ + mem_size_t ptr, ptr2; + struct mem *mem, *mem2; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + u8_t local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_MEM_ALLOC_DECL_PROTECT(); + + if (size == 0) { + return NULL; + } + + /* Expand the size of the allocated memory region so that we can + adjust for alignment. */ + size = LWIP_MEM_ALIGN_SIZE(size); + + if (size < MIN_SIZE_ALIGNED) { + /* every data block must be at least MIN_SIZE_ALIGNED long */ + size = MIN_SIZE_ALIGNED; + } + + if (size > MEM_SIZE_ALIGNED) { + return NULL; + } + + /* protect the heap from concurrent access */ + sys_mutex_lock(&mem_mutex); + LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* run as long as a mem_free disturbed mem_malloc or mem_trim */ + do { + local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + /* Scan through the heap searching for a free block that is big enough, + * beginning with the lowest free block. + */ + for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; + ptr = ((struct mem *)(void *)&ram[ptr])->next) { + mem = (struct mem *)(void *)&ram[ptr]; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* allow mem_free or mem_trim to run */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem. */ + local_mem_free_count = 1; + break; + } +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + if ((!mem->used) && + (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { + /* mem is not used and at least perfect fit is possible: + * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + + if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { + /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing + * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') + * -> split large block, create empty remainder, + * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if + * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, + * struct mem would fit in but no data between mem2 and mem2->next + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory + */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + /* create mem2 struct */ + mem2 = (struct mem *)(void *)&ram[ptr2]; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; + /* and insert it between mem and mem->next */ + mem->next = ptr2; + mem->used = 1; + + if (mem2->next != MEM_SIZE_ALIGNED) { + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; + } + MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); + } else { + /* (a mem2 struct does no fit into the user data space of mem and mem->next will always + * be used at this point: if not we have 2 unused structs in a row, plug_holes should have + * take care of this). + * -> near fit or exact fit: do not split, no mem2 creation + * also can't move mem->next directly behind mem, since mem->next + * will always be used at this point! + */ + mem->used = 1; + MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); + } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +mem_malloc_adjust_lfree: +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + if (mem == lfree) { + struct mem *cur = lfree; + /* Find next free block after mem and update lowest free pointer */ + while (cur->used && cur != ram_end) { +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; + LWIP_MEM_ALLOC_UNPROTECT(); + /* prevent high interrupt latency... */ + LWIP_MEM_ALLOC_PROTECT(); + if (mem_free_count != 0) { + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem or lfree. */ + goto mem_malloc_adjust_lfree; + } +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + cur = (struct mem *)(void *)&ram[cur->next]; + } + lfree = cur; + LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); + } + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", + (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); + LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", + ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); + LWIP_ASSERT("mem_malloc: sanity check alignment", + (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); + + return (u8_t *)mem + SIZEOF_STRUCT_MEM; + } + } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + /* if we got interrupted by a mem_free, try again */ + } while (local_mem_free_count != 0); +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); + MEM_STATS_INC(err); + LWIP_MEM_ALLOC_UNPROTECT(); + sys_mutex_unlock(&mem_mutex); + return NULL; +} + +#endif /* MEM_USE_POOLS */ + +#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) +void * +mem_calloc(mem_size_t count, mem_size_t size) +{ + return mem_clib_calloc(count, size); +} + +#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ +/** + * Contiguously allocates enough space for count objects that are size bytes + * of memory each and returns a pointer to the allocated memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void * +mem_calloc(mem_size_t count, mem_size_t size) +{ + void *p; + + /* allocate 'count' objects of size 'size' */ + p = mem_malloc(count * size); + if (p) { + /* zero the memory */ + memset(p, 0, (size_t)count * (size_t)size); + } + return p; +} +#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/memp.c b/Sming/third-party/lwip2/lwip2-src/src/core/memp.c new file mode 100644 index 0000000000..58fab1a20a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/memp.c @@ -0,0 +1,496 @@ +/** + * @file + * Dynamic pool memory manager + * + * lwIP has dedicated pools for many structures (netconn, protocol control blocks, + * packet buffers, ...). All these pools are managed here. + * + * @defgroup mempool Memory pools + * @ingroup infrastructure + * Custom memory pools + + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/stats.h" + +#include + +/* Make sure we include everything we need for size calculation required by memp_std.h */ +#include "lwip/pbuf.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/ip4_frag.h" +#include "lwip/netbuf.h" +#include "lwip/api.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/priv/api_msg.h" +#include "lwip/sockets.h" +#include "lwip/netifapi.h" +#include "lwip/etharp.h" +#include "lwip/igmp.h" +#include "lwip/timeouts.h" +/* needed by default MEMP_NUM_SYS_TIMEOUT */ +#include "netif/ppp/ppp_opts.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" +#include "lwip/priv/nd6_priv.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" + +#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) +#include "lwip/priv/memp_std.h" + +const struct memp_desc* const memp_pools[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, +#include "lwip/priv/memp_std.h" +}; + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2 +#undef MEMP_OVERFLOW_CHECK +/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */ +#define MEMP_OVERFLOW_CHECK 1 +#endif + +#if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC +/** + * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". + */ +static int +memp_sanity(const struct memp_desc *desc) +{ + struct memp *t, *h; + + t = *desc->tab; + if (t != NULL) { + for (h = t->next; (t != NULL) && (h != NULL); t = t->next, + h = ((h->next != NULL) ? h->next->next : NULL)) { + if (t == h) { + return 0; + } + } + } + + return 1; +} +#endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */ + +#if MEMP_OVERFLOW_CHECK +/** + * Check if a memp element was victim of an overflow + * (e.g. the restricted area after it has been altered) + * + * @param p the memp element to check + * @param desc the pool p comes from + */ +static void +memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc) +{ +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + u16_t k; + u8_t *m; + m = (u8_t*)p + MEMP_SIZE + desc->size; + for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128] = "detected memp overflow in pool "; + strcat(errstr, desc->desc); + LWIP_ASSERT(errstr, 0); + } + } +#else /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(desc); +#endif /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */ +} + +/** + * Check if a memp element was victim of an underflow + * (e.g. the restricted area before it has been altered) + * + * @param p the memp element to check + * @param desc the pool p comes from + */ +static void +memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc) +{ +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 + u16_t k; + u8_t *m; + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; + for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { + if (m[k] != 0xcd) { + char errstr[128] = "detected memp underflow in pool "; + strcat(errstr, desc->desc); + LWIP_ASSERT(errstr, 0); + } + } +#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(desc); +#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */ +} + +/** + * Initialize the restricted area of on memp element. + */ +static void +memp_overflow_init_element(struct memp *p, const struct memp_desc *desc) +{ +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + u8_t *m; +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; + memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); +#endif +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE + desc->size; + memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); +#endif +#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(desc); +#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */ +} + +#if MEMP_OVERFLOW_CHECK >= 2 +/** + * Do an overflow check for all elements in every pool. + * + * @see memp_overflow_check_element for a description of the check + */ +static void +memp_overflow_check_all(void) +{ + u16_t i, j; + struct memp *p; + SYS_ARCH_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + + for (i = 0; i < MEMP_MAX; ++i) { + p = (struct memp*)LWIP_MEM_ALIGN(memp_pools[i]->base); + for (j = 0; j < memp_pools[i]->num; ++j) { + memp_overflow_check_element_overflow(p, memp_pools[i]); + memp_overflow_check_element_underflow(p, memp_pools[i]); + p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED)); + } + } + SYS_ARCH_UNPROTECT(old_level); +} +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +#endif /* MEMP_OVERFLOW_CHECK */ + +/** + * Initialize custom memory pool. + * Related functions: memp_malloc_pool, memp_free_pool + * + * @param desc pool to initialize + */ +void +memp_init_pool(const struct memp_desc *desc) +{ +#if MEMP_MEM_MALLOC + LWIP_UNUSED_ARG(desc); +#else + int i; + struct memp *memp; + + *desc->tab = NULL; + memp = (struct memp*)LWIP_MEM_ALIGN(desc->base); + /* create a linked list of memp elements */ + for (i = 0; i < desc->num; ++i) { + memp->next = *desc->tab; + *desc->tab = memp; +#if MEMP_OVERFLOW_CHECK + memp_overflow_init_element(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + /* cast through void* to get rid of alignment warnings */ + memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size +#if MEMP_OVERFLOW_CHECK + + MEMP_SANITY_REGION_AFTER_ALIGNED +#endif + ); + } +#if MEMP_STATS + desc->stats->avail = desc->num; +#endif /* MEMP_STATS */ +#endif /* !MEMP_MEM_MALLOC */ + +#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) + desc->stats->name = desc->desc; +#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */ +} + +/** + * Initializes lwIP built-in pools. + * Related functions: memp_malloc, memp_free + * + * Carves out memp_memory into linked lists for each pool-type. + */ +void +memp_init(void) +{ + u16_t i; + + /* for every pool: */ + for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) { + memp_init_pool(memp_pools[i]); + +#if LWIP_STATS && MEMP_STATS + lwip_stats.memp[i] = memp_pools[i]->stats; +#endif + } + +#if MEMP_OVERFLOW_CHECK >= 2 + /* check everything a first time to see if it worked */ + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +} + +static void* +#if !MEMP_OVERFLOW_CHECK +do_memp_malloc_pool(const struct memp_desc *desc) +#else +do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line) +#endif +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + +#if MEMP_MEM_MALLOC + memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size)); + SYS_ARCH_PROTECT(old_level); +#else /* MEMP_MEM_MALLOC */ + SYS_ARCH_PROTECT(old_level); + + memp = *desc->tab; +#endif /* MEMP_MEM_MALLOC */ + + if (memp != NULL) { +#if !MEMP_MEM_MALLOC +#if MEMP_OVERFLOW_CHECK == 1 + memp_overflow_check_element_overflow(memp, desc); + memp_overflow_check_element_underflow(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + + *desc->tab = memp->next; +#if MEMP_OVERFLOW_CHECK + memp->next = NULL; +#endif /* MEMP_OVERFLOW_CHECK */ +#endif /* !MEMP_MEM_MALLOC */ +#if MEMP_OVERFLOW_CHECK + memp->file = file; + memp->line = line; +#if MEMP_MEM_MALLOC + memp_overflow_init_element(memp, desc); +#endif /* MEMP_MEM_MALLOC */ +#endif /* MEMP_OVERFLOW_CHECK */ + LWIP_ASSERT("memp_malloc: memp properly aligned", + ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); +#if MEMP_STATS + desc->stats->used++; + if (desc->stats->used > desc->stats->max) { + desc->stats->max = desc->stats->used; + } +#endif + SYS_ARCH_UNPROTECT(old_level); + /* cast through u8_t* to get rid of alignment warnings */ + return ((u8_t*)memp + MEMP_SIZE); + } else { + LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc)); +#if MEMP_STATS + desc->stats->err++; +#endif + } + + SYS_ARCH_UNPROTECT(old_level); + return NULL; +} + +/** + * Get an element from a custom pool. + * + * @param desc the pool to get an element from + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc_pool(const struct memp_desc *desc) +#else +memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line) +#endif +{ + LWIP_ASSERT("invalid pool desc", desc != NULL); + if (desc == NULL) { + return NULL; + } + +#if !MEMP_OVERFLOW_CHECK + return do_memp_malloc_pool(desc); +#else + return do_memp_malloc_pool_fn(desc, file, line); +#endif +} + +/** + * Get an element from a specific pool. + * + * @param type the pool to get an element from + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc(memp_t type) +#else +memp_malloc_fn(memp_t type, const char* file, const int line) +#endif +{ + void *memp; + LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); + +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + +#if !MEMP_OVERFLOW_CHECK + memp = do_memp_malloc_pool(memp_pools[type]); +#else + memp = do_memp_malloc_pool_fn(memp_pools[type], file, line); +#endif + + return memp; +} + +static void +do_memp_free_pool(const struct memp_desc* desc, void *mem) +{ + struct memp *memp; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("memp_free: mem properly aligned", + ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); + + /* cast through void* to get rid of alignment warnings */ + memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); + + SYS_ARCH_PROTECT(old_level); + +#if MEMP_OVERFLOW_CHECK == 1 + memp_overflow_check_element_overflow(memp, desc); + memp_overflow_check_element_underflow(memp, desc); +#endif /* MEMP_OVERFLOW_CHECK */ + +#if MEMP_STATS + desc->stats->used--; +#endif + +#if MEMP_MEM_MALLOC + LWIP_UNUSED_ARG(desc); + SYS_ARCH_UNPROTECT(old_level); + mem_free(memp); +#else /* MEMP_MEM_MALLOC */ + memp->next = *desc->tab; + *desc->tab = memp; + +#if MEMP_SANITY_CHECK + LWIP_ASSERT("memp sanity", memp_sanity(desc)); +#endif /* MEMP_SANITY_CHECK */ + + SYS_ARCH_UNPROTECT(old_level); +#endif /* !MEMP_MEM_MALLOC */ +} + +/** + * Put a custom pool element back into its pool. + * + * @param desc the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free_pool(const struct memp_desc* desc, void *mem) +{ + LWIP_ASSERT("invalid pool desc", desc != NULL); + if ((desc == NULL) || (mem == NULL)) { + return; + } + + do_memp_free_pool(desc, mem); +} + +/** + * Put an element back into its pool. + * + * @param type the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free(memp_t type, void *mem) +{ +#ifdef LWIP_HOOK_MEMP_AVAILABLE + struct memp *old_first; +#endif + + LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;); + + if (mem == NULL) { + return; + } + +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + +#ifdef LWIP_HOOK_MEMP_AVAILABLE + old_first = *memp_pools[type]->tab; +#endif + + do_memp_free_pool(memp_pools[type], mem); + +#ifdef LWIP_HOOK_MEMP_AVAILABLE + if (old_first == NULL) { + LWIP_HOOK_MEMP_AVAILABLE(type); + } +#endif +} diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/netif.c b/Sming/third-party/lwip2/lwip2-src/src/core/netif.c new file mode 100644 index 0000000000..428b148421 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/netif.c @@ -0,0 +1,1265 @@ +/** + * @file + * lwIP network interface abstraction + * + * @defgroup netif Network interface (NETIF) + * @ingroup callbackstyle_api + * + * @defgroup netif_ip4 IPv4 address handling + * @ingroup netif + * + * @defgroup netif_ip6 IPv6 address handling + * @ingroup netif + * + * @defgroup netif_cd Client data handling + * Store data (void*) on a netif for application usage. + * @see @ref LWIP_NUM_NETIF_CLIENT_DATA + * @ingroup netif + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#include "lwip/opt.h" + +#include + +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/udp.h" +#include "lwip/raw.h" +#include "lwip/snmp.h" +#include "lwip/igmp.h" +#include "lwip/etharp.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/ip.h" +#if ENABLE_LOOPBACK +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/tcpip.h" +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#include "netif/ethernet.h" + +#if LWIP_AUTOIP +#include "lwip/autoip.h" +#endif /* LWIP_AUTOIP */ +#if LWIP_DHCP +#include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ +#if LWIP_IPV6 +#include "lwip/nd6.h" +#endif + +#if LWIP_NETIF_STATUS_CALLBACK +#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) +#else +#define NETIF_STATUS_CALLBACK(n) +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) +#else +#define NETIF_LINK_CALLBACK(n) +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +struct netif *netif_list; +struct netif *netif_default; + +static u8_t netif_num; + +#if LWIP_NUM_NETIF_CLIENT_DATA > 0 +static u8_t netif_client_id; +#endif + +#define NETIF_REPORT_TYPE_IPV4 0x01 +#define NETIF_REPORT_TYPE_IPV6 0x02 +static void netif_issue_reports(struct netif* netif, u8_t report_type); + +#if LWIP_IPV6 +static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ + +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t* addr); +#endif +#if LWIP_IPV6 +static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t* addr); +#endif + + +static struct netif loop_netif; + +/** + * Initialize a lwip network interface structure for a loopback interface + * + * @param netif the lwip network interface structure for this loopif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + */ +static err_t +netif_loopif_init(struct netif *netif) +{ + /* initialize the snmp variables and counters inside the struct netif + * ifSpeed: no assumption can be made! + */ + MIB2_INIT_NETIF(netif, snmp_ifType_softwareLoopback, 0); + + netif->name[0] = 'l'; + netif->name[1] = 'o'; +#if LWIP_IPV4 + netif->output = netif_loop_output_ipv4; +#endif +#if LWIP_IPV6 + netif->output_ip6 = netif_loop_output_ipv6; +#endif +#if LWIP_LOOPIF_MULTICAST + netif->flags |= NETIF_FLAG_IGMP; +#endif + return ERR_OK; +} +#endif /* LWIP_HAVE_LOOPIF */ + +void +netif_init(void) +{ +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +#define LOOPIF_ADDRINIT &loop_ipaddr, &loop_netmask, &loop_gw, + ip4_addr_t loop_ipaddr, loop_netmask, loop_gw; + IP4_ADDR(&loop_gw, 127,0,0,1); + IP4_ADDR(&loop_ipaddr, 127,0,0,1); + IP4_ADDR(&loop_netmask, 255,0,0,0); +#else /* LWIP_IPV4 */ +#define LOOPIF_ADDRINIT +#endif /* LWIP_IPV4 */ + +#if NO_SYS + netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input); +#else /* NO_SYS */ + netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input); +#endif /* NO_SYS */ + +#if LWIP_IPV6 + IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL); + loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; +#endif /* LWIP_IPV6 */ + + netif_set_link_up(&loop_netif); + netif_set_up(&loop_netif); + +#endif /* LWIP_HAVE_LOOPIF */ +} + +/** + * @ingroup lwip_nosys + * Forwards a received packet for input processing with + * ethernet_input() or ip_input() depending on netif flags. + * Don't call directly, pass to netif_add() and call + * netif->input(). + * Only works if the netif driver correctly sets + * NETIF_FLAG_ETHARP and/or NETIF_FLAG_ETHERNET flag! + */ +err_t +netif_input(struct pbuf *p, struct netif *inp) +{ +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + return ethernet_input(p, inp); + } else +#endif /* LWIP_ETHERNET */ + return ip_input(p, inp); +} + +/** + * @ingroup netif + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack.\n + * It is recommended to use a function that passes the input directly + * to the stack (netif_input(), NO_SYS=1 mode) or via sending a + * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).\n + * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET + * to decide whether to forward to ethernet_input() or ip_input(). + * In other words, the functions only work when the netif + * driver is implemented correctly!\n + * Most members of struct netif should be be initialized by the + * netif init function = netif driver (init parameter of this function).\n + * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after + * setting the MAC address in struct netif.hwaddr + * (IPv6 requires a link-local address). + * + * @return netif, or NULL if failed. + */ +struct netif * +netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input) +{ +#if LWIP_IPV6 + s8_t i; +#endif + + LWIP_ASSERT("No init function given", init != NULL); + + /* reset new interface configuration state */ +#if LWIP_IPV4 + ip_addr_set_zero_ip4(&netif->ip_addr); + ip_addr_set_zero_ip4(&netif->netmask); + ip_addr_set_zero_ip4(&netif->gw); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + ip_addr_set_zero_ip6(&netif->ip6_addr[i]); + netif->ip6_addr_state[i] = IP6_ADDR_INVALID; + } + netif->output_ip6 = netif_null_output_ip6; +#endif /* LWIP_IPV6 */ + NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); + netif->flags = 0; +#ifdef netif_get_client_data + memset(netif->client_data, 0, sizeof(netif->client_data)); +#endif /* LWIP_NUM_NETIF_CLIENT_DATA */ +#if LWIP_IPV6_AUTOCONFIG + /* IPv6 address autoconfiguration not enabled by default */ + netif->ip6_autoconfig_enabled = 0; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_NETIF_STATUS_CALLBACK + netif->status_callback = NULL; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + netif->link_callback = NULL; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_IGMP + netif->igmp_mac_filter = NULL; +#endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->mld_mac_filter = NULL; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if ENABLE_LOOPBACK + netif->loop_first = NULL; + netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK */ + + /* remember netif specific state information data */ + netif->state = state; + netif->num = netif_num++; + netif->input = input; + + NETIF_SET_HWADDRHINT(netif, NULL); +#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS + netif->loop_cnt_current = 0; +#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ + +#if LWIP_IPV4 + netif_set_addr(netif, ipaddr, netmask, gw); +#endif /* LWIP_IPV4 */ + + /* call user specified initialization function for netif */ + if (init(netif) != ERR_OK) { + return NULL; + } + + /* add this netif to the list */ + netif->next = netif_list; + netif_list = netif; + mib2_netif_added(netif); + +#if LWIP_IGMP + /* start IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_start(netif); + } +#endif /* LWIP_IGMP */ + + LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP", + netif->name[0], netif->name[1])); +#if LWIP_IPV4 + LWIP_DEBUGF(NETIF_DEBUG, (" addr ")); + ip4_addr_debug_print(NETIF_DEBUG, ipaddr); + LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); + ip4_addr_debug_print(NETIF_DEBUG, netmask); + LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); + ip4_addr_debug_print(NETIF_DEBUG, gw); +#endif /* LWIP_IPV4 */ + LWIP_DEBUGF(NETIF_DEBUG, ("\n")); + return netif; +} + +#if LWIP_IPV4 +/** + * @ingroup netif_ip4 + * Change IP address configuration for a network interface (including netmask + * and default gateway). + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * @param netmask the new netmask + * @param gw the new default gateway + */ +void +netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, + const ip4_addr_t *gw) +{ + if (ip4_addr_isany(ipaddr)) { + /* when removing an address, we have to remove it *before* changing netmask/gw + to ensure that tcp RST segment can be sent correctly */ + netif_set_ipaddr(netif, ipaddr); + netif_set_netmask(netif, netmask); + netif_set_gw(netif, gw); + } else { + netif_set_netmask(netif, netmask); + netif_set_gw(netif, gw); + /* set ipaddr last to ensure netmask/gw have been set when status callback is called */ + netif_set_ipaddr(netif, ipaddr); + } +} +#endif /* LWIP_IPV4*/ + +/** + * @ingroup netif + * Remove a network interface from the list of lwIP netifs. + * + * @param netif the network interface to remove + */ +void +netif_remove(struct netif *netif) +{ +#if LWIP_IPV6 + int i; +#endif + + if (netif == NULL) { + return; + } + +#if LWIP_IPV4 + if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) { +#if LWIP_TCP + tcp_netif_ip_addr_changed(netif_ip_addr4(netif), NULL); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(netif_ip_addr4(netif), NULL); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(netif_ip_addr4(netif), NULL); +#endif /* LWIP_RAW */ + } + +#if LWIP_IGMP + /* stop IGMP processing */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_stop(netif); + } +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) { +#if LWIP_TCP + tcp_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(netif_ip_addr6(netif, i), NULL); +#endif /* LWIP_RAW */ + } + } +#if LWIP_IPV6_MLD + /* stop MLD processing */ + mld6_stop(netif); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + if (netif_is_up(netif)) { + /* set netif down before removing (call callback function) */ + netif_set_down(netif); + } + + mib2_remove_ip4(netif); + + /* this netif is default? */ + if (netif_default == netif) { + /* reset default netif */ + netif_set_default(NULL); + } + /* is it the first netif? */ + if (netif_list == netif) { + netif_list = netif->next; + } else { + /* look for netif further down the list */ + struct netif * tmp_netif; + for (tmp_netif = netif_list; tmp_netif != NULL; tmp_netif = tmp_netif->next) { + if (tmp_netif->next == netif) { + tmp_netif->next = netif->next; + break; + } + } + if (tmp_netif == NULL) { + return; /* netif is not on the list */ + } + } + mib2_netif_removed(netif); +#if LWIP_NETIF_REMOVE_CALLBACK + if (netif->remove_callback) { + netif->remove_callback(netif); + } +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); +} + +/** + * @ingroup netif + * Find a network interface by searching for its name + * + * @param name the name of the netif (like netif->name) plus concatenated number + * in ascii representation (e.g. 'en0') + */ +struct netif * +netif_find(const char *name) +{ + struct netif *netif; + u8_t num; + + if (name == NULL) { + return NULL; + } + + num = (u8_t)(name[2] - '0'); + + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (num == netif->num && + name[0] == netif->name[0] && + name[1] == netif->name[1]) { + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); + return netif; + } + } + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); + return NULL; +} + +#if LWIP_IPV4 +/** + * @ingroup netif_ip4 + * Change the IP address of a network interface + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * + * @note call netif_set_addr() if you also want to change netmask and + * default gateway + */ +void +netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr) +{ + ip_addr_t new_addr; + *ip_2_ip4(&new_addr) = (ipaddr ? *ipaddr : *IP4_ADDR_ANY4); + IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4); + + /* address is actually being changed? */ + if (ip4_addr_cmp(ip_2_ip4(&new_addr), netif_ip4_addr(netif)) == 0) { + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); +#if LWIP_TCP + tcp_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(netif_ip_addr4(netif), &new_addr); +#endif /* LWIP_RAW */ + + mib2_remove_ip4(netif); + mib2_remove_route_ip4(0, netif); + /* set new IP address to netif */ + ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr); + IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4); + mib2_add_ip4(netif); + mib2_add_route_ip4(0, netif); + + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4); + + NETIF_STATUS_CALLBACK(netif); + } + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(netif_ip4_addr(netif)), + ip4_addr2_16(netif_ip4_addr(netif)), + ip4_addr3_16(netif_ip4_addr(netif)), + ip4_addr4_16(netif_ip4_addr(netif)))); +} + +/** + * @ingroup netif_ip4 + * Change the default gateway for a network interface + * + * @param netif the network interface to change + * @param gw the new default gateway + * + * @note call netif_set_addr() if you also want to change ip address and netmask + */ +void +netif_set_gw(struct netif *netif, const ip4_addr_t *gw) +{ + ip4_addr_set(ip_2_ip4(&netif->gw), gw); + IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(netif_ip4_gw(netif)), + ip4_addr2_16(netif_ip4_gw(netif)), + ip4_addr3_16(netif_ip4_gw(netif)), + ip4_addr4_16(netif_ip4_gw(netif)))); +} + +/** + * @ingroup netif_ip4 + * Change the netmask of a network interface + * + * @param netif the network interface to change + * @param netmask the new netmask + * + * @note call netif_set_addr() if you also want to change ip address and + * default gateway + */ +void +netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask) +{ + mib2_remove_route_ip4(0, netif); + /* set new netmask to netif */ + ip4_addr_set(ip_2_ip4(&netif->netmask), netmask); + IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4); + mib2_add_route_ip4(0, netif); + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + netif->name[0], netif->name[1], + ip4_addr1_16(netif_ip4_netmask(netif)), + ip4_addr2_16(netif_ip4_netmask(netif)), + ip4_addr3_16(netif_ip4_netmask(netif)), + ip4_addr4_16(netif_ip4_netmask(netif)))); +} +#endif /* LWIP_IPV4 */ + +/** + * @ingroup netif + * Set a network interface as the default network interface + * (used to output all packets for which no specific route is found) + * + * @param netif the default network interface + */ +void +netif_set_default(struct netif *netif) +{ + if (netif == NULL) { + /* remove default route */ + mib2_remove_route_ip4(1, netif); + } else { + /* install default route */ + mib2_add_route_ip4(1, netif); + } + netif_default = netif; + LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", + netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); +} + +/** + * @ingroup netif + * Bring an interface up, available for processing + * traffic. + */ +void +netif_set_up(struct netif *netif) +{ + if (!(netif->flags & NETIF_FLAG_UP)) { + netif->flags |= NETIF_FLAG_UP; + + MIB2_COPY_SYSUPTIME_TO(&netif->ts); + + NETIF_STATUS_CALLBACK(netif); + + if (netif->flags & NETIF_FLAG_LINK_UP) { + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4|NETIF_REPORT_TYPE_IPV6); + } + } +} + +/** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change + */ +static void +netif_issue_reports(struct netif* netif, u8_t report_type) +{ +#if LWIP_IPV4 + if ((report_type & NETIF_REPORT_TYPE_IPV4) && + !ip4_addr_isany_val(*netif_ip4_addr(netif))) { +#if LWIP_ARP + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & (NETIF_FLAG_ETHARP)) { + etharp_gratuitous(netif); + } +#endif /* LWIP_ARP */ + +#if LWIP_IGMP + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups(netif); + } +#endif /* LWIP_IGMP */ + } +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 + if (report_type & NETIF_REPORT_TYPE_IPV6) { +#if LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups(netif); +#endif /* LWIP_IPV6_MLD */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send Router Solicitation messages. */ + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + } +#endif /* LWIP_IPV6 */ +} + +/** + * @ingroup netif + * Bring an interface down, disabling any traffic processing. + */ +void +netif_set_down(struct netif *netif) +{ + if (netif->flags & NETIF_FLAG_UP) { + netif->flags &= ~NETIF_FLAG_UP; + MIB2_COPY_SYSUPTIME_TO(&netif->ts); + +#if LWIP_IPV4 && LWIP_ARP + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_cleanup_netif(netif); + } +#endif /* LWIP_IPV4 && LWIP_ARP */ + +#if LWIP_IPV6 + nd6_cleanup_netif(netif); +#endif /* LWIP_IPV6 */ + + NETIF_STATUS_CALLBACK(netif); + } +} + +#if LWIP_NETIF_STATUS_CALLBACK +/** + * @ingroup netif + * Set callback to be called when interface is brought up/down or address is changed while up + */ +void +netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) +{ + if (netif) { + netif->status_callback = status_callback; + } +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_REMOVE_CALLBACK +/** + * @ingroup netif + * Set callback to be called when the interface has been removed + */ +void +netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) +{ + if (netif) { + netif->remove_callback = remove_callback; + } +} +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +/** + * @ingroup netif + * Called by a driver when its link goes up + */ +void +netif_set_link_up(struct netif *netif) +{ + if (!(netif->flags & NETIF_FLAG_LINK_UP)) { + netif->flags |= NETIF_FLAG_LINK_UP; + +#if LWIP_DHCP + dhcp_network_changed(netif); +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP + autoip_network_changed(netif); +#endif /* LWIP_AUTOIP */ + + if (netif->flags & NETIF_FLAG_UP) { + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4|NETIF_REPORT_TYPE_IPV6); + } + NETIF_LINK_CALLBACK(netif); + } +} + +/** + * @ingroup netif + * Called by a driver when its link goes down + */ +void +netif_set_link_down(struct netif *netif ) +{ + if (netif->flags & NETIF_FLAG_LINK_UP) { + netif->flags &= ~NETIF_FLAG_LINK_UP; + NETIF_LINK_CALLBACK(netif); + } +} + +#if LWIP_NETIF_LINK_CALLBACK +/** + * @ingroup netif + * Set callback to be called when link is brought up/down + */ +void +netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) +{ + if (netif) { + netif->link_callback = link_callback; + } +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * @ingroup netif + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is simply copied and handed back to netif->input. + * In multithreaded mode, this is done directly since netif->input must put + * the packet on a queue. + * In callback mode, the packet is put on an internal queue and is fed to + * netif->input by netif_poll(). + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @return ERR_OK if the packet has been sent + * ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p) +{ + struct pbuf *r; + err_t err; + struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if MIB2_STATS +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* MIB2_STATS */ + SYS_ARCH_DECL_PROTECT(lev); + + /* Allocate a new pbuf */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return ERR_MEM; + } +#if LWIP_LOOPBACK_MAX_PBUFS + clen = pbuf_clen(r); + /* check for overflow or too many pbuf on queue */ + if (((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || + ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return ERR_MEM; + } + netif->loop_cnt_current += clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* Copy the whole pbuf queue p into the single pbuf r */ + if ((err = pbuf_copy(r, p)) != ERR_OK) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards); + return err; + } + + /* Put the packet on a linked list which gets emptied through calling + netif_poll(). */ + + /* let last point to the last pbuf in chain r */ + for (last = r; last->next != NULL; last = last->next); + + SYS_ARCH_PROTECT(lev); + if (netif->loop_first != NULL) { + LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); + netif->loop_last->next = r; + netif->loop_last = last; + } else { + netif->loop_first = r; + netif->loop_last = last; + } + SYS_ARCH_UNPROTECT(lev); + + LINK_STATS_INC(link.xmit); + MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len); + MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* For multithreading environment, schedule a call to netif_poll */ + tcpip_callback_with_block((tcpip_callback_fn)netif_poll, netif, 0); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + + return ERR_OK; +} + +#if LWIP_HAVE_LOOPIF +#if LWIP_IPV4 +static err_t +netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t* addr) +{ + LWIP_UNUSED_ARG(addr); + return netif_loop_output(netif, p); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +static err_t +netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t* addr) +{ + LWIP_UNUSED_ARG(addr); + return netif_loop_output(netif, p); +} +#endif /* LWIP_IPV6 */ +#endif /* LWIP_HAVE_LOOPIF */ + + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if MIB2_STATS +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* MIB2_STATS */ + SYS_ARCH_DECL_PROTECT(lev); + + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + while (netif->loop_first != NULL) { + struct pbuf *in, *in_end; +#if LWIP_LOOPBACK_MAX_PBUFS + u8_t clen = 1; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + in = in_end = netif->loop_first; + while (in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; +#if LWIP_LOOPBACK_MAX_PBUFS + clen++; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + } +#if LWIP_LOOPBACK_MAX_PBUFS + /* adjust the number of pbufs on queue */ + LWIP_ASSERT("netif->loop_cnt_current underflow", + ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); + netif->loop_cnt_current -= clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + + /* 'in_end' now points to the last pbuf from 'in' */ + if (in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; + SYS_ARCH_UNPROTECT(lev); + + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len); + MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts); + /* loopback packets are always IP packets! */ + if (ip_input(in, netif) != ERR_OK) { + pbuf_free(in); + } + SYS_ARCH_PROTECT(lev); + } + SYS_ARCH_UNPROTECT(lev); +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ + struct netif *netif = netif_list; + /* loop through netifs */ + while (netif != NULL) { + netif_poll(netif); + /* proceed to next network interface */ + netif = netif->next; + } +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_NUM_NETIF_CLIENT_DATA > 0 +/** + * @ingroup netif_cd + * Allocate an index to store data in client_data member of struct netif. + * Returned value is an index in mentioned array. + * @see LWIP_NUM_NETIF_CLIENT_DATA + */ +u8_t +netif_alloc_client_data_id(void) +{ + u8_t result = netif_client_id; + netif_client_id++; + + LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA); + return result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX; +} +#endif + +#if LWIP_IPV6 +/** + * @ingroup netif_ip6 + * Change an IPv6 address of a network interface + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param addr6 the new IPv6 address + * + * @note call netif_ip6_addr_set_state() to set the address valid/temptative + */ +void +netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6) +{ + LWIP_ASSERT("addr6 != NULL", addr6 != NULL); + netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1], + addr6->addr[2], addr6->addr[3]); +} + +/* + * Change an IPv6 address of a network interface (internal version taking 4 * u32_t) + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param i0 word0 of the new IPv6 address + * @param i1 word1 of the new IPv6 address + * @param i2 word2 of the new IPv6 address + * @param i3 word3 of the new IPv6 address + */ +void +netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3) +{ + const ip6_addr_t *old_addr; + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); + + old_addr = netif_ip6_addr(netif, addr_idx); + /* address is actually being changed? */ + if ((old_addr->addr[0] != i0) || (old_addr->addr[1] != i1) || + (old_addr->addr[2] != i2) || (old_addr->addr[3] != i3)) { + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n")); + + if (netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) { +#if LWIP_TCP || LWIP_UDP + ip_addr_t new_ipaddr; + IP_ADDR6(&new_ipaddr, i0, i1, i2, i3); +#endif /* LWIP_TCP || LWIP_UDP */ +#if LWIP_TCP + tcp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr); +#endif /* LWIP_RAW */ + } + /* @todo: remove/readd mib2 ip6 entries? */ + + IP6_ADDR(ip_2_ip6(&(netif->ip6_addr[addr_idx])), i0, i1, i2, i3); + IP_SET_TYPE_VAL(netif->ip6_addr[addr_idx], IPADDR_TYPE_V6); + + if (netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) { + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); + NETIF_STATUS_CALLBACK(netif); + } + } + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", + addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), + netif_ip6_addr_state(netif, addr_idx))); +} + +/** + * @ingroup netif_ip6 + * Change the state of an IPv6 address of a network interface + * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE + * includes the number of checks done, see ip6_addr.h) + * + * @param netif the network interface to change + * @param addr_idx index of the IPv6 address + * @param state the new IPv6 address state + */ +void +netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state) +{ + u8_t old_state; + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES); + + old_state = netif_ip6_addr_state(netif, addr_idx); + /* state is actually being changed? */ + if (old_state != state) { + u8_t old_valid = old_state & IP6_ADDR_VALID; + u8_t new_valid = state & IP6_ADDR_VALID; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n")); + +#if LWIP_IPV6_MLD + /* Reevaluate solicited-node multicast group membership. */ + if (netif->flags & NETIF_FLAG_MLD6) { + nd6_adjust_mld_membership(netif, addr_idx, state); + } +#endif /* LWIP_IPV6_MLD */ + + if (old_valid && !new_valid) { + /* address about to be removed by setting invalid */ +#if LWIP_TCP + tcp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); +#endif /* LWIP_TCP */ +#if LWIP_UDP + udp_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); +#endif /* LWIP_UDP */ +#if LWIP_RAW + raw_netif_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL); +#endif /* LWIP_RAW */ + /* @todo: remove mib2 ip6 entries? */ + } + netif->ip6_addr_state[addr_idx] = state; + + if (!old_valid && new_valid) { + /* address added by setting valid */ + /* @todo: add mib2 ip6 entries? */ + netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6); + } + if ((old_state & IP6_ADDR_PREFERRED) != (state & IP6_ADDR_PREFERRED)) { + /* address state has changed (valid flag changed or switched between + preferred and deprecated) -> call the callback function */ + NETIF_STATUS_CALLBACK(netif); + } + } + + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n", + addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)), + netif_ip6_addr_state(netif, addr_idx))); +} + +/** + * Checks if a specific address is assigned to the netif and returns its + * index. + * + * @param netif the netif to check + * @param ip6addr the IPv6 address to find + * @return >= 0: address found, this is its index + * -1: address not found on this netif + */ +s8_t +netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) { + return i; + } + } + return -1; +} + +/** + * @ingroup netif_ip6 + * Create a link-local IPv6 address on a netif (stored in slot 0) + * + * @param netif the netif to create the address on + * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion) + * if == 0, use hwaddr directly as interface ID + */ +void +netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit) +{ + u8_t i, addr_index; + + /* Link-local prefix. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul); + ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0; + + /* Generate interface ID. */ + if (from_mac_48bit) { + /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | + ((u32_t)(netif->hwaddr[1]) << 16) | + ((u32_t)(netif->hwaddr[2]) << 8) | + (0xff)); + ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((0xfeul << 24) | + ((u32_t)(netif->hwaddr[3]) << 16) | + ((u32_t)(netif->hwaddr[4]) << 8) | + (netif->hwaddr[5])); + } else { + /* Use hwaddr directly as interface ID. */ + ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0; + ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0; + + addr_index = 3; + for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) { + if (i == 4) { + addr_index--; + } + ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)); + } + } + + /* Set address state. */ +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* Will perform duplicate address detection (DAD). */ + netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE); +#else + /* Consider address valid. */ + netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED); +#endif /* LWIP_IPV6_AUTOCONFIG */ +} + +/** + * @ingroup netif_ip6 + * This function allows for the easy addition of a new IPv6 address to an interface. + * It takes care of finding an empty slot and then sets the address tentative + * (to make sure that all the subsequent processing happens). + * + * @param netif netif to add the address on + * @param ip6addr address to add + * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here + */ +err_t +netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx) +{ + s8_t i; + + i = netif_get_ip6_addr_match(netif, ip6addr); + if (i >= 0) { + /* Address already added */ + if (chosen_idx != NULL) { + *chosen_idx = i; + } + return ERR_OK; + } + + /* Find a free slot -- musn't be the first one (reserved for link local) */ + for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { + ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr); + netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE); + if (chosen_idx != NULL) { + *chosen_idx = i; + } + return ERR_OK; + } + } + + if (chosen_idx != NULL) { + *chosen_idx = -1; + } + return ERR_VAL; +} + +/** Dummy IPv6 output function for netifs not supporting IPv6 + */ +static err_t +netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(ipaddr); + + return ERR_IF; +} +#endif /* LWIP_IPV6 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/pbuf.c b/Sming/third-party/lwip2/lwip2-src/src/core/pbuf.c new file mode 100644 index 0000000000..059f83a571 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/pbuf.c @@ -0,0 +1,1442 @@ +/** + * @file + * Packet buffer management + */ + +/** + * @defgroup pbuf Packet buffers (PBUF) + * @ingroup infrastructure + * + * Packets are built from the pbuf data structure. It supports dynamic + * memory allocation for packet contents or can reference externally + * managed packet contents both in RAM and ROM. Quick allocation for + * incoming packets is provided through pools with fixed sized pbufs. + * + * A packet may span over multiple pbufs, chained as a singly linked + * list. This is called a "pbuf chain". + * + * Multiple packets may be queued, also using this singly linked list. + * This is called a "packet queue". + * + * So, a packet queue consists of one or more pbuf chains, each of + * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE + * NOT SUPPORTED!!! Use helper structs to queue multiple packets. + * + * The differences between a pbuf chain and a packet queue are very + * precise but subtle. + * + * The last pbuf of a packet has a ->tot_len field that equals the + * ->len field. It can be found by traversing the list. If the last + * pbuf of a packet has a ->next field other than NULL, more packets + * are on the queue. + * + * Therefore, looping through a pbuf of a single packet, has an + * loop end condition (tot_len == p->len), NOT (next == NULL). + * + * Example of custom pbuf usage for zero-copy RX: + @code{.c} +typedef struct my_custom_pbuf +{ + struct pbuf_custom p; + void* dma_descriptor; +} my_custom_pbuf_t; + +LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(my_custom_pbuf_t), "Zero-copy RX PBUF pool"); + +void my_pbuf_free_custom(void* p) +{ + my_custom_pbuf_t* my_puf = (my_custom_pbuf_t*)p; + + LOCK_INTERRUPTS(); + free_rx_dma_descriptor(my_pbuf->dma_descriptor); + LWIP_MEMPOOL_FREE(RX_POOL, my_pbuf); + UNLOCK_INTERRUPTS(); +} + +void eth_rx_irq() +{ + dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet(); + my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL); + + my_pbuf->p.custom_free_function = my_pbuf_free_custom; + my_pbuf->dma_descriptor = dma_desc; + + invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length); + + struct pbuf* p = pbuf_alloced_custom(PBUF_RAW, + dma_desc->rx_length, + PBUF_REF, + &my_pbuf->p, + dma_desc->rx_data, + dma_desc->max_buffer_size); + + if(netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } +} + @endcode + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#if LWIP_TCP && TCP_QUEUE_OOSEQ +#include "lwip/priv/tcp_priv.h" +#endif +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif + +#include + +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) +/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically + aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ +#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_IS_EMPTY() +#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ + +#if !NO_SYS +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL +#include "lwip/tcpip.h" +#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ + if (tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \ + SYS_ARCH_PROTECT(old_level); \ + pbuf_free_ooseq_pending = 0; \ + SYS_ARCH_UNPROTECT(old_level); \ + } } while(0) +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ +#endif /* !NO_SYS */ + +volatile u8_t pbuf_free_ooseq_pending; +#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() + +/** + * Attempt to reclaim some memory from queued out-of-sequence TCP segments + * if we run out of pool pbufs. It's better to give priority to new packets + * if we're running out. + * + * This must be done in the correct thread context therefore this function + * can only be used with NO_SYS=0 and through tcpip_callback. + */ +#if !NO_SYS +static +#endif /* !NO_SYS */ +void +pbuf_free_ooseq(void) +{ + struct tcp_pcb* pcb; + SYS_ARCH_SET(pbuf_free_ooseq_pending, 0); + + for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { + if (NULL != pcb->ooseq) { + /** Free the ooseq pbufs of one PCB only */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + return; + } + } +} + +#if !NO_SYS +/** + * Just a callback function for tcpip_callback() that calls pbuf_free_ooseq(). + */ +static void +pbuf_free_ooseq_callback(void *arg) +{ + LWIP_UNUSED_ARG(arg); + pbuf_free_ooseq(); +} +#endif /* !NO_SYS */ + +/** Queue a call to pbuf_free_ooseq if not already queued. */ +static void +pbuf_pool_is_empty(void) +{ +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL + SYS_ARCH_SET(pbuf_free_ooseq_pending, 1); +#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ + u8_t queued; + SYS_ARCH_DECL_PROTECT(old_level); + SYS_ARCH_PROTECT(old_level); + queued = pbuf_free_ooseq_pending; + pbuf_free_ooseq_pending = 1; + SYS_ARCH_UNPROTECT(old_level); + + if (!queued) { + /* queue a call to pbuf_free_ooseq if not already queued */ + PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); + } +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ +} +#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ + +/** + * @ingroup pbuf + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + * chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + * protocol headers. Additional headers must be prepended + * by allocating another pbuf and chain in to the front of + * the ROM pbuf. It is assumed that the memory used is really + * similar to ROM in that it is immutable and will not be + * changed. Memory which is dynamic should generally not + * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + * protocol headers. It is assumed that the pbuf is only + * being used in a single thread. If the pbuf gets queued, + * then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + * the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ +struct pbuf * +pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) +{ + struct pbuf *p, *q, *r; + u16_t offset; + s32_t rem_len; /* remaining length */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); + + /* determine header offset */ + switch (layer) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; + break; + case PBUF_IP: + /* add room for IP layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; + break; + case PBUF_LINK: + /* add room for link layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; + break; + case PBUF_RAW_TX: + /* add room for encapsulating link layer headers (e.g. 802.11) */ + offset = PBUF_LINK_ENCAPSULATION_HLEN; + break; + case PBUF_RAW: + /* no offset (e.g. RX buffers or chain successors) */ + offset = 0; + break; + default: + LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); + return NULL; + } + + switch (type) { + case PBUF_POOL: + /* allocate head of pbuf chain into p */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); + if (p == NULL) { + PBUF_POOL_IS_EMPTY(); + return NULL; + } + p->type = type; + p->next = NULL; + + /* make the payload pointer point 'offset' bytes into pbuf data memory */ + p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); + LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + /* the total length of the pbuf chain is the requested size */ + p->tot_len = length; + /* set the length of the first pbuf in the chain */ + p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); + LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", + ((u8_t*)p->payload + p->len <= + (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); + LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", + (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); + /* set reference count (needed here in case we fail) */ + p->ref = 1; + + /* now allocate the tail of the pbuf chain */ + + /* remember first pbuf for linkage in next iteration */ + r = p; + /* remaining length to be allocated */ + rem_len = length - p->len; + /* any remaining pbufs to be allocated? */ + while (rem_len > 0) { + q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); + if (q == NULL) { + PBUF_POOL_IS_EMPTY(); + /* free chain so far allocated */ + pbuf_free(p); + /* bail out unsuccessfully */ + return NULL; + } + q->type = type; + q->flags = 0; + q->next = NULL; + /* make previous pbuf point to this pbuf */ + r->next = q; + /* set total length of this pbuf and next in chain */ + LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); + q->tot_len = (u16_t)rem_len; + /* this pbuf length is pool size, unless smaller sized tail */ + q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); + q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); + LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", + ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", + ((u8_t*)p->payload + p->len <= + (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); + q->ref = 1; + /* calculate remaining length to be allocated */ + rem_len -= q->len; + /* remember this pbuf for linkage in next iteration */ + r = q; + } + /* end of chain */ + /*r->next = NULL;*/ + + break; + case PBUF_RAM: + { + mem_size_t alloc_len = LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length); + + /* bug #50040: Check for integer overflow when calculating alloc_len */ + if (alloc_len < LWIP_MEM_ALIGN_SIZE(length)) { + return NULL; + } + + /* If pbuf is to be allocated in RAM, allocate memory for it. */ + p = (struct pbuf*)mem_malloc(alloc_len); + } + + if (p == NULL) { + return NULL; + } + /* Set up internal structure of the pbuf. */ + p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + + LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", + ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); + break; + /* pbuf references existing (non-volatile static constant) ROM payload? */ + case PBUF_ROM: + /* pbuf references existing (externally allocated) RAM payload? */ + case PBUF_REF: + /* only allocate memory for the pbuf structure */ + p = (struct pbuf *)memp_malloc(MEMP_PBUF); + if (p == NULL) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", + (type == PBUF_ROM) ? "ROM" : "REF")); + return NULL; + } + /* caller must set this field properly, afterwards */ + p->payload = NULL; + p->len = p->tot_len = length; + p->next = NULL; + p->type = type; + break; + default: + LWIP_ASSERT("pbuf_alloc: erroneous type", 0); + return NULL; + } + /* set reference count */ + p->ref = 1; + /* set flags */ + p->flags = 0; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); + return p; +} + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** + * @ingroup pbuf + * Initialize a custom pbuf (already allocated). + * + * @param l flag to define header size + * @param length size of the pbuf's payload + * @param type type of the pbuf (only used to treat the pbuf accordingly, as + * this function allocates no memory) + * @param p pointer to the custom pbuf to initialize (already allocated) + * @param payload_mem pointer to the buffer that is used for payload and headers, + * must be at least big enough to hold 'length' plus the header size, + * may be NULL if set later. + * ATTENTION: The caller is responsible for correct alignment of this buffer!! + * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least + * big enough to hold 'length' plus the header size + */ +struct pbuf* +pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, + void *payload_mem, u16_t payload_mem_len) +{ + u16_t offset; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); + + /* determine header offset */ + switch (l) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; + break; + case PBUF_IP: + /* add room for IP layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN; + break; + case PBUF_LINK: + /* add room for link layer header */ + offset = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; + break; + case PBUF_RAW_TX: + /* add room for encapsulating link layer headers (e.g. 802.11) */ + offset = PBUF_LINK_ENCAPSULATION_HLEN; + break; + case PBUF_RAW: + offset = 0; + break; + default: + LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); + return NULL; + } + + if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); + return NULL; + } + + p->pbuf.next = NULL; + if (payload_mem != NULL) { + p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); + } else { + p->pbuf.payload = NULL; + } + p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; + p->pbuf.len = p->pbuf.tot_len = length; + p->pbuf.type = type; + p->pbuf.ref = 1; + return &p->pbuf; +} +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** + * @ingroup pbuf + * Shrink a pbuf chain to a desired length. + * + * @param p pbuf to shrink. + * @param new_len desired new length of pbuf chain + * + * Depending on the desired length, the first few pbufs in a chain might + * be skipped and left unchanged. The new last pbuf in the chain will be + * resized, and any remaining pbufs will be freed. + * + * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. + * @note May not be called on a packet queue. + * + * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). + */ +void +pbuf_realloc(struct pbuf *p, u16_t new_len) +{ + struct pbuf *q; + u16_t rem_len; /* remaining length */ + s32_t grow; + + LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); + LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || + p->type == PBUF_ROM || + p->type == PBUF_RAM || + p->type == PBUF_REF); + + /* desired length larger than current length? */ + if (new_len >= p->tot_len) { + /* enlarging not yet supported */ + return; + } + + /* the pbuf chain grows by (new_len - p->tot_len) bytes + * (which may be negative in case of shrinking) */ + grow = new_len - p->tot_len; + + /* first, step over any pbufs that should remain in the chain */ + rem_len = new_len; + q = p; + /* should this pbuf be kept? */ + while (rem_len > q->len) { + /* decrease remaining length by pbuf length */ + rem_len -= q->len; + /* decrease total length indicator */ + LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); + q->tot_len += (u16_t)grow; + /* proceed to next pbuf in chain */ + q = q->next; + LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); + } + /* we have now reached the new last pbuf (in q) */ + /* rem_len == desired length for pbuf q */ + + /* shrink allocated memory for PBUF_RAM */ + /* (other types merely adjust their length fields */ + if ((q->type == PBUF_RAM) && (rem_len != q->len) +#if LWIP_SUPPORT_CUSTOM_PBUF + && ((q->flags & PBUF_FLAG_IS_CUSTOM) == 0) +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + ) { + /* reallocate and adjust the length of the pbuf that will be split */ + q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); + LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); + } + /* adjust length fields for new last pbuf */ + q->len = rem_len; + q->tot_len = q->len; + + /* any remaining pbufs in chain? */ + if (q->next != NULL) { + /* free remaining pbufs in chain */ + pbuf_free(q->next); + } + /* q is last packet in chain */ + q->next = NULL; + +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * @see pbuf_header. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size. + * @param force Allow 'header_size_increment > 0' for PBUF_REF/PBUF_ROM types + * + * @return non-zero on failure, zero on success. + * + */ +static u8_t +pbuf_header_impl(struct pbuf *p, s16_t header_size_increment, u8_t force) +{ + u16_t type; + void *payload; + u16_t increment_magnitude; + + LWIP_ASSERT("p != NULL", p != NULL); + if ((header_size_increment == 0) || (p == NULL)) { + return 0; + } + + if (header_size_increment < 0) { + increment_magnitude = (u16_t)-header_size_increment; + /* Check that we aren't going to move off the end of the pbuf */ + LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); + } else { + increment_magnitude = (u16_t)header_size_increment; +#if 0 + /* Can't assert these as some callers speculatively call + pbuf_header() to see if it's OK. Will return 1 below instead. */ + /* Check that we've got the correct type of pbuf to work with */ + LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", + p->type == PBUF_RAM || p->type == PBUF_POOL); + /* Check that we aren't going to move off the beginning of the pbuf */ + LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", + (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); +#endif + } + + type = p->type; + /* remember current payload pointer */ + payload = p->payload; + + /* pbuf types containing payloads? */ + if (type == PBUF_RAM || type == PBUF_POOL) { + /* set new payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + /* boundary check fails? */ + if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, + ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", + (void *)p->payload, (void *)((u8_t *)p + SIZEOF_STRUCT_PBUF))); + /* restore old payload pointer */ + p->payload = payload; + /* bail out unsuccessfully */ + return 1; + } + /* pbuf types referring to external payloads? */ + } else if (type == PBUF_REF || type == PBUF_ROM) { + /* hide a header in the payload? */ + if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { + /* increase payload pointer */ + p->payload = (u8_t *)p->payload - header_size_increment; + } else if ((header_size_increment > 0) && force) { + p->payload = (u8_t *)p->payload - header_size_increment; + } else { + /* cannot expand payload to front (yet!) + * bail out unsuccessfully */ + return 1; + } + } else { + /* Unknown type */ + LWIP_ASSERT("bad pbuf type", 0); + return 1; + } + /* modify pbuf length fields */ + p->len += header_size_increment; + p->tot_len += header_size_increment; + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", + (void *)payload, (void *)p->payload, header_size_increment)); + + return 0; +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If hdr_size_inc is 0, this function does nothing and returns successful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size_increment) +{ + return pbuf_header_impl(p, header_size_increment, 0); +} + +/** + * Same as pbuf_header but does not check if 'header_size > 0' is allowed. + * This is used internally only, to allow PBUF_REF for RX. + */ +u8_t +pbuf_header_force(struct pbuf *p, s16_t header_size_increment) +{ + return pbuf_header_impl(p, header_size_increment, 1); +} + +/** + * @ingroup pbuf + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param p The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + * + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ +u8_t +pbuf_free(struct pbuf *p) +{ + u16_t type; + struct pbuf *q; + u8_t count; + + if (p == NULL) { + LWIP_ASSERT("p != NULL", p != NULL); + /* if assertions are disabled, proceed with debug output */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("pbuf_free(p == NULL) was called.\n")); + return 0; + } + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); + + PERF_START; + + LWIP_ASSERT("pbuf_free: sane type", + p->type == PBUF_RAM || p->type == PBUF_ROM || + p->type == PBUF_REF || p->type == PBUF_POOL); + + count = 0; + /* de-allocate all consecutive pbufs from the head of the chain that + * obtain a zero reference count after decrementing*/ + while (p != NULL) { + u16_t ref; + SYS_ARCH_DECL_PROTECT(old_level); + /* Since decrementing ref cannot be guaranteed to be a single machine operation + * we must protect it. We put the new ref into a local variable to prevent + * further protection. */ + SYS_ARCH_PROTECT(old_level); + /* all pbufs in a chain are referenced at least once */ + LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); + /* decrease reference count (number of pointers to pbuf) */ + ref = --(p->ref); + SYS_ARCH_UNPROTECT(old_level); + /* this pbuf is no longer referenced to? */ + if (ref == 0) { + /* remember next pbuf in chain for next iteration */ + q = p->next; + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); + type = p->type; +#if LWIP_SUPPORT_CUSTOM_PBUF + /* is this a custom pbuf? */ + if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { + struct pbuf_custom *pc = (struct pbuf_custom*)p; + LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); + pc->custom_free_function(p); + } else +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + { + /* is this a pbuf from the pool? */ + if (type == PBUF_POOL) { + memp_free(MEMP_PBUF_POOL, p); + /* is this a ROM or RAM referencing pbuf? */ + } else if (type == PBUF_ROM || type == PBUF_REF) { + memp_free(MEMP_PBUF, p); + /* type == PBUF_RAM */ + } else { + mem_free(p); + } + } + count++; + /* proceed to next pbuf */ + p = q; + /* p->ref > 0, this pbuf is still referenced to */ + /* (and so the remaining pbufs in chain as well) */ + } else { + LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); + /* stop walking through the chain */ + p = NULL; + } + } + PERF_STOP("pbuf_free"); + /* return number of de-allocated pbufs */ + return count; +} + +/** + * Count number of pbufs in a chain + * + * @param p first pbuf of chain + * @return the number of pbufs in a chain + */ +u16_t +pbuf_clen(const struct pbuf *p) +{ + u16_t len; + + len = 0; + while (p != NULL) { + ++len; + p = p->next; + } + return len; +} + +/** + * @ingroup pbuf + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void +pbuf_ref(struct pbuf *p) +{ + /* pbuf given? */ + if (p != NULL) { + SYS_ARCH_INC(p->ref, 1); + LWIP_ASSERT("pbuf ref overflow", p->ref > 0); + } +} + +/** + * @ingroup pbuf + * Concatenate two pbufs (each may be a pbuf chain) and take over + * the caller's reference of the tail pbuf. + * + * @note The caller MAY NOT reference the tail pbuf afterwards. + * Use pbuf_chain() for that purpose. + * + * @see pbuf_chain() + */ +void +pbuf_cat(struct pbuf *h, struct pbuf *t) +{ + struct pbuf *p; + + LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", + ((h != NULL) && (t != NULL)), return;); + + /* proceed to last pbuf of chain */ + for (p = h; p->next != NULL; p = p->next) { + /* add total length of second chain to all totals of first chain */ + p->tot_len += t->tot_len; + } + /* { p is last pbuf of first h chain, p->next == NULL } */ + LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); + LWIP_ASSERT("p->next == NULL", p->next == NULL); + /* add total length of second chain to last pbuf total of first chain */ + p->tot_len += t->tot_len; + /* chain last pbuf of head (p) with first of tail (t) */ + p->next = t; + /* p->next now references t, but the caller will drop its reference to t, + * so netto there is no change to the reference count of t. + */ +} + +/** + * @ingroup pbuf + * Chain two pbufs (or pbuf chains) together. + * + * The caller MUST call pbuf_free(t) once it has stopped + * using it. Use pbuf_cat() instead if you no longer use t. + * + * @param h head pbuf (chain) + * @param t tail pbuf (chain) + * @note The pbufs MUST belong to the same packet. + * @note MAY NOT be called on a packet queue. + * + * The ->tot_len fields of all pbufs of the head chain are adjusted. + * The ->next field of the last pbuf of the head chain is adjusted. + * The ->ref field of the first pbuf of the tail chain is adjusted. + * + */ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ + pbuf_cat(h, t); + /* t is now referenced by h */ + pbuf_ref(t); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); +} + +/** + * Dechains the first pbuf from its succeeding pbufs in the chain. + * + * Makes p->tot_len field equal to p->len. + * @param p pbuf to dechain + * @return remainder of the pbuf chain, or NULL if it was de-allocated. + * @note May not be called on a packet queue. + */ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ + struct pbuf *q; + u8_t tail_gone = 1; + /* tail */ + q = p->next; + /* pbuf has successor in chain? */ + if (q != NULL) { + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); + /* enforce invariant if assertion is disabled */ + q->tot_len = p->tot_len - p->len; + /* decouple pbuf from remainder */ + p->next = NULL; + /* total length of pbuf p is its own length only */ + p->tot_len = p->len; + /* q is no longer referenced by p, free it */ + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); + tail_gone = pbuf_free(q); + if (tail_gone > 0) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, + ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); + } + /* return remaining tail or NULL if deallocated */ + } + /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ + LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); + return ((tail_gone > 0) ? NULL : q); +} + +/** + * @ingroup pbuf + * Create PBUF_RAM copies of pbufs. + * + * Used to queue packets on behalf of the lwIP stack, such as + * ARP based queueing. + * + * @note You MUST explicitly use p = pbuf_take(p); + * + * @note Only one packet is copied, no packet queue! + * + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy + * + * @return ERR_OK if pbuf was copied + * ERR_ARG if one of the pbufs is NULL or p_to is not big + * enough to hold p_from + */ +err_t +pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from) +{ + u16_t offset_to=0, offset_from=0, len; + + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", + (const void*)p_to, (const void*)p_from)); + + /* is the target big enough to hold the source? */ + LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && + (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); + + /* iterate through pbuf chain */ + do + { + /* copy one part of the original chain */ + if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { + /* complete current p_from fits into current p_to */ + len = p_from->len - offset_from; + } else { + /* current p_from does not fit into current p_to */ + len = p_to->len - offset_to; + } + MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); + offset_to += len; + offset_from += len; + LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); + LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); + if (offset_from >= p_from->len) { + /* on to next p_from (if any) */ + offset_from = 0; + p_from = p_from->next; + } + if (offset_to == p_to->len) { + /* on to next p_to (if any) */ + offset_to = 0; + p_to = p_to->next; + LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;); + } + + if ((p_from != NULL) && (p_from->len == p_from->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy() does not allow packet queues!", + (p_from->next == NULL), return ERR_VAL;); + } + if ((p_to != NULL) && (p_to->len == p_to->tot_len)) { + /* don't copy more than one packet! */ + LWIP_ERROR("pbuf_copy() does not allow packet queues!", + (p_to->next == NULL), return ERR_VAL;); + } + } while (p_from); + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); + return ERR_OK; +} + +/** + * @ingroup pbuf + * Copy (part of) the contents of a packet buffer + * to an application supplied buffer. + * + * @param buf the pbuf from which to copy data + * @param dataptr the application supplied buffer + * @param len length of data to copy (dataptr must be big enough). No more + * than buf->tot_len will be copied, irrespective of len + * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure + */ +u16_t +pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) +{ + const struct pbuf *p; + u16_t left; + u16_t buf_copy_len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + + left = 0; + + if ((buf == NULL) || (dataptr == NULL)) { + return 0; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for (p = buf; len != 0 && p != NULL; p = p->next) { + if ((offset != 0) && (offset >= p->len)) { + /* don't copy from this buffer -> on to the next */ + offset -= p->len; + } else { + /* copy from this buffer. maybe only partially. */ + buf_copy_len = p->len - offset; + if (buf_copy_len > len) { + buf_copy_len = len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); + copied_total += buf_copy_len; + left += buf_copy_len; + len -= buf_copy_len; + offset = 0; + } + } + return copied_total; +} + +#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE +/** + * This method modifies a 'pbuf chain', so that its total length is + * smaller than 64K. The remainder of the original pbuf chain is stored + * in *rest. + * This function never creates new pbufs, but splits an existing chain + * in two parts. The tot_len of the modified packet queue will likely be + * smaller than 64K. + * 'packet queues' are not supported by this function. + * + * @param p the pbuf queue to be split + * @param rest pointer to store the remainder (after the first 64K) + */ +void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) +{ + *rest = NULL; + if ((p != NULL) && (p->next != NULL)) { + u16_t tot_len_front = p->len; + struct pbuf *i = p; + struct pbuf *r = p->next; + + /* continue until the total length (summed up as u16_t) overflows */ + while ((r != NULL) && ((u16_t)(tot_len_front + r->len) > tot_len_front)) { + tot_len_front += r->len; + i = r; + r = r->next; + } + /* i now points to last packet of the first segment. Set next + pointer to NULL */ + i->next = NULL; + + if (r != NULL) { + /* Update the tot_len field in the first part */ + for (i = p; i != NULL; i = i->next) { + i->tot_len -= r->tot_len; + LWIP_ASSERT("tot_len/len mismatch in last pbuf", + (i->next != NULL) || (i->tot_len == i->len)); + } + if (p->flags & PBUF_FLAG_TCP_FIN) { + r->flags |= PBUF_FLAG_TCP_FIN; + } + + /* tot_len field in rest does not need modifications */ + /* reference counters do not need modifications */ + *rest = r; + } + } +} +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + +/* Actual implementation of pbuf_skip() but returning const pointer... */ +static const struct pbuf* +pbuf_skip_const(const struct pbuf* in, u16_t in_offset, u16_t* out_offset) +{ + u16_t offset_left = in_offset; + const struct pbuf* q = in; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= offset_left)) { + offset_left -= q->len; + q = q->next; + } + if (out_offset != NULL) { + *out_offset = offset_left; + } + return q; +} + +/** + * @ingroup pbuf + * Skip a number of bytes at the start of a pbuf + * + * @param in input pbuf + * @param in_offset offset to skip + * @param out_offset resulting offset in the returned pbuf + * @return the pbuf in the queue where the offset is + */ +struct pbuf* +pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset) +{ + const struct pbuf* out = pbuf_skip_const(in, in_offset, out_offset); + return LWIP_CONST_CAST(struct pbuf*, out); +} + +/** + * @ingroup pbuf + * Copy application supplied data into a pbuf. + * This function can only be used to copy the equivalent of buf->tot_len data. + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ + struct pbuf *p; + u16_t buf_copy_len; + u16_t total_copy_len = len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return ERR_ARG;); + LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return ERR_ARG;); + LWIP_ERROR("pbuf_take: buf not large enough", (buf->tot_len >= len), return ERR_MEM;); + + if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { + return ERR_ARG; + } + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for (p = buf; total_copy_len != 0; p = p->next) { + LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); + buf_copy_len = total_copy_len; + if (buf_copy_len > p->len) { + /* this pbuf cannot hold all remaining data */ + buf_copy_len = p->len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(p->payload, &((const char*)dataptr)[copied_total], buf_copy_len); + total_copy_len -= buf_copy_len; + copied_total += buf_copy_len; + } + LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); + return ERR_OK; +} + +/** + * @ingroup pbuf + * Same as pbuf_take() but puts data at an offset + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * @param offset offset in pbuf where to copy dataptr to + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset) +{ + u16_t target_offset; + struct pbuf* q = pbuf_skip(buf, offset, &target_offset); + + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->tot_len >= target_offset + len)) { + u16_t remaining_len = len; + const u8_t* src_ptr = (const u8_t*)dataptr; + /* copy the part that goes into the first pbuf */ + u16_t first_copy_len = LWIP_MIN(q->len - target_offset, len); + MEMCPY(((u8_t*)q->payload) + target_offset, dataptr, first_copy_len); + remaining_len -= first_copy_len; + src_ptr += first_copy_len; + if (remaining_len > 0) { + return pbuf_take(q->next, src_ptr, remaining_len); + } + return ERR_OK; + } + return ERR_MEM; +} + +/** + * @ingroup pbuf + * Creates a single pbuf out of a queue of pbufs. + * + * @remark: Either the source pbuf 'p' is freed by this function or the original + * pbuf 'p' is returned, therefore the caller has to check the result! + * + * @param p the source pbuf + * @param layer pbuf_layer of the new pbuf + * + * @return a new, single pbuf (p->next is NULL) + * or the old pbuf if allocation fails + */ +struct pbuf* +pbuf_coalesce(struct pbuf *p, pbuf_layer layer) +{ + struct pbuf *q; + err_t err; + if (p->next == NULL) { + return p; + } + q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); + if (q == NULL) { + /* @todo: what do we do now? */ + return p; + } + err = pbuf_copy(q, p); + LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ + LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); + pbuf_free(p); + return q; +} + +#if LWIP_CHECKSUM_ON_COPY +/** + * Copies data into a single pbuf (*not* into a pbuf queue!) and updates + * the checksum while copying + * + * @param p the pbuf to copy data into + * @param start_offset offset of p->payload where to copy the data to + * @param dataptr data to copy into the pbuf + * @param len length of data to copy into the pbuf + * @param chksum pointer to the checksum which is updated + * @return ERR_OK if successful, another error if the data does not fit + * within the (first) pbuf (no pbuf queues!) + */ +err_t +pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum) +{ + u32_t acc; + u16_t copy_chksum; + char *dst_ptr; + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("dataptr != NULL", dataptr != NULL); + LWIP_ASSERT("chksum != NULL", chksum != NULL); + LWIP_ASSERT("len != 0", len != 0); + + if ((start_offset >= p->len) || (start_offset + len > p->len)) { + return ERR_ARG; + } + + dst_ptr = ((char*)p->payload) + start_offset; + copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); + if ((start_offset & 1) != 0) { + copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); + } + acc = *chksum; + acc += copy_chksum; + *chksum = FOLD_U32T(acc); + return ERR_OK; +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + +/** + * @ingroup pbuf + * Get one byte from the specified position in a pbuf + * WARNING: returns zero for offset >= p->tot_len + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len + */ +u8_t +pbuf_get_at(const struct pbuf* p, u16_t offset) +{ + int ret = pbuf_try_get_at(p, offset); + if (ret >= 0) { + return (u8_t)ret; + } + return 0; +} + +/** + * @ingroup pbuf + * Get one byte from the specified position in a pbuf + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p [0..0xFF] OR negative if 'offset' >= p->tot_len + */ +int +pbuf_try_get_at(const struct pbuf* p, u16_t offset) +{ + u16_t q_idx; + const struct pbuf* q = pbuf_skip_const(p, offset, &q_idx); + + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > q_idx)) { + return ((u8_t*)q->payload)[q_idx]; + } + return -1; +} + +/** + * @ingroup pbuf + * Put one byte to the specified position in a pbuf + * WARNING: silently ignores offset >= p->tot_len + * + * @param p pbuf to fill + * @param offset offset into p of the byte to write + * @param data byte to write at an offset into p + */ +void +pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data) +{ + u16_t q_idx; + struct pbuf* q = pbuf_skip(p, offset, &q_idx); + + /* write requested data if pbuf is OK */ + if ((q != NULL) && (q->len > q_idx)) { + ((u8_t*)q->payload)[q_idx] = data; + } +} + +/** + * @ingroup pbuf + * Compare pbuf contents at specified offset with memory s2, both of length n + * + * @param p pbuf to compare + * @param offset offset into p at which to start comparing + * @param s2 buffer to compare + * @param n length of buffer to compare + * @return zero if equal, nonzero otherwise + * (0xffff if p is too short, diffoffset+1 otherwise) + */ +u16_t +pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n) +{ + u16_t start = offset; + const struct pbuf* q = p; + u16_t i; + + /* pbuf long enough to perform check? */ + if(p->tot_len < (offset + n)) { + return 0xffff; + } + + /* get the correct pbuf from chain. We know it succeeds because of p->tot_len check above. */ + while ((q != NULL) && (q->len <= start)) { + start -= q->len; + q = q->next; + } + + /* return requested data if pbuf is OK */ + for (i = 0; i < n; i++) { + /* We know pbuf_get_at() succeeds because of p->tot_len check above. */ + u8_t a = pbuf_get_at(q, start + i); + u8_t b = ((const u8_t*)s2)[i]; + if (a != b) { + return i+1; + } + } + return 0; +} + +/** + * @ingroup pbuf + * Find occurrence of mem (with length mem_len) in pbuf p, starting at offset + * start_offset. + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param mem search for the contents of this buffer + * @param mem_len length of 'mem' + * @param start_offset offset into p at which to start searching + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) +{ + u16_t i; + u16_t max = p->tot_len - mem_len; + if (p->tot_len >= mem_len + start_offset) { + for (i = start_offset; i <= max; i++) { + u16_t plus = pbuf_memcmp(p, i, mem, mem_len); + if (plus == 0) { + return i; + } + } + } + return 0xFFFF; +} + +/** + * Find occurrence of substr with length substr_len in pbuf p, start at offset + * start_offset + * WARNING: in contrast to strstr(), this one does not stop at the first \0 in + * the pbuf/source string! + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param substr string to search for in p, maximum length is 0xFFFE + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_strstr(const struct pbuf* p, const char* substr) +{ + size_t substr_len; + if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { + return 0xFFFF; + } + substr_len = strlen(substr); + if (substr_len >= 0xFFFF) { + return 0xFFFF; + } + return pbuf_memfind(p, substr, (u16_t)substr_len, 0); +} diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/raw.c b/Sming/third-party/lwip2/lwip2-src/src/core/raw.c new file mode 100644 index 0000000000..80cf9ec64b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/raw.c @@ -0,0 +1,521 @@ +/** + * @file + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP.\n + * See also @ref raw_raw + * + * @defgroup raw_raw RAW + * @ingroup callbackstyle_api + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP.\n + * @see @ref raw_api + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" + +#include + +/** The list of RAW PCBs */ +static struct raw_pcb *raw_pcbs; + +static u8_t +raw_input_match(struct raw_pcb *pcb, u8_t broadcast) +{ + LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ + +#if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { +#if IP_SOF_BROADCAST_RECV + if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { + return 0; + } +#endif /* IP_SOF_BROADCAST_RECV */ + return 1; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + + /* Only need to check PCB if incoming IP version matches PCB IP version */ + if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { +#if LWIP_IPV4 + /* Special case: IPv4 broadcast: receive all broadcasts + * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ + if (broadcast != 0) { +#if IP_SOF_BROADCAST_RECV + if (ip_get_option(pcb, SOF_BROADCAST)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) { + return 1; + } + } + } else +#endif /* LWIP_IPV4 */ + /* Handle IPv4 and IPv6: catch all or exact match */ + if (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + return 1; + } + } + + return 0; +} + +/** + * Determine if in incoming IP packet is covered by a RAW PCB + * and if so, pass it to a user-provided receive callback function. + * + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and calls the corresponding receive + * callback function. + * + * @param p pbuf to be demultiplexed to a RAW PCB. + * @param inp network interface on which the datagram was received. + * @return - 1 if the packet has been eaten by a RAW PCB receive + * callback function. The caller MAY NOT not reference the + * packet any longer, and MAY NOT call pbuf_free(). + * @return - 0 if packet is not eaten (pbuf is still referenced by the + * caller). + * + */ +u8_t +raw_input(struct pbuf *p, struct netif *inp) +{ + struct raw_pcb *pcb, *prev; + s16_t proto; + u8_t eaten = 0; + u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); + + LWIP_UNUSED_ARG(inp); + +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_HDR_GET_VERSION(p->payload) == 6) +#endif /* LWIP_IPV4 */ + { + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; + proto = IP6H_NEXTH(ip6hdr); + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + proto = IPH_PROTO((struct ip_hdr *)p->payload); + } +#endif /* LWIP_IPV4 */ + + prev = NULL; + pcb = raw_pcbs; + /* loop through all raw pcbs until the packet is eaten by one */ + /* this allows multiple pcbs to match against the packet by design */ + while ((eaten == 0) && (pcb != NULL)) { + if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) { + /* receive callback function available? */ + if (pcb->recv != NULL) { +#ifndef LWIP_NOASSERT + void* old_payload = p->payload; +#endif + /* the receive callback function did not eat the packet? */ + eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()); + if (eaten != 0) { + /* receive function ate the packet */ + p = NULL; + eaten = 1; + if (prev != NULL) { + /* move the pcb to the front of raw_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + } else { + /* sanity-check that the receive callback did not alter the pbuf */ + LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", + p->payload == old_payload); + } + } + /* no receive callback function was set for this raw PCB */ + } + /* drop the packet */ + prev = pcb; + pcb = pcb->next; + } + return eaten; +} + +/** + * @ingroup raw_raw + * Bind a RAW PCB. + * + * @param pcb RAW PCB to be bound with a local address ipaddr. + * @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to + * bind to all local interfaces. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_USE. The specified IP address is already bound to by + * another RAW PCB. + * + * @see raw_disconnect() + */ +err_t +raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) +{ + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); + return ERR_OK; +} + +/** + * @ingroup raw_raw + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_sendto() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_sendto() + */ +err_t +raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) +{ + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); + return ERR_OK; +} + +/** + * @ingroup raw_raw + * Set the callback function for received packets that match the + * raw PCB's protocol and binding. + * + * The callback function MUST either + * - eat the packet by calling pbuf_free() and returning non-zero. The + * packet will not be passed to other raw PCBs or other protocol layers. + * - not free the packet, and return zero. The packet will be matched + * against further PCBs and/or forwarded to another protocol layers. + */ +void +raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * @ingroup raw_raw + * Send the raw IP packet to the given address. Note that actually you cannot + * modify the IP headers (this is inconsistent with the receive callback where + * you actually get the IP headers), you can only specify the IP payload here. + * It requires some more changes in lwIP. (there will be a raw_send() function + * then.) + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) +{ + err_t err; + struct netif *netif; + const ip_addr_t *src_ip; + struct pbuf *q; /* q will be sent down the stack */ + s16_t header_size; + + if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { + return ERR_VAL; + } + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); + + header_size = ( +#if LWIP_IPV4 && LWIP_IPV6 + IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN); +#elif LWIP_IPV4 + IP_HLEN); +#else + IP6_HLEN); +#endif + + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_header(p, header_size)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + } + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + if (pbuf_header(q, -header_size)) { + LWIP_ASSERT("Can't restore header we just removed!", 0); + return ERR_MEM; + } + } + + if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + /* Don't call ip_route() with IP_ANY_TYPE */ + netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr); + } else { + netif = ip_route(&pcb->local_ip, ipaddr); + } + + if (netif == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); + ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + +#if IP_SOF_BROADCAST + if (IP_IS_V4(ipaddr)) + { + /* broadcast filter? */ + if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; + } + } +#endif /* IP_SOF_BROADCAST */ + + if (ip_addr_isany(&pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = ip_netif_get_local_ip(netif, ipaddr); +#if LWIP_IPV6 + if (src_ip == NULL) { + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } +#endif /* LWIP_IPV6 */ + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &pcb->local_ip; + } + +#if LWIP_IPV6 + /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, + compute the checksum and update the checksum in the payload. */ + if (IP_IS_V6(ipaddr) && pcb->chksum_reqd) { + u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr)); + LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); + SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); + } +#endif + + NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); + err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * @ingroup raw_raw + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * + */ +err_t +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ + return raw_sendto(pcb, p, &pcb->remote_ip); +} + +/** + * @ingroup raw_raw + * Remove an RAW PCB. + * + * @param pcb RAW PCB to be removed. The PCB is removed from the list of + * RAW PCB's and the data structure is freed from memory. + * + * @see raw_new() + */ +void +raw_remove(struct raw_pcb *pcb) +{ + struct raw_pcb *pcb2; + /* pcb to be removed is first in list? */ + if (raw_pcbs == pcb) { + /* make list start at 2nd pcb */ + raw_pcbs = raw_pcbs->next; + /* pcb not 1st in list */ + } else { + for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in raw_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + break; + } + } + } + memp_free(MEMP_RAW_PCB, pcb); +} + +/** + * @ingroup raw_raw + * Create a RAW PCB. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new(u8_t proto) +{ + struct raw_pcb *pcb; + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); + + pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); + /* could allocate RAW PCB? */ + if (pcb != NULL) { + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct raw_pcb)); + pcb->protocol = proto; + pcb->ttl = RAW_TTL; + pcb->next = raw_pcbs; + raw_pcbs = pcb; + } + return pcb; +} + +/** + * @ingroup raw_raw + * Create a RAW PCB for specific IP type. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) packets, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @param proto the protocol number (next header) of the IPv6 packet payload + * (e.g. IP6_NEXTH_ICMP6) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new_ip_type(u8_t type, u8_t proto) +{ + struct raw_pcb *pcb; + pcb = raw_new(proto); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else /* LWIP_IPV4 && LWIP_IPV6 */ + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** This function is called from netif.c when address is changed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change + */ +void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr) +{ + struct raw_pcb* rpcb; + + if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { + for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&rpcb->local_ip, old_addr)) { + /* The PCB is bound to the old ipaddr and + * is set to bound to the new one instead */ + ip_addr_copy(rpcb->local_ip, *new_addr); + } + } + } +} + +#endif /* LWIP_RAW */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/stats.c b/Sming/third-party/lwip2/lwip2-src/src/core/stats.c new file mode 100644 index 0000000000..893d199c04 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/stats.c @@ -0,0 +1,169 @@ +/** + * @file + * Statistics module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/debug.h" + +#include + +struct stats_ lwip_stats; + +void +stats_init(void) +{ +#ifdef LWIP_DEBUG +#if MEM_STATS + lwip_stats.mem.name = "MEM"; +#endif /* MEM_STATS */ +#endif /* LWIP_DEBUG */ +} + +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, const char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); + LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); + LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); + LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); + LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); + LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); +} + +#if IGMP_STATS || MLD6_STATS +void +stats_display_igmp(struct stats_igmp *igmp, const char *name) +{ + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); + LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); + LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); + LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n\t", igmp->rx_group)); + LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", igmp->rx_general)); + LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); + LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); + LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); + LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n", igmp->tx_report)); +} +#endif /* IGMP_STATS || MLD6_STATS */ + +#if MEM_STATS || MEMP_STATS +void +stats_display_mem(struct stats_mem *mem, const char *name) +{ + LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); + LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); + LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); + LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); + LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); +} + +#if MEMP_STATS +void +stats_display_memp(struct stats_mem *mem, int index) +{ + if (index < MEMP_MAX) { + stats_display_mem(mem, mem->name); + } +} +#endif /* MEMP_STATS */ +#endif /* MEM_STATS || MEMP_STATS */ + +#if SYS_STATS +void +stats_display_sys(struct stats_sys *sys) +{ + LWIP_PLATFORM_DIAG(("\nSYS\n\t")); + LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); + LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); + LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); + LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); + LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); + LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); + LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); + LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); + LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n", (u32_t)sys->mbox.err)); +} +#endif /* SYS_STATS */ + +void +stats_display(void) +{ + s16_t i; + + LINK_STATS_DISPLAY(); + ETHARP_STATS_DISPLAY(); + IPFRAG_STATS_DISPLAY(); + IP6_FRAG_STATS_DISPLAY(); + IP_STATS_DISPLAY(); + ND6_STATS_DISPLAY(); + IP6_STATS_DISPLAY(); + IGMP_STATS_DISPLAY(); + MLD6_STATS_DISPLAY(); + ICMP_STATS_DISPLAY(); + ICMP6_STATS_DISPLAY(); + UDP_STATS_DISPLAY(); + TCP_STATS_DISPLAY(); + MEM_STATS_DISPLAY(); + for (i = 0; i < MEMP_MAX; i++) { + MEMP_STATS_DISPLAY(i); + } + SYS_STATS_DISPLAY(); +} +#endif /* LWIP_STATS_DISPLAY */ + +#endif /* LWIP_STATS */ + diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/sys.c b/Sming/third-party/lwip2/lwip2-src/src/core/sys.c new file mode 100644 index 0000000000..7059b4de5b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/sys.c @@ -0,0 +1,106 @@ +/** + * @file + * lwIP Operating System abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/** + * @defgroup sys_layer Porting (system abstraction layer) + * @ingroup lwip + * @verbinclude "sys_arch.txt" + * + * @defgroup sys_os OS abstraction layer + * @ingroup sys_layer + * No need to implement functions in this section in NO_SYS mode. + * + * @defgroup sys_sem Semaphores + * @ingroup sys_os + * + * @defgroup sys_mutex Mutexes + * @ingroup sys_os + * Mutexes are recommended to correctly handle priority inversion, + * especially if you use LWIP_CORE_LOCKING . + * + * @defgroup sys_mbox Mailboxes + * @ingroup sys_os + * + * @defgroup sys_time Time + * @ingroup sys_layer + * + * @defgroup sys_prot Critical sections + * @ingroup sys_layer + * Used to protect short regions of code against concurrent access. + * - Your system is a bare-metal system (probably with an RTOS) + * and interrupts are under your control: + * Implement this as LockInterrupts() / UnlockInterrupts() + * - Your system uses an RTOS with deferred interrupt handling from a + * worker thread: Implement as a global mutex or lock/unlock scheduler + * - Your system uses a high-level OS with e.g. POSIX signals: + * Implement as a global mutex + * + * @defgroup sys_misc Misc + * @ingroup sys_os + */ + +#include "lwip/opt.h" + +#include "lwip/sys.h" + +/* Most of the functions defined in sys.h must be implemented in the + * architecture-dependent file sys_arch.c */ + +#if !NO_SYS + +#ifndef sys_msleep +/** + * Sleep for some ms. Timeouts are NOT processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ + if (ms > 0) { + sys_sem_t delaysem; + err_t err = sys_sem_new(&delaysem, 0); + if (err == ERR_OK) { + sys_arch_sem_wait(&delaysem, ms); + sys_sem_free(&delaysem); + } + } +} +#endif /* sys_msleep */ + +#endif /* !NO_SYS */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/tcp.c b/Sming/third-party/lwip2/lwip2-src/src/core/tcp.c new file mode 100644 index 0000000000..ec2e1f92ce --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/tcp.c @@ -0,0 +1,2164 @@ +/** + * @file + * Transmission Control Protocol for IP + * See also @ref tcp_raw + * + * @defgroup tcp_raw TCP + * @ingroup callbackstyle_api + * Transmission Control Protocol for IP\n + * @see @ref raw_api and @ref netconn + * + * Common functions for the TCP implementation, such as functinos + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/tcp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/debug.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/nd6.h" + +#include + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#ifndef TCP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define TCP_LOCAL_PORT_RANGE_START 0xc000 +#define TCP_LOCAL_PORT_RANGE_END 0xffff +#define TCP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)) +#endif + +#if LWIP_TCP_KEEPALIVE +#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) +#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) +#else /* LWIP_TCP_KEEPALIVE */ +#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE +#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT +#endif /* LWIP_TCP_KEEPALIVE */ + +/* As initial send MSS, we use TCP_MSS but limit it to 536. */ +#if TCP_MSS > 536 +#define INITIAL_MSS 536 +#else +#define INITIAL_MSS TCP_MSS +#endif + +static const char * const tcp_state_str[] = { + "CLOSED", + "LISTEN", + "SYN_SENT", + "SYN_RCVD", + "ESTABLISHED", + "FIN_WAIT_1", + "FIN_WAIT_2", + "CLOSE_WAIT", + "CLOSING", + "LAST_ACK", + "TIME_WAIT" +}; + +/* last local TCP port */ +static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; + +/* Incremented every coarse grained timer shot (typically every 500 ms). */ +u32_t tcp_ticks; +static const u8_t tcp_backoff[13] = + { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + /* Times per slowtmr hits */ +static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; + +/* The TCP PCB lists. */ + +/** List of all TCP PCBs bound but not yet (connected || listening) */ +struct tcp_pcb *tcp_bound_pcbs; +/** List of all TCP PCBs in LISTEN state */ +union tcp_listen_pcbs_t tcp_listen_pcbs; +/** List of all TCP PCBs that are in a state in which + * they accept or send data. */ +struct tcp_pcb *tcp_active_pcbs; +/** List of all TCP PCBs in TIME-WAIT state */ +struct tcp_pcb *tcp_tw_pcbs; + +/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ +struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, + &tcp_active_pcbs, &tcp_tw_pcbs}; + +u8_t tcp_active_pcbs_changed; + +/** Timer counter to handle calling slow-timer from tcp_tmr() */ +static u8_t tcp_timer; +static u8_t tcp_timer_ctr; +static u16_t tcp_new_port(void); + +static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); + +/** + * Initialize this module. + */ +void +tcp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + +/** + * Called periodically to dispatch TCP timers. + */ +void +tcp_tmr(void) +{ + /* Call tcp_fasttmr() every 250 ms */ + tcp_fasttmr(); + + if (++tcp_timer & 1) { + /* Call tcp_slowtmr() every 500 ms, i.e., every other timer + tcp_tmr() is called. */ + tcp_slowtmr(); + } +} + +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG +/** Called when a listen pcb is closed. Iterates one pcb list and removes the + * closed listener pcb from pcb->listener if matching. + */ +static void +tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb) +{ + struct tcp_pcb *pcb; + for (pcb = list; pcb != NULL; pcb = pcb->next) { + if (pcb->listener == lpcb) { + pcb->listener = NULL; + } + } +} +#endif + +/** Called when a listen pcb is closed. Iterates all pcb lists and removes the + * closed listener pcb from pcb->listener if matching. + */ +static void +tcp_listen_closed(struct tcp_pcb *pcb) +{ +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + size_t i; + LWIP_ASSERT("pcb != NULL", pcb != NULL); + LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN); + for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { + tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen*)pcb); + } +#endif + LWIP_UNUSED_ARG(pcb); +} + +#if TCP_LISTEN_BACKLOG +/** @ingroup tcp_raw + * Delay accepting a connection in respect to the listen backlog: + * the number of outstanding connections is increased until + * tcp_backlog_accepted() is called. + * + * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() + * or else the backlog feature will get out of sync! + * + * @param pcb the connection pcb which is not fully accepted yet + */ +void +tcp_backlog_delayed(struct tcp_pcb* pcb) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + if ((pcb->flags & TF_BACKLOGPEND) == 0) { + if (pcb->listener != NULL) { + pcb->listener->accepts_pending++; + LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); + pcb->flags |= TF_BACKLOGPEND; + } + } +} + +/** @ingroup tcp_raw + * A delayed-accept a connection is accepted (or closed/aborted): decreases + * the number of outstanding connections after calling tcp_backlog_delayed(). + * + * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() + * or else the backlog feature will get out of sync! + * + * @param pcb the connection pcb which is now fully accepted (or closed/aborted) + */ +void +tcp_backlog_accepted(struct tcp_pcb* pcb) +{ + LWIP_ASSERT("pcb != NULL", pcb != NULL); + if ((pcb->flags & TF_BACKLOGPEND) != 0) { + if (pcb->listener != NULL) { + LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); + pcb->listener->accepts_pending--; + pcb->flags &= ~TF_BACKLOGPEND; + } + } +} +#endif /* TCP_LISTEN_BACKLOG */ + +/** + * Closes the TX side of a connection held by the PCB. + * For tcp_close(), a RST is sent if the application didn't receive all data + * (tcp_recved() not called for all data passed to recv callback). + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +static err_t +tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) +{ + if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { + if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) { + /* Not all data received by application, send RST to tell the remote + side about this. */ + LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); + + /* don't call tcp_abort here: we must not deallocate the pcb since + that might not be expected when calling tcp_close */ + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + if (pcb->state == ESTABLISHED) { + /* move to TIME_WAIT since we close actively */ + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + /* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */ + if (tcp_input_pcb == pcb) { + /* prevent using a deallocated pcb: free it from tcp_input later */ + tcp_trigger_input_pcb_close(); + } else { + memp_free(MEMP_TCP_PCB, pcb); + } + } + return ERR_OK; + } + } + + /* - states which free the pcb are handled here, + - states which send FIN and change state are handled in tcp_close_shutdown_fin() */ + switch (pcb->state) { + case CLOSED: + /* Closing a pcb in the CLOSED state might seem erroneous, + * however, it is in this state once allocated and as yet unused + * and the user needs some way to free it should the need arise. + * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) + * or for a pcb that has been used and then entered the CLOSED state + * is erroneous, but this should never happen as the pcb has in those cases + * been freed, and so any remaining handles are bogus. */ + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + memp_free(MEMP_TCP_PCB, pcb); + break; + case LISTEN: + tcp_listen_closed(pcb); + tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); + memp_free(MEMP_TCP_PCB_LISTEN, pcb); + break; + case SYN_SENT: + TCP_PCB_REMOVE_ACTIVE(pcb); + memp_free(MEMP_TCP_PCB, pcb); + MIB2_STATS_INC(mib2.tcpattemptfails); + break; + default: + return tcp_close_shutdown_fin(pcb); + } + return ERR_OK; +} + +static err_t +tcp_close_shutdown_fin(struct tcp_pcb *pcb) +{ + err_t err; + LWIP_ASSERT("pcb != NULL", pcb != NULL); + + switch (pcb->state) { + case SYN_RCVD: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + tcp_backlog_accepted(pcb); + MIB2_STATS_INC(mib2.tcpattemptfails); + pcb->state = FIN_WAIT_1; + } + break; + case ESTABLISHED: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + MIB2_STATS_INC(mib2.tcpestabresets); + pcb->state = FIN_WAIT_1; + } + break; + case CLOSE_WAIT: + err = tcp_send_fin(pcb); + if (err == ERR_OK) { + MIB2_STATS_INC(mib2.tcpestabresets); + pcb->state = LAST_ACK; + } + break; + default: + /* Has already been closed, do nothing. */ + return ERR_OK; + break; + } + + if (err == ERR_OK) { + /* To ensure all data has been sent when tcp_close returns, we have + to make sure tcp_output doesn't fail. + Since we don't really have to ensure all data has been sent when tcp_close + returns (unsent data is sent from tcp timer functions, also), we don't care + for the return value of tcp_output for now. */ + tcp_output(pcb); + } else if (err == ERR_MEM) { + /* Mark this pcb for closing. Closing is retried from tcp_tmr. */ + pcb->flags |= TF_CLOSEPEND; + } + return err; +} + +/** + * @ingroup tcp_raw + * Closes the connection held by the PCB. + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it (unless an error is returned). + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); + tcp_debug_print_state(pcb->state); + + if (pcb->state != LISTEN) { + /* Set a flag not to receive any more data... */ + pcb->flags |= TF_RXCLOSED; + } + /* ... and close */ + return tcp_close_shutdown(pcb, 1); +} + +/** + * @ingroup tcp_raw + * Causes all or part of a full-duplex connection of this PCB to be shut down. + * This doesn't deallocate the PCB unless shutting down both sides! + * Shutting down both sides is the same as calling tcp_close, so if it succeds, + * the PCB should not be referenced any more. + * + * @param pcb PCB to shutdown + * @param shut_rx shut down receive side if this is != 0 + * @param shut_tx shut down send side if this is != 0 + * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) + * another err_t on error. + */ +err_t +tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) +{ + if (pcb->state == LISTEN) { + return ERR_CONN; + } + if (shut_rx) { + /* shut down the receive side: set a flag not to receive any more data... */ + pcb->flags |= TF_RXCLOSED; + if (shut_tx) { + /* shutting down the tx AND rx side is the same as closing for the raw API */ + return tcp_close_shutdown(pcb, 1); + } + /* ... and free buffered data */ + if (pcb->refused_data != NULL) { + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + } + if (shut_tx) { + /* This can't happen twice since if it succeeds, the pcb's state is changed. + Only close in these states as the others directly deallocate the PCB */ + switch (pcb->state) { + case SYN_RCVD: + case ESTABLISHED: + case CLOSE_WAIT: + return tcp_close_shutdown(pcb, (u8_t)shut_rx); + default: + /* Not (yet?) connected, cannot shutdown the TX side as that would bring us + into CLOSED state, where the PCB is deallocated. */ + return ERR_CONN; + } + } + return ERR_OK; +} + +/** + * Abandons a connection and optionally sends a RST to the remote + * host. Deletes the local protocol control block. This is done when + * a connection is killed because of shortage of memory. + * + * @param pcb the tcp_pcb to abort + * @param reset boolean to indicate whether a reset should be sent + */ +void +tcp_abandon(struct tcp_pcb *pcb, int reset) +{ + u32_t seqno, ackno; +#if LWIP_CALLBACK_API + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + void *errf_arg; + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", + pcb->state != LISTEN); + /* Figure out on which TCP PCB list we are, and remove us. If we + are in an active state, call the receive function associated with + the PCB with a NULL argument, and send an RST to the remote end. */ + if (pcb->state == TIME_WAIT) { + tcp_pcb_remove(&tcp_tw_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + int send_rst = 0; + u16_t local_port = 0; + enum tcp_state last_state; + seqno = pcb->snd_nxt; + ackno = pcb->rcv_nxt; +#if LWIP_CALLBACK_API + errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + errf_arg = pcb->callback_arg; + if (pcb->state == CLOSED) { + if (pcb->local_port != 0) { + /* bound, not yet opened */ + TCP_RMV(&tcp_bound_pcbs, pcb); + } + } else { + send_rst = reset; + local_port = pcb->local_port; + TCP_PCB_REMOVE_ACTIVE(pcb); + } + if (pcb->unacked != NULL) { + tcp_segs_free(pcb->unacked); + } + if (pcb->unsent != NULL) { + tcp_segs_free(pcb->unsent); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + tcp_segs_free(pcb->ooseq); + } +#endif /* TCP_QUEUE_OOSEQ */ + tcp_backlog_accepted(pcb); + if (send_rst) { + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); + tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); + } + last_state = pcb->state; + memp_free(MEMP_TCP_PCB, pcb); + TCP_EVENT_ERR(last_state, errf, errf_arg, ERR_ABRT); + } +} + +/** + * @ingroup tcp_raw + * Aborts the connection by sending a RST (reset) segment to the remote + * host. The pcb is deallocated. This function never fails. + * + * ATTENTION: When calling this from one of the TCP callbacks, make + * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + * or you will risk accessing deallocated memory or memory leaks! + * + * @param pcb the tcp pcb to abort + */ +void +tcp_abort(struct tcp_pcb *pcb) +{ + tcp_abandon(pcb, 1); +} + +/** + * @ingroup tcp_raw + * Binds the connection to a local port number and IP address. If the + * IP address is not given (i.e., ipaddr == NULL), the IP address of + * the outgoing network interface is used instead. + * + * @param pcb the tcp_pcb to bind (no check is done whether this pcb is + * already bound!) + * @param ipaddr the local ip address to bind to (use IP4_ADDR_ANY to bind + * to any local address + * @param port the local port to bind to + * @return ERR_USE if the port is already in use + * ERR_VAL if bind failed because the PCB is not in a valid state + * ERR_OK if bound + */ +err_t +tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + int i; + int max_pcb_list = NUM_TCP_PCB_LISTS; + struct tcp_pcb *cpcb; + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + /* still need to check for ipaddr == NULL in IPv6 only case */ + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + + LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); + +#if SO_REUSE + /* Unless the REUSEADDR flag is set, + we have to check the pcbs in TIME-WAIT state, also. + We do not dump TIME_WAIT pcb's; they can still be matched by incoming + packets using both local and remote IP addresses and ports to distinguish. + */ + if (ip_get_option(pcb, SOF_REUSEADDR)) { + max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; + } +#endif /* SO_REUSE */ + + if (port == 0) { + port = tcp_new_port(); + if (port == 0) { + return ERR_BUF; + } + } else { + /* Check if the address already is in use (on all lists) */ + for (i = 0; i < max_pcb_list; i++) { + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { +#if SO_REUSE + /* Omit checking for the same port if both pcbs have REUSEADDR set. + For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in + tcp_connect. */ + if (!ip_get_option(pcb, SOF_REUSEADDR) || + !ip_get_option(cpcb, SOF_REUSEADDR)) +#endif /* SO_REUSE */ + { + /* @todo: check accept_any_ip_version */ + if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && + (ip_addr_isany(&cpcb->local_ip) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&cpcb->local_ip, ipaddr))) { + return ERR_USE; + } + } + } + } + } + } + + if (!ip_addr_isany(ipaddr)) { + ip_addr_set(&pcb->local_ip, ipaddr); + } + pcb->local_port = port; + TCP_REG(&tcp_bound_pcbs, pcb); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); + return ERR_OK; +} +#if LWIP_CALLBACK_API +/** + * Default accept callback if no accept callback is specified by the user. + */ +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + tcp_abort(pcb); + + return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * @ingroup tcp_raw + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen_with_backlog(tpcb, backlog); + */ +struct tcp_pcb * +tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); +} + +/** + * @ingroup tcp_raw + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @param err when NULL is returned, this contains the error reason + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); + */ +struct tcp_pcb * +tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) +{ + struct tcp_pcb_listen *lpcb = NULL; + err_t res; + + LWIP_UNUSED_ARG(backlog); + LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); + + /* already listening? */ + if (pcb->state == LISTEN) { + lpcb = (struct tcp_pcb_listen*)pcb; + res = ERR_ALREADY; + goto done; + } +#if SO_REUSE + if (ip_get_option(pcb, SOF_REUSEADDR)) { + /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage + is declared (listen-/connection-pcb), we have to make sure now that + this port is only used once for every local IP. */ + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if ((lpcb->local_port == pcb->local_port) && + ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + /* this address/port is already used */ + lpcb = NULL; + res = ERR_USE; + goto done; + } + } + } +#endif /* SO_REUSE */ + lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); + if (lpcb == NULL) { + res = ERR_MEM; + goto done; + } + lpcb->callback_arg = pcb->callback_arg; + lpcb->local_port = pcb->local_port; + lpcb->state = LISTEN; + lpcb->prio = pcb->prio; + lpcb->so_options = pcb->so_options; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; +#if LWIP_IPV4 && LWIP_IPV6 + IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + ip_addr_copy(lpcb->local_ip, pcb->local_ip); + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + memp_free(MEMP_TCP_PCB, pcb); +#if LWIP_CALLBACK_API + lpcb->accept = tcp_accept_null; +#endif /* LWIP_CALLBACK_API */ +#if TCP_LISTEN_BACKLOG + lpcb->accepts_pending = 0; + tcp_backlog_set(lpcb, backlog); +#endif /* TCP_LISTEN_BACKLOG */ + TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); + res = ERR_OK; +done: + if (err != NULL) { + *err = res; + } + return (struct tcp_pcb *)lpcb; +} + +/** + * Update the state that tracks the available window space to advertise. + * + * Returns how much extra window would be advertised if we sent an + * update now. + */ +u32_t +tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) +{ + u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; + + if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { + /* we can advertise more window */ + pcb->rcv_ann_wnd = pcb->rcv_wnd; + return new_right_edge - pcb->rcv_ann_right_edge; + } else { + if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { + /* Can happen due to other end sending out of advertised window, + * but within actual available (but not yet advertised) window */ + pcb->rcv_ann_wnd = 0; + } else { + /* keep the right edge of window constant */ + u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; +#if !LWIP_WND_SCALE + LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); +#endif + pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; + } + return 0; + } +} + +/** + * @ingroup tcp_raw + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + * + * @param pcb the tcp_pcb for which data is read + * @param len the amount of bytes that have been read by the application + */ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ + int wnd_inflation; + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_recved for listen-pcbs", + pcb->state != LISTEN); + + pcb->rcv_wnd += len; + if (pcb->rcv_wnd > TCP_WND_MAX(pcb)) { + pcb->rcv_wnd = TCP_WND_MAX(pcb); + } else if (pcb->rcv_wnd == 0) { + /* rcv_wnd overflowed */ + if ((pcb->state == CLOSE_WAIT) || (pcb->state == LAST_ACK)) { + /* In passive close, we allow this, since the FIN bit is added to rcv_wnd + by the stack itself, since it is not mandatory for an application + to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */ + pcb->rcv_wnd = TCP_WND_MAX(pcb); + } else { + LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0); + } + } + + wnd_inflation = tcp_update_rcv_ann_wnd(pcb); + + /* If the change in the right edge of window is significant (default + * watermark is TCP_WND/4), then send an explicit update now. + * Otherwise wait for a packet to be sent in the normal course of + * events (or more window to be available later) */ + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { + tcp_ack_now(pcb); + tcp_output(pcb); + } + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F").\n", + len, pcb->rcv_wnd, (u16_t)(TCP_WND_MAX(pcb) - pcb->rcv_wnd))); +} + +/** + * Allocate a new local TCP port. + * + * @return a new (free) local TCP port number + */ +static u16_t +tcp_new_port(void) +{ + u8_t i; + u16_t n = 0; + struct tcp_pcb *pcb; + +again: + if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) { + tcp_port = TCP_LOCAL_PORT_RANGE_START; + } + /* Check all PCB lists. */ + for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { + for (pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == tcp_port) { + if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + } + return tcp_port; +} + +/** + * @ingroup tcp_raw + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + * + * @param pcb the tcp_pcb used to establish the connection + * @param ipaddr the remote ip address to connect to + * @param port the remote tcp port to connect to + * @param connected callback function to call when connected (on error, + the err calback will be called) + * @return ERR_VAL if invalid arguments are given + * ERR_OK if connect request has been sent + * other err_t values if connect request couldn't be sent + */ +err_t +tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, + tcp_connected_fn connected) +{ + err_t ret; + u32_t iss; + u16_t old_local_port; + + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + + LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); + ip_addr_set(&pcb->remote_ip, ipaddr); + pcb->remote_port = port; + + /* check if we have a route to the remote host */ + if (ip_addr_isany(&pcb->local_ip)) { + /* no local IP address set, yet. */ + struct netif *netif; + const ip_addr_t *local_ip; + ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip); + if ((netif == NULL) || (local_ip == NULL)) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } + /* Use the address as local address of the pcb. */ + ip_addr_copy(pcb->local_ip, *local_ip); + } + + old_local_port = pcb->local_port; + if (pcb->local_port == 0) { + pcb->local_port = tcp_new_port(); + if (pcb->local_port == 0) { + return ERR_BUF; + } + } else { +#if SO_REUSE + if (ip_get_option(pcb, SOF_REUSEADDR)) { + /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure + now that the 5-tuple is unique. */ + struct tcp_pcb *cpcb; + int i; + /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ + for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { + for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if ((cpcb->local_port == pcb->local_port) && + (cpcb->remote_port == port) && + ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && + ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { + /* linux returns EISCONN here, but ERR_USE should be OK for us */ + return ERR_USE; + } + } + } + } +#endif /* SO_REUSE */ + } + + iss = tcp_next_iss(pcb); + pcb->rcv_nxt = 0; + pcb->snd_nxt = iss; + pcb->lastack = iss - 1; + pcb->snd_wl2 = iss - 1; + pcb->snd_lbb = iss - 1; + /* Start with a window that does not need scaling. When window scaling is + enabled and used, the window is enlarged when both sides agree on scaling. */ + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->snd_wnd = TCP_WND; + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = INITIAL_MSS; +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + pcb->cwnd = 1; +#if LWIP_CALLBACK_API + pcb->connected = connected; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(connected); +#endif /* LWIP_CALLBACK_API */ + + /* Send a SYN together with the MSS option. */ + ret = tcp_enqueue_flags(pcb, TCP_SYN); + if (ret == ERR_OK) { + /* SYN segment was enqueued, changed the pcbs state now */ + pcb->state = SYN_SENT; + if (old_local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + TCP_REG_ACTIVE(pcb); + MIB2_STATS_INC(mib2.tcpactiveopens); + + tcp_output(pcb); + } + return ret; +} + +/** + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_slowtmr(void) +{ + struct tcp_pcb *pcb, *prev; + tcpwnd_size_t eff_wnd; + u8_t pcb_remove; /* flag if a PCB should be removed */ + u8_t pcb_reset; /* flag if a RST should be sent when removing */ + err_t err; + + err = ERR_OK; + + ++tcp_ticks; + ++tcp_timer_ctr; + +tcp_slowtmr_start: + /* Steps through all of the active PCBs. */ + prev = NULL; + pcb = tcp_active_pcbs; + if (pcb == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); + } + while (pcb != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); + LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + if (pcb->last_timer == tcp_timer_ctr) { + /* skip this pcb, we have already processed it */ + pcb = pcb->next; + continue; + } + pcb->last_timer = tcp_timer_ctr; + + pcb_remove = 0; + pcb_reset = 0; + + if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); + } + else if (pcb->nrtx >= TCP_MAXRTX) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); + } else { + if (pcb->persist_backoff > 0) { + /* If snd_wnd is zero, use persist timer to send 1 byte probes + * instead of using the standard retransmission mechanism. */ + u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff-1]; + if (pcb->persist_cnt < backoff_cnt) { + pcb->persist_cnt++; + } + if (pcb->persist_cnt >= backoff_cnt) { + if (tcp_zero_window_probe(pcb) == ERR_OK) { + pcb->persist_cnt = 0; + if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { + pcb->persist_backoff++; + } + } + } + } else { + /* Increase the retransmission timer if it is running */ + if (pcb->rtime >= 0) { + ++pcb->rtime; + } + + if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { + /* Time for a retransmission. */ + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F + " pcb->rto %"S16_F"\n", + pcb->rtime, pcb->rto)); + + /* Double retransmission time-out unless we are trying to + * connect to somebody (i.e., we are in SYN_SENT). */ + if (pcb->state != SYN_SENT) { + u8_t backoff_idx = LWIP_MIN(pcb->nrtx, sizeof(tcp_backoff)-1); + pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[backoff_idx]; + } + + /* Reset the retransmission timer. */ + pcb->rtime = 0; + + /* Reduce congestion window and ssthresh. */ + eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); + pcb->ssthresh = eff_wnd >> 1; + if (pcb->ssthresh < (tcpwnd_size_t)(pcb->mss << 1)) { + pcb->ssthresh = (pcb->mss << 1); + } + pcb->cwnd = pcb->mss; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + + /* The following needs to be called AFTER cwnd is set to one + mss - STJ */ + tcp_rexmit_rto(pcb); + } + } + } + /* Check if this PCB has stayed too long in FIN-WAIT-2 */ + if (pcb->state == FIN_WAIT_2) { + /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ + if (pcb->flags & TF_RXCLOSED) { + /* PCB was fully closed (either through close() or SHUT_RDWR): + normal FIN-WAIT timeout handling. */ + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); + } + } + } + + /* Check if KEEPALIVE should be sent */ + if (ip_get_option(pcb, SOF_KEEPALIVE) && + ((pcb->state == ESTABLISHED) || + (pcb->state == CLOSE_WAIT))) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) + { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + ++pcb_remove; + ++pcb_reset; + } else if ((u32_t)(tcp_ticks - pcb->tmr) > + (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) + / TCP_SLOW_INTERVAL) + { + err = tcp_keepalive(pcb); + if (err == ERR_OK) { + pcb->keep_cnt_sent++; + } + } + } + + /* If this PCB has queued out of sequence data, but has been + inactive for too long, will drop the data (it will eventually + be retransmitted). */ +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL && + (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); + } +#endif /* TCP_QUEUE_OOSEQ */ + + /* Check if this PCB has stayed too long in SYN-RCVD */ + if (pcb->state == SYN_RCVD) { + if ((u32_t)(tcp_ticks - pcb->tmr) > + TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); + } + } + + /* Check if this PCB has stayed too long in LAST-ACK */ + if (pcb->state == LAST_ACK) { + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); + } + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; +#if LWIP_CALLBACK_API + tcp_err_fn err_fn = pcb->errf; +#endif /* LWIP_CALLBACK_API */ + void *err_arg; + enum tcp_state last_state; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_active_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); + tcp_active_pcbs = pcb->next; + } + + if (pcb_reset) { + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + } + + err_arg = pcb->callback_arg; + last_state = pcb->state; + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + + tcp_active_pcbs_changed = 0; + TCP_EVENT_ERR(last_state, err_fn, err_arg, ERR_ABRT); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + } else { + /* get the 'next' element now and work with 'prev' below (in case of abort) */ + prev = pcb; + pcb = pcb->next; + + /* We check if we should poll the connection. */ + ++prev->polltmr; + if (prev->polltmr >= prev->pollinterval) { + prev->polltmr = 0; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + tcp_active_pcbs_changed = 0; + TCP_EVENT_POLL(prev, err); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } + /* if err == ERR_ABRT, 'prev' is already deallocated */ + if (err == ERR_OK) { + tcp_output(prev); + } + } + } + } + + + /* Steps through all of the TIME-WAIT PCBs. */ + prev = NULL; + pcb = tcp_tw_pcbs; + while (pcb != NULL) { + LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + pcb_remove = 0; + + /* Check if this PCB has stayed long enough in TIME-WAIT */ + if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { + ++pcb_remove; + } + + /* If the PCB should be removed, do it. */ + if (pcb_remove) { + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); + /* Remove PCB from tcp_tw_pcbs list. */ + if (prev != NULL) { + LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); + prev->next = pcb->next; + } else { + /* This PCB was the first. */ + LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); + tcp_tw_pcbs = pcb->next; + } + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); + } else { + prev = pcb; + pcb = pcb->next; + } + } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_fasttmr(void) +{ + struct tcp_pcb *pcb; + + ++tcp_timer_ctr; + +tcp_fasttmr_start: + pcb = tcp_active_pcbs; + + while (pcb != NULL) { + if (pcb->last_timer != tcp_timer_ctr) { + struct tcp_pcb *next; + pcb->last_timer = tcp_timer_ctr; + /* send delayed ACKs */ + if (pcb->flags & TF_ACK_DELAY) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + tcp_output(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + /* send pending FIN */ + if (pcb->flags & TF_CLOSEPEND) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); + pcb->flags &= ~(TF_CLOSEPEND); + tcp_close_shutdown_fin(pcb); + } + + next = pcb->next; + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + tcp_active_pcbs_changed = 0; + tcp_process_refused_data(pcb); + if (tcp_active_pcbs_changed) { + /* application callback has changed the pcb list: restart the loop */ + goto tcp_fasttmr_start; + } + } + pcb = next; + } else { + pcb = pcb->next; + } + } +} + +/** Call tcp_output for all active pcbs that have TF_NAGLEMEMERR set */ +void +tcp_txnow(void) +{ + struct tcp_pcb *pcb; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->flags & TF_NAGLEMEMERR) { + tcp_output(pcb); + } + } +} + +/** Pass pcb->refused_data to the recv callback */ +err_t +tcp_process_refused_data(struct tcp_pcb *pcb) +{ +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + struct pbuf *rest; + while (pcb->refused_data != NULL) +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + { + err_t err; + u8_t refused_flags = pcb->refused_data->flags; + /* set pcb->refused_data to NULL in case the callback frees it and then + closes the pcb */ + struct pbuf *refused_data = pcb->refused_data; +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + pbuf_split_64k(refused_data, &rest); + pcb->refused_data = rest; +#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = NULL; +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + /* Notify again application with data previously received. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); + TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); + if (err == ERR_OK) { + /* did refused_data include a FIN? */ + if (refused_flags & PBUF_FLAG_TCP_FIN +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + && (rest == NULL) +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + ) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + } + } else if (err == ERR_ABRT) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + /* Drop incoming packets because pcb is "full" (only if the incoming + segment contains data). */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); + return ERR_ABRT; + } else { + /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_cat(refused_data, rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = refused_data; + return ERR_INPROGRESS; + } + } + return ERR_OK; +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + * @param seg tcp_seg list of TCP segments to free + */ +void +tcp_segs_free(struct tcp_seg *seg) +{ + while (seg != NULL) { + struct tcp_seg *next = seg->next; + tcp_seg_free(seg); + seg = next; + } +} + +/** + * Frees a TCP segment (tcp_seg structure). + * + * @param seg single tcp_seg to free + */ +void +tcp_seg_free(struct tcp_seg *seg) +{ + if (seg != NULL) { + if (seg->p != NULL) { + pbuf_free(seg->p); +#if TCP_DEBUG + seg->p = NULL; +#endif /* TCP_DEBUG */ + } + memp_free(MEMP_TCP_SEG, seg); + } +} + +/** + * Sets the priority of a connection. + * + * @param pcb the tcp_pcb to manipulate + * @param prio new priority + */ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ + pcb->prio = prio; +} + +#if TCP_QUEUE_OOSEQ +/** + * Returns a copy of the given TCP segment. + * The pbuf and data are not copied, only the pointers + * + * @param seg the old tcp_seg + * @return a copy of seg + */ +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ + struct tcp_seg *cseg; + + cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); + if (cseg == NULL) { + return NULL; + } + SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); + pbuf_ref(cseg->p); + return cseg; +} +#endif /* TCP_QUEUE_OOSEQ */ + +#if LWIP_CALLBACK_API +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } else if (err == ERR_OK) { + return tcp_close(pcb); + } + return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Kills the oldest active connection that has the same or lower priority than + * 'prio'. + * + * @param prio minimum priority + */ +static void +tcp_kill_prio(u8_t prio) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + u8_t mprio; + + mprio = LWIP_MIN(TCP_PRIO_MAX, prio); + + /* We kill the oldest active connection that has lower priority than prio. */ + inactivity = 0; + inactive = NULL; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->prio <= mprio && + (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + mprio = pcb->prio; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/** + * Kills the oldest connection that is in specific state. + * Called from tcp_alloc() for LAST_ACK and CLOSING if no more connections are available. + */ +static void +tcp_kill_state(enum tcp_state state) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + LWIP_ASSERT("invalid state", (state == CLOSING) || (state == LAST_ACK)); + + inactivity = 0; + inactive = NULL; + /* Go through the list of active pcbs and get the oldest pcb that is in state + CLOSING/LAST_ACK. */ + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->state == state) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", + tcp_state_str[state], (void *)inactive, inactivity)); + /* Don't send a RST, since no data is lost. */ + tcp_abandon(inactive, 0); + } +} + +/** + * Kills the oldest connection that is in TIME_WAIT state. + * Called from tcp_alloc() if no more connections are available. + */ +static void +tcp_kill_timewait(void) +{ + struct tcp_pcb *pcb, *inactive; + u32_t inactivity; + + inactivity = 0; + inactive = NULL; + /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { + inactivity = tcp_ticks - pcb->tmr; + inactive = pcb; + } + } + if (inactive != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", + (void *)inactive, inactivity)); + tcp_abort(inactive); + } +} + +/** + * Allocate a new tcp_pcb structure. + * + * @param prio priority for the new pcb + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ + struct tcp_pcb *pcb; + + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in TIME-WAIT. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); + tcp_kill_timewait(); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in LAST-ACK (these wouldn't go to TIME-WAIT). */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest LAST-ACK connection\n")); + tcp_kill_state(LAST_ACK); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing oldest connection in CLOSING. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest CLOSING connection\n")); + tcp_kill_state(CLOSING); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb == NULL) { + /* Try killing active connections with lower priority than the new one. */ + LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); + tcp_kill_prio(prio); + /* Try to allocate a tcp_pcb again. */ + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed multiple times before */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* adjust err stats: memp_malloc failed above */ + MEMP_STATS_DEC(err, MEMP_TCP_PCB); + } + } + if (pcb != NULL) { + /* zero out the whole pcb, so there is no need to initialize members to zero */ + memset(pcb, 0, sizeof(struct tcp_pcb)); + pcb->prio = prio; + pcb->snd_buf = TCP_SND_BUF; + /* Start with a window that does not need scaling. When window scaling is + enabled and used, the window is enlarged when both sides agree on scaling. */ + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); + pcb->ttl = TCP_TTL; + /* As initial send MSS, we use TCP_MSS but limit it to 536. + The send MSS is updated when an MSS option is received. */ + pcb->mss = INITIAL_MSS; + pcb->rto = 3000 / TCP_SLOW_INTERVAL; + pcb->sv = 3000 / TCP_SLOW_INTERVAL; + pcb->rtime = -1; + pcb->cwnd = 1; + pcb->tmr = tcp_ticks; + pcb->last_timer = tcp_timer_ctr; + + /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example + of using the largest advertised receive window. We've seen complications with + receiving TCPs that use window scaling and/or window auto-tuning where the + initial advertised window is very small and then grows rapidly once the + connection is established. To avoid these complications, we set ssthresh to the + largest effective cwnd (amount of in-flight data) that the sender can have. */ + pcb->ssthresh = TCP_SND_BUF; + +#if LWIP_CALLBACK_API + pcb->recv = tcp_recv_null; +#endif /* LWIP_CALLBACK_API */ + + /* Init KEEPALIVE timer */ + pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; + +#if LWIP_TCP_KEEPALIVE + pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; + pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; +#endif /* LWIP_TCP_KEEPALIVE */ + } + return pcb; +} + +/** + * @ingroup tcp_raw + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * + * @internal: Maybe there should be a idle TCP PCB list where these + * PCBs are put on. Port reservation using tcp_bind() is implemented but + * allocated pcbs that are not bound can't be killed automatically if wanting + * to allocate a pcb with higher prio (@see tcp_kill_prio()) + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new(void) +{ + return tcp_alloc(TCP_PRIO_NORMAL); +} + +/** + * @ingroup tcp_raw + * Creates a new TCP protocol control block but doesn't + * place it on any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) connections, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new_ip_type(u8_t type) +{ + struct tcp_pcb * pcb; + pcb = tcp_alloc(TCP_PRIO_NORMAL); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** + * @ingroup tcp_raw + * Used to specify the argument that should be passed callback + * functions. + * + * @param pcb tcp_pcb to set the callback argument + * @param arg void pointer argument to pass to callback functions + */ +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{ + /* This function is allowed to be called for both listen pcbs and + connection pcbs. */ + if (pcb != NULL) { + pcb->callback_arg = arg; + } +} +#if LWIP_CALLBACK_API + +/** + * @ingroup tcp_raw + * Used to specify the function that should be called when a TCP + * connection receives data. + * + * @param pcb tcp_pcb to set the recv callback + * @param recv callback function to call for this pcb when data is received + */ +void +tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) +{ + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); + pcb->recv = recv; + } +} + +/** + * @ingroup tcp_raw + * Used to specify the function that should be called when TCP data + * has been successfully delivered to the remote host. + * + * @param pcb tcp_pcb to set the sent callback + * @param sent callback function to call for this pcb when data is successfully sent + */ +void +tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) +{ + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); + pcb->sent = sent; + } +} + +/** + * @ingroup tcp_raw + * Used to specify the function that should be called when a fatal error + * has occurred on the connection. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param pcb tcp_pcb to set the err callback + * @param err callback function to call for this pcb when a fatal error + * has occurred on the connection + */ +void +tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) +{ + if (pcb != NULL) { + LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); + pcb->errf = err; + } +} + +/** + * @ingroup tcp_raw + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + * + * @param pcb tcp_pcb to set the accept callback + * @param accept callback function to call for this pcb when LISTENing + * connection has been connected to another host + */ +void +tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) +{ + if ((pcb != NULL) && (pcb->state == LISTEN)) { + struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen*)pcb; + lpcb->accept = accept; + } +} +#endif /* LWIP_CALLBACK_API */ + + +/** + * @ingroup tcp_raw + * Used to specify the function that should be called periodically + * from TCP. The interval is specified in terms of the TCP coarse + * timer interval, which is called twice a second. + * + */ +void +tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) +{ + LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); +#if LWIP_CALLBACK_API + pcb->poll = poll; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(poll); +#endif /* LWIP_CALLBACK_API */ + pcb->pollinterval = interval; +} + +/** + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory + * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). + * + * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! + */ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ + if (pcb->state != CLOSED && + pcb->state != TIME_WAIT && + pcb->state != LISTEN) { + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + + tcp_backlog_accepted(pcb); + + if (pcb->refused_data != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + if (pcb->unsent != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); + } + if (pcb->unacked != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); + } +#if TCP_QUEUE_OOSEQ + if (pcb->ooseq != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); + } + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ + + /* Stop the retransmission timer as it will expect data on unacked + queue if it fires */ + pcb->rtime = -1; + + tcp_segs_free(pcb->unsent); + tcp_segs_free(pcb->unacked); + pcb->unacked = pcb->unsent = NULL; +#if TCP_OVERSIZE + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + } +} + +/** + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + * @param pcblist PCB list to purge. + * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! + */ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ + TCP_RMV(pcblist, pcb); + + tcp_pcb_purge(pcb); + + /* if there is an outstanding delayed ACKs, send it */ + if (pcb->state != TIME_WAIT && + pcb->state != LISTEN && + pcb->flags & TF_ACK_DELAY) { + pcb->flags |= TF_ACK_NOW; + tcp_output(pcb); + } + + if (pcb->state != LISTEN) { + LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); + LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); +#if TCP_QUEUE_OOSEQ + LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); +#endif /* TCP_QUEUE_OOSEQ */ + } + + pcb->state = CLOSED; + /* reset the local port to prevent the pcb from being 'bound' */ + pcb->local_port = 0; + + LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} + +/** + * Calculates a new initial sequence number for new connections. + * + * @return u32_t pseudo random sequence number + */ +u32_t +tcp_next_iss(struct tcp_pcb *pcb) +{ +#ifdef LWIP_HOOK_TCP_ISN + return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); +#else /* LWIP_HOOK_TCP_ISN */ + static u32_t iss = 6510; + + LWIP_UNUSED_ARG(pcb); + + iss += tcp_ticks; /* XXX */ + return iss; +#endif /* LWIP_HOOK_TCP_ISN */ +} + +#if TCP_CALCULATE_EFF_SEND_MSS +/** + * Calculates the effective send mss that can be used for a specific IP address + * by using ip_route to determine the netif used to send to the address and + * calculating the minimum of TCP_MSS and that netif's mtu (if set). + */ +u16_t +tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest +#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING + , const ip_addr_t *src +#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ + ) +{ + u16_t mss_s; + struct netif *outif; + s16_t mtu; + + outif = ip_route(src, dest); +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_IS_V6(dest)) +#endif /* LWIP_IPV4 */ + { + /* First look in destination cache, to see if there is a Path MTU. */ + mtu = nd6_get_destination_mtu(ip_2_ip6(dest), outif); + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + if (outif == NULL) { + return sendmss; + } + mtu = outif->mtu; + } +#endif /* LWIP_IPV4 */ + + if (mtu != 0) { +#if LWIP_IPV6 +#if LWIP_IPV4 + if (IP_IS_V6(dest)) +#endif /* LWIP_IPV4 */ + { + mss_s = mtu - IP6_HLEN - TCP_HLEN; + } +#if LWIP_IPV4 + else +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + { + mss_s = mtu - IP_HLEN - TCP_HLEN; + } +#endif /* LWIP_IPV4 */ + /* RFC 1122, chap 4.2.2.6: + * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize + * We correct for TCP options in tcp_write(), and don't support IP options. + */ + sendmss = LWIP_MIN(sendmss, mss_s); + } + return sendmss; +} +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +/** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */ +static void +tcp_netif_ip_addr_changed_pcblist(const ip_addr_t* old_addr, struct tcp_pcb* pcb_list) +{ + struct tcp_pcb *pcb; + pcb = pcb_list; + while (pcb != NULL) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&pcb->local_ip, old_addr) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) +#endif /* LWIP_AUTOIP */ + ) { + /* this connection must be aborted */ + struct tcp_pcb *next = pcb->next; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); + tcp_abort(pcb); + pcb = next; + } else { + pcb = pcb->next; + } + } +} + +/** This function is called from netif.c when address is changed or netif is removed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change or NULL if netif has been removed + */ +void +tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr) +{ + struct tcp_pcb_listen *lpcb, *next; + + if (!ip_addr_isany(old_addr)) { + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); + + if (!ip_addr_isany(new_addr)) { + /* PCB bound to current local interface address? */ + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) { + next = lpcb->next; + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { + /* The PCB is listening to the old ipaddr and + * is set to listen to the new one instead */ + ip_addr_copy(lpcb->local_ip, *new_addr); + } + } + } + } +} + +const char* +tcp_debug_state_str(enum tcp_state s) +{ + return tcp_state_str[s]; +} + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +/** + * Print a tcp header for debugging purposes. + * + * @param tcphdr pointer to a struct tcp_hdr + */ +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ + LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", + lwip_ntohl(tcphdr->seqno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", + lwip_ntohl(tcphdr->ackno))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", + TCPH_HDRLEN(tcphdr), + (u16_t)(TCPH_FLAGS(tcphdr) >> 5 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 4 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 3 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1), + (u16_t)(TCPH_FLAGS(tcphdr) & 1), + lwip_ntohs(tcphdr->wnd))); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", + lwip_ntohs(tcphdr->chksum), lwip_ntohs(tcphdr->urgp))); + LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} + +/** + * Print a tcp state for debugging purposes. + * + * @param s enum tcp_state to print + */ +void +tcp_debug_print_state(enum tcp_state s) +{ + LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); +} + +/** + * Print tcp flags for debugging purposes. + * + * @param flags tcp flags, all active flags are printed + */ +void +tcp_debug_print_flags(u8_t flags) +{ + if (flags & TCP_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); + } + if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); + } + if (flags & TCP_RST) { + LWIP_DEBUGF(TCP_DEBUG, ("RST ")); + } + if (flags & TCP_PSH) { + LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); + } + if (flags & TCP_ACK) { + LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); + } + if (flags & TCP_URG) { + LWIP_DEBUGF(TCP_DEBUG, ("URG ")); + } + if (flags & TCP_ECE) { + LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); + } + if (flags & TCP_CWR) { + LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); +} + +/** + * Print all tcp_pcbs in every list for debugging purposes. + */ +void +tcp_debug_print_pcbs(void) +{ + struct tcp_pcb *pcb; + struct tcp_pcb_listen *pcbl; + + LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } + + LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); + for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F" ", pcbl->local_port)); + tcp_debug_print_state(pcbl->state); + } + + LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", + pcb->local_port, pcb->remote_port, + pcb->snd_nxt, pcb->rcv_nxt)); + tcp_debug_print_state(pcb->state); + } +} + +/** + * Check state consistency of the tcp_pcb lists. + */ +s16_t +tcp_pcbs_sane(void) +{ + struct tcp_pcb *pcb; + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); + LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + } + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + } + return 1; +} +#endif /* TCP_DEBUG */ + +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/tcp_in.c b/Sming/third-party/lwip2/lwip2-src/src/core/tcp_in.c new file mode 100644 index 0000000000..ba879284f2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/tcp_in.c @@ -0,0 +1,1818 @@ +/** + * @file + * Transmission Control Protocol, incoming traffic + * + * The input processing functions of the TCP layer. + * + * These functions are generally called in the order (ip_input() ->) + * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcp_priv.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#if LWIP_ND6_TCP_REACHABILITY_HINTS +#include "lwip/nd6.h" +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +/** Initial CWND calculation as defined RFC 2581 */ +#define LWIP_TCP_CALC_INITIAL_CWND(mss) LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U)); + +/* These variables are global to all functions involved in the input + processing of TCP segments. They are set by the tcp_input() + function. */ +static struct tcp_seg inseg; +static struct tcp_hdr *tcphdr; +static u16_t tcphdr_optlen; +static u16_t tcphdr_opt1len; +static u8_t* tcphdr_opt2; +static u16_t tcp_optidx; +static u32_t seqno, ackno; +static tcpwnd_size_t recv_acked; +static u16_t tcplen; +static u8_t flags; + +static u8_t recv_flags; +static struct pbuf *recv_data; + +struct tcp_pcb *tcp_input_pcb; + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb); +static void tcp_receive(struct tcp_pcb *pcb); +static void tcp_parseopt(struct tcp_pcb *pcb); + +static void tcp_listen_input(struct tcp_pcb_listen *pcb); +static void tcp_timewait_input(struct tcp_pcb *pcb); + +/** + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + * + * @param p received TCP segment to process (p->payload pointing to the TCP header) + * @param inp network interface on which this segment was received + */ +void +tcp_input(struct pbuf *p, struct netif *inp) +{ + struct tcp_pcb *pcb, *prev; + struct tcp_pcb_listen *lpcb; +#if SO_REUSE + struct tcp_pcb *lpcb_prev = NULL; + struct tcp_pcb_listen *lpcb_any = NULL; +#endif /* SO_REUSE */ + u8_t hdrlen_bytes; + err_t err; + + LWIP_UNUSED_ARG(inp); + + PERF_START; + + TCP_STATS_INC(tcp.recv); + MIB2_STATS_INC(mib2.tcpinsegs); + + tcphdr = (struct tcp_hdr *)p->payload; + +#if TCP_INPUT_DEBUG + tcp_debug_print(tcphdr); +#endif + + /* Check that TCP header fits in payload */ + if (p->len < TCP_HLEN) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* Don't even process incoming broadcasts/multicasts. */ + if (ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()) || + ip_addr_ismulticast(ip_current_dest_addr())) { + TCP_STATS_INC(tcp.proterr); + goto dropped; + } + +#if CHECKSUM_CHECK_TCP + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { + /* Verify TCP checksum. */ + u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + ip_current_src_addr(), ip_current_dest_addr()); + if (chksum != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + chksum)); + tcp_debug_print(tcphdr); + TCP_STATS_INC(tcp.chkerr); + goto dropped; + } + } +#endif /* CHECKSUM_CHECK_TCP */ + + /* sanity-check header length */ + hdrlen_bytes = TCPH_HDRLEN(tcphdr) * 4; + if ((hdrlen_bytes < TCP_HLEN) || (hdrlen_bytes > p->tot_len)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: invalid header length (%"U16_F")\n", (u16_t)hdrlen_bytes)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* Move the payload pointer in the pbuf so that it points to the + TCP data instead of the TCP header. */ + tcphdr_optlen = hdrlen_bytes - TCP_HLEN; + tcphdr_opt2 = NULL; + if (p->len >= hdrlen_bytes) { + /* all options are in the first pbuf */ + tcphdr_opt1len = tcphdr_optlen; + pbuf_header(p, -(s16_t)hdrlen_bytes); /* cannot fail */ + } else { + u16_t opt2len; + /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ + /* there must be a next pbuf, due to hdrlen_bytes sanity check above */ + LWIP_ASSERT("p->next != NULL", p->next != NULL); + + /* advance over the TCP header (cannot fail) */ + pbuf_header(p, -TCP_HLEN); + + /* determine how long the first and second parts of the options are */ + tcphdr_opt1len = p->len; + opt2len = tcphdr_optlen - tcphdr_opt1len; + + /* options continue in the next pbuf: set p to zero length and hide the + options in the next pbuf (adjusting p->tot_len) */ + pbuf_header(p, -(s16_t)tcphdr_opt1len); + + /* check that the options fit in the second pbuf */ + if (opt2len > p->next->len) { + /* drop short packets */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: options overflow second pbuf (%"U16_F" bytes)\n", p->next->len)); + TCP_STATS_INC(tcp.lenerr); + goto dropped; + } + + /* remember the pointer to the second part of the options */ + tcphdr_opt2 = (u8_t*)p->next->payload; + + /* advance p->next to point after the options, and manually + adjust p->tot_len to keep it consistent with the changed p->next */ + pbuf_header(p->next, -(s16_t)opt2len); + p->tot_len -= opt2len; + + LWIP_ASSERT("p->len == 0", p->len == 0); + LWIP_ASSERT("p->tot_len == p->next->tot_len", p->tot_len == p->next->tot_len); + } + + /* Convert fields in TCP header to host byte order. */ + tcphdr->src = lwip_ntohs(tcphdr->src); + tcphdr->dest = lwip_ntohs(tcphdr->dest); + seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno); + ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno); + tcphdr->wnd = lwip_ntohs(tcphdr->wnd); + + flags = TCPH_FLAGS(tcphdr); + tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); + + /* Demultiplex an incoming segment. First, we check if it is destined + for an active connection. */ + prev = NULL; + + for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); + LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); + LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); + if (prev != NULL) { + prev->next = pcb->next; + pcb->next = tcp_active_pcbs; + tcp_active_pcbs = pcb; + } else { + TCP_STATS_INC(tcp.cachehit); + } + LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); + break; + } + prev = pcb; + } + + if (pcb == NULL) { + /* If it did not go to an active connection, we check the connections + in the TIME-WAIT state. */ + for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { + LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + if (pcb->remote_port == tcphdr->src && + pcb->local_port == tcphdr->dest && + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && + ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + /* We don't really care enough to move this PCB to the front + of the list since we are not very likely to receive that + many segments for connections in TIME-WAIT. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); + tcp_timewait_input(pcb); + pbuf_free(p); + return; + } + } + + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ + prev = NULL; + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if (lpcb->local_port == tcphdr->dest) { + if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { + /* found an ANY TYPE (IPv4/IPv6) match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ + break; +#endif /* SO_REUSE */ + } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { + if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { + /* found an exact match */ + break; + } else if (ip_addr_isany(&lpcb->local_ip)) { + /* found an ANY-match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ + break; + #endif /* SO_REUSE */ + } + } + } + prev = (struct tcp_pcb *)lpcb; + } +#if SO_REUSE + /* first try specific local IP */ + if (lpcb == NULL) { + /* only pass to ANY if no specific local IP has been found */ + lpcb = lpcb_any; + prev = lpcb_prev; + } +#endif /* SO_REUSE */ + if (lpcb != NULL) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if (prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } else { + TCP_STATS_INC(tcp.cachehit); + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb); + pbuf_free(p); + return; + } + } + +#if TCP_INPUT_DEBUG + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); + tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + + if (pcb != NULL) { + /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_INPUT_DEBUG */ + + /* Set up a tcp_seg structure. */ + inseg.next = NULL; + inseg.len = p->tot_len; + inseg.p = p; + inseg.tcphdr = tcphdr; + + recv_data = NULL; + recv_flags = 0; + recv_acked = 0; + + if (flags & TCP_PSH) { + p->flags |= PBUF_FLAG_PUSH; + } + + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + if ((tcp_process_refused_data(pcb) == ERR_ABRT) || + ((pcb->refused_data != NULL) && (tcplen > 0))) { + /* pcb has been aborted or refused data is still refused and the new + segment contains data */ + if (pcb->rcv_ann_wnd == 0) { + /* this is a zero-window probe, we respond to it with current RCV.NXT + and drop the data segment */ + tcp_send_empty_ack(pcb); + } + TCP_STATS_INC(tcp.drop); + MIB2_STATS_INC(mib2.tcpinerrs); + goto aborted; + } + } + tcp_input_pcb = pcb; + err = tcp_process(pcb); + /* A return value of ERR_ABRT means that tcp_abort() was called + and that the pcb has been freed. If so, we don't do anything. */ + if (err != ERR_ABRT) { + if (recv_flags & TF_RESET) { + /* TF_RESET means that the connection was reset by the other + end. We then call the error callback to inform the + application that the connection is dead before we + deallocate the PCB. */ + TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + } else { + err = ERR_OK; + /* If the application has registered a "sent" function to be + called when new send buffer space is available, we call it + now. */ + if (recv_acked > 0) { + u16_t acked16; +#if LWIP_WND_SCALE + /* recv_acked is u32_t but the sent callback only takes a u16_t, + so we might have to call it multiple times. */ + u32_t acked = recv_acked; + while (acked > 0) { + acked16 = (u16_t)LWIP_MIN(acked, 0xffffu); + acked -= acked16; +#else + { + acked16 = recv_acked; +#endif + TCP_EVENT_SENT(pcb, (u16_t)acked16, err); + if (err == ERR_ABRT) { + goto aborted; + } + } + recv_acked = 0; + } + if (recv_flags & TF_CLOSED) { + /* The connection has been closed and we will deallocate the + PCB. */ + if (!(pcb->flags & TF_RXCLOSED)) { + /* Connection closed although the application has only shut down the + tx side: call the PCB's err callback and indicate the closure to + ensure the application doesn't continue using the PCB. */ + TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); + } + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); + goto aborted; + } +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + while (recv_data != NULL) { + struct pbuf *rest = NULL; + pbuf_split_64k(recv_data, &rest); +#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + if (recv_data != NULL) { +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + + LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); + if (pcb->flags & TF_RXCLOSED) { + /* received data although already closed -> abort (send RST) to + notify the remote host that not all data has been processed */ + pbuf_free(recv_data); +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_free(rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + tcp_abort(pcb); + goto aborted; + } + + /* Notify application that data has been received. */ + TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + if (err == ERR_ABRT) { +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_free(rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + goto aborted; + } + + /* If the upper layer can't receive this data, store it */ + if (err != ERR_OK) { +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + if (rest != NULL) { + pbuf_cat(recv_data, rest); + } +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + pcb->refused_data = recv_data; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); +#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE + break; + } else { + /* Upper layer received the data, go on with the rest if > 64K */ + recv_data = rest; +#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + } + } + + /* If a FIN segment was received, we call the callback + function with a NULL buffer to indicate EOF. */ + if (recv_flags & TF_GOT_FIN) { + if (pcb->refused_data != NULL) { + /* Delay this if we have refused data. */ + pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; + } else { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto aborted; + } + } + } + + tcp_input_pcb = NULL; + /* Try to send something out. */ + tcp_output(pcb); +#if TCP_INPUT_DEBUG +#if TCP_DEBUG + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + } + } + /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). + Below this line, 'pcb' may not be dereferenced! */ +aborted: + tcp_input_pcb = NULL; + recv_data = NULL; + + /* give up our reference to inseg.p */ + if (inseg.p != NULL) + { + pbuf_free(inseg.p); + inseg.p = NULL; + } + } else { + + /* If no matching PCB was found, send a TCP RST (reset) to the + sender. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); + if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { + TCP_STATS_INC(tcp.proterr); + TCP_STATS_INC(tcp.drop); + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } + pbuf_free(p); + } + + LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); + PERF_STOP("tcp_input"); + return; +dropped: + TCP_STATS_INC(tcp.drop); + MIB2_STATS_INC(mib2.tcpinerrs); + pbuf_free(p); +} + +/** + * Called by tcp_input() when a segment arrives for a listening + * connection (from tcp_input()). + * + * @param pcb the tcp_pcb_listen for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static void +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ + struct tcp_pcb *npcb; + u32_t iss; + err_t rc; + + if (flags & TCP_RST) { + /* An incoming RST should be ignored. Return. */ + return; + } + + /* In the LISTEN state, we check for incoming SYN segments, + creates a new PCB, and responds with a SYN|ACK. */ + if (flags & TCP_ACK) { + /* For incoming segments with the ACK flag set, respond with a + RST. */ + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } else if (flags & TCP_SYN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); +#if TCP_LISTEN_BACKLOG + if (pcb->accepts_pending >= pcb->backlog) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); + return; + } +#endif /* TCP_LISTEN_BACKLOG */ + npcb = tcp_alloc(pcb->prio); + /* If a new PCB could not be created (probably due to lack of memory), + we don't do anything, but rely on the sender will retransmit the + SYN at a time when we have more memory available. */ + if (npcb == NULL) { + err_t err; + LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); + TCP_STATS_INC(tcp.memerr); + TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); + LWIP_UNUSED_ARG(err); /* err not useful here */ + return; + } +#if TCP_LISTEN_BACKLOG + pcb->accepts_pending++; + npcb->flags |= TF_BACKLOGPEND; +#endif /* TCP_LISTEN_BACKLOG */ + /* Set up the new PCB. */ + ip_addr_copy(npcb->local_ip, *ip_current_dest_addr()); + ip_addr_copy(npcb->remote_ip, *ip_current_src_addr()); + npcb->local_port = pcb->local_port; + npcb->remote_port = tcphdr->src; + npcb->state = SYN_RCVD; + npcb->rcv_nxt = seqno + 1; + npcb->rcv_ann_right_edge = npcb->rcv_nxt; + iss = tcp_next_iss(npcb); + npcb->snd_wl2 = iss; + npcb->snd_nxt = iss; + npcb->lastack = iss; + npcb->snd_lbb = iss; + npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ + npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + npcb->listener = pcb; +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + /* inherit socket options */ + npcb->so_options = pcb->so_options & SOF_INHERITED; + /* Register the new PCB so that we can begin receiving segments + for it. */ + TCP_REG_ACTIVE(npcb); + + /* Parse any options in the SYN. */ + tcp_parseopt(npcb); + npcb->snd_wnd = tcphdr->wnd; + npcb->snd_wnd_max = npcb->snd_wnd; + +#if TCP_CALCULATE_EFF_SEND_MSS + npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + MIB2_STATS_INC(mib2.tcppassiveopens); + + /* Send a SYN|ACK together with the MSS option. */ + rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); + if (rc != ERR_OK) { + tcp_abandon(npcb, 0); + return; + } + tcp_output(npcb); + } + return; +} + +/** + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static void +tcp_timewait_input(struct tcp_pcb *pcb) +{ + /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ + /* RFC 793 3.9 Event Processing - Segment Arrives: + * - first check sequence number - we skip that one in TIME_WAIT (always + * acceptable since we only send ACKs) + * - second check the RST bit (... return) */ + if (flags & TCP_RST) { + return; + } + /* - fourth, check the SYN bit, */ + if (flags & TCP_SYN) { + /* If an incoming segment is not acceptable, an acknowledgment + should be sent in reply */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { + /* If the SYN is in the window it is an error, send a reset */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + return; + } + } else if (flags & TCP_FIN) { + /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. + Restart the 2 MSL time-wait timeout.*/ + pcb->tmr = tcp_ticks; + } + + if ((tcplen > 0)) { + /* Acknowledge data, FIN or out-of-window SYN */ + pcb->flags |= TF_ACK_NOW; + tcp_output(pcb); + } + return; +} + +/** + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + * involved is passed as a parameter to this function + */ +static err_t +tcp_process(struct tcp_pcb *pcb) +{ + struct tcp_seg *rseg; + u8_t acceptable = 0; + err_t err; + + err = ERR_OK; + + /* Process incoming RST segments. */ + if (flags & TCP_RST) { + /* First, determine if the reset is acceptable. */ + if (pcb->state == SYN_SENT) { + /* "In the SYN-SENT state (a RST received in response to an initial SYN), + the RST is acceptable if the ACK field acknowledges the SYN." */ + if (ackno == pcb->snd_nxt) { + acceptable = 1; + } + } else { + /* "In all states except SYN-SENT, all reset (RST) segments are validated + by checking their SEQ-fields." */ + if (seqno == pcb->rcv_nxt) { + acceptable = 1; + } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd)) { + /* If the sequence number is inside the window, we only send an ACK + and wait for a re-send with matching sequence number. + This violates RFC 793, but is required to protection against + CVE-2004-0230 (RST spoofing attack). */ + tcp_ack_now(pcb); + } + } + + if (acceptable) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); + LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); + recv_flags |= TF_RESET; + pcb->flags &= ~TF_ACK_DELAY; + return ERR_RST; + } else { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", + seqno, pcb->rcv_nxt)); + return ERR_OK; + } + } + + if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { + /* Cope with new connection attempt after remote end crashed */ + tcp_ack_now(pcb); + return ERR_OK; + } + + if ((pcb->flags & TF_RXCLOSED) == 0) { + /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ + pcb->tmr = tcp_ticks; + } + pcb->keep_cnt_sent = 0; + + tcp_parseopt(pcb); + + /* Do different things depending on the TCP state. */ + switch (pcb->state) { + case SYN_SENT: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, + pcb->snd_nxt, lwip_ntohl(pcb->unacked->tcphdr->seqno))); + /* received SYN ACK with expected sequence number? */ + if ((flags & TCP_ACK) && (flags & TCP_SYN) + && (ackno == pcb->lastack + 1)) { + pcb->rcv_nxt = seqno + 1; + pcb->rcv_ann_right_edge = pcb->rcv_nxt; + pcb->lastack = ackno; + pcb->snd_wnd = tcphdr->wnd; + pcb->snd_wnd_max = pcb->snd_wnd; + pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ + pcb->state = ESTABLISHED; + +#if TCP_CALCULATE_EFF_SEND_MSS + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + + pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); + --pcb->snd_queuelen; + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); + rseg = pcb->unacked; + if (rseg == NULL) { + /* might happen if tcp_output fails in tcp_rexmit_rto() + in which case the segment is on the unsent list */ + rseg = pcb->unsent; + LWIP_ASSERT("no segment to free", rseg != NULL); + pcb->unsent = rseg->next; + } else { + pcb->unacked = rseg->next; + } + tcp_seg_free(rseg); + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if (pcb->unacked == NULL) { + pcb->rtime = -1; + } else { + pcb->rtime = 0; + pcb->nrtx = 0; + } + + /* Call the user specified function to call when successfully + * connected. */ + TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + tcp_ack_now(pcb); + } + /* received ACK? possibly a half-open connection */ + else if (flags & TCP_ACK) { + /* send a RST to bring the other side in a non-synchronized state. */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + /* Resend SYN immediately (don't wait for rto timeout) to establish + connection faster, but do not send more SYNs than we otherwise would + have, or we might get caught in a loop on loopback interfaces. */ + if (pcb->nrtx < TCP_SYNMAXRTX) { + pcb->rtime = 0; + tcp_rexmit_rto(pcb); + } + } + break; + case SYN_RCVD: + if (flags & TCP_ACK) { + /* expected ACK number? */ + if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { + pcb->state = ESTABLISHED; + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG +#if LWIP_CALLBACK_API + LWIP_ASSERT("pcb->listener->accept != NULL", + (pcb->listener == NULL) || (pcb->listener->accept != NULL)); +#endif + if (pcb->listener == NULL) { + /* listen pcb might be closed by now */ + err = ERR_VAL; + } else +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + { + tcp_backlog_accepted(pcb); + /* Call the accept function. */ + TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, ERR_OK, err); + } + if (err != ERR_OK) { + /* If the accept function returns with an error, we abort + * the connection. */ + /* Already aborted? */ + if (err != ERR_ABRT) { + tcp_abort(pcb); + } + return ERR_ABRT; + } + /* If there was any data contained within this ACK, + * we'd better pass it on to the application as well. */ + tcp_receive(pcb); + + /* Prevent ACK for SYN to generate a sent event */ + if (recv_acked != 0) { + recv_acked--; + } + + pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F + " ssthresh %"TCPWNDSIZE_F"\n", + pcb->cwnd, pcb->ssthresh)); + + if (recv_flags & TF_GOT_FIN) { + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + } else { + /* incorrect ACK number, send RST */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + ip_current_src_addr(), tcphdr->dest, tcphdr->src); + } + } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { + /* Looks like another copy of the SYN - retransmit our SYN-ACK */ + tcp_rexmit(pcb); + } + break; + case CLOSE_WAIT: + /* FALLTHROUGH */ + case ESTABLISHED: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { /* passive close */ + tcp_ack_now(pcb); + pcb->state = CLOSE_WAIT; + } + break; + case FIN_WAIT_1: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && + pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, + ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } else { + tcp_ack_now(pcb); + pcb->state = CLOSING; + } + } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && + pcb->unsent == NULL) { + pcb->state = FIN_WAIT_2; + } + break; + case FIN_WAIT_2: + tcp_receive(pcb); + if (recv_flags & TF_GOT_FIN) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_ack_now(pcb); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case CLOSING: + tcp_receive(pcb); + if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + tcp_pcb_purge(pcb); + TCP_RMV_ACTIVE(pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + } + break; + case LAST_ACK: + tcp_receive(pcb); + if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); + /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ + recv_flags |= TF_CLOSED; + } + break; + default: + break; + } + return ERR_OK; +} + +#if TCP_QUEUE_OOSEQ +/** + * Insert segment into the list (segments covered with new one will be deleted) + * + * Called from tcp_receive() + */ +static void +tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) +{ + struct tcp_seg *old_seg; + + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + /* received segment overlaps all following segments */ + tcp_segs_free(next); + next = NULL; + } else { + /* delete some following segments + oos queue may have segments with FIN flag */ + while (next && + TCP_SEQ_GEQ((seqno + cseg->len), + (next->tcphdr->seqno + next->len))) { + /* cseg with FIN already processed */ + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); + } + old_seg = next; + next = next->next; + tcp_seg_free(old_seg); + } + if (next && + TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { + /* We need to trim the incoming segment. */ + cseg->len = (u16_t)(next->tcphdr->seqno - seqno); + pbuf_realloc(cseg->p, cseg->len); + } + } + cseg->next = next; +} +#endif /* TCP_QUEUE_OOSEQ */ + +/** + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, it places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + * + * Called from tcp_process(). + */ +static void +tcp_receive(struct tcp_pcb *pcb) +{ + struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ + struct tcp_seg *prev, *cseg; +#endif /* TCP_QUEUE_OOSEQ */ + s32_t off; + s16_t m; + u32_t right_wnd_edge; + u16_t new_tot_len; + int found_dupack = 0; +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS + u32_t ooseq_blen; + u16_t ooseq_qlen; +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ + + LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); + + if (flags & TCP_ACK) { + right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; + + /* Update window. */ + if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || + (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || + (pcb->snd_wl2 == ackno && (u32_t)SND_WND_SCALE(pcb, tcphdr->wnd) > pcb->snd_wnd)) { + pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); + /* keep track of the biggest window announced by the remote host to calculate + the maximum segment size */ + if (pcb->snd_wnd_max < pcb->snd_wnd) { + pcb->snd_wnd_max = pcb->snd_wnd; + } + pcb->snd_wl1 = seqno; + pcb->snd_wl2 = ackno; + if (pcb->snd_wnd == 0) { + if (pcb->persist_backoff == 0) { + /* start persist timer */ + pcb->persist_cnt = 0; + pcb->persist_backoff = 1; + } + } else if (pcb->persist_backoff > 0) { + /* stop persist timer */ + pcb->persist_backoff = 0; + } + LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"TCPWNDSIZE_F"\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG + } else { + if (pcb->snd_wnd != (tcpwnd_size_t)SND_WND_SCALE(pcb, tcphdr->wnd)) { + LWIP_DEBUGF(TCP_WND_DEBUG, + ("tcp_receive: no window update lastack %"U32_F" ackno %" + U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", + pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); + } +#endif /* TCP_WND_DEBUG */ + } + + /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a + * duplicate ack if: + * 1) It doesn't ACK new data + * 2) length of received packet is zero (i.e. no payload) + * 3) the advertised window hasn't changed + * 4) There is outstanding unacknowledged data (retransmission timer running) + * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) + * + * If it passes all five, should process as a dupack: + * a) dupacks < 3: do nothing + * b) dupacks == 3: fast retransmit + * c) dupacks > 3: increase cwnd + * + * If it only passes 1-3, should reset dupack counter (and add to + * stats, which we don't do in lwIP) + * + * If it only passes 1, should reset dupack counter + * + */ + + /* Clause 1 */ + if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { + /* Clause 2 */ + if (tcplen == 0) { + /* Clause 3 */ + if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { + /* Clause 4 */ + if (pcb->rtime >= 0) { + /* Clause 5 */ + if (pcb->lastack == ackno) { + found_dupack = 1; + if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { + ++pcb->dupacks; + } + if (pcb->dupacks > 3) { + /* Inflate the congestion window, but not if it means that + the value overflows. */ + if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + } else if (pcb->dupacks == 3) { + /* Do fast retransmit */ + tcp_rexmit_fast(pcb); + } + } + } + } + } + /* If Clause (1) or more is true, but not a duplicate ack, reset + * count of consecutive duplicate acks */ + if (!found_dupack) { + pcb->dupacks = 0; + } + } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { + /* We come here when the ACK acknowledges new data. */ + + /* Reset the "IN Fast Retransmit" flag, since we are no longer + in fast retransmit. Also reset the congestion window to the + slow start threshold. */ + if (pcb->flags & TF_INFR) { + pcb->flags &= ~TF_INFR; + pcb->cwnd = pcb->ssthresh; + } + + /* Reset the number of retransmissions. */ + pcb->nrtx = 0; + + /* Reset the retransmission time-out. */ + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + /* Reset the fast retransmit variables. */ + pcb->dupacks = 0; + pcb->lastack = ackno; + + /* Update the congestion control variables (cwnd and + ssthresh). */ + if (pcb->state >= ESTABLISHED) { + if (pcb->cwnd < pcb->ssthresh) { + if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); + } else { + tcpwnd_size_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); + if (new_cwnd > pcb->cwnd) { + pcb->cwnd = new_cwnd; + } + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); + } + } + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", + ackno, + pcb->unacked != NULL? + lwip_ntohl(pcb->unacked->tcphdr->seqno): 0, + pcb->unacked != NULL? + lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); + + /* Remove segment from the unacknowledged list if the incoming + ACK acknowledges them. */ + while (pcb->unacked != NULL && + TCP_SEQ_LEQ(lwip_ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked), ackno)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", + lwip_ntohl(pcb->unacked->tcphdr->seqno), + lwip_ntohl(pcb->unacked->tcphdr->seqno) + + TCP_TCPLEN(pcb->unacked))); + + next = pcb->unacked; + pcb->unacked = pcb->unacked->next; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); + LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); + + pcb->snd_queuelen -= pbuf_clen(next->p); + recv_acked += next->len; + tcp_seg_free(next); + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unacked)\n", (tcpwnd_size_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + } + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if (pcb->unacked == NULL) { + pcb->rtime = -1; + } else { + pcb->rtime = 0; + } + + pcb->polltmr = 0; + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (ip_current_is_v6()) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + } else { + /* Out of sequence ACK, didn't really ack anything */ + tcp_send_empty_ack(pcb); + } + + /* We go through the ->unsent list to see if any of the segments + on the list are acknowledged by the ACK. This may seem + strange since an "unsent" segment shouldn't be acked. The + rationale is that lwIP puts all outstanding segments on the + ->unsent list after a retransmission, so these segments may + in fact have been sent once. */ + while (pcb->unsent != NULL && + TCP_SEQ_BETWEEN(ackno, lwip_ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", + lwip_ntohl(pcb->unsent->tcphdr->seqno), lwip_ntohl(pcb->unsent->tcphdr->seqno) + + TCP_TCPLEN(pcb->unsent))); + + next = pcb->unsent; + pcb->unsent = pcb->unsent->next; +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); + LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); + /* Prevent ACK for FIN to generate a sent event */ + pcb->snd_queuelen -= pbuf_clen(next->p); + recv_acked += next->len; + tcp_seg_free(next); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unsent)\n", (tcpwnd_size_t)pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_receive: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + } + pcb->snd_buf += recv_acked; + /* End of ACK for new data processing. */ + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", + pcb->rttest, pcb->rtseq, ackno)); + + /* RTT estimation calculations. This is done by checking if the + incoming segment acknowledges the segment we use to take a + round-trip time measurement. */ + if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { + /* diff between this shouldn't exceed 32K since this are tcp timer ticks + and a round-trip shouldn't be that long... */ + m = (s16_t)(tcp_ticks - pcb->rttest); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", + m, (u16_t)(m * TCP_SLOW_INTERVAL))); + + /* This is taken directly from VJs original code in his paper */ + m = m - (pcb->sa >> 3); + pcb->sa += m; + if (m < 0) { + m = -m; + } + m = m - (pcb->sv >> 2); + pcb->sv += m; + pcb->rto = (pcb->sa >> 3) + pcb->sv; + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", + pcb->rto, (u16_t)(pcb->rto * TCP_SLOW_INTERVAL))); + + pcb->rttest = 0; + } + } + + /* If the incoming segment contains data, we must process it + further unless the pcb already received a FIN. + (RFC 793, chapter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, + LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ + if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { + /* This code basically does three things: + + +) If the incoming segment contains data that is the next + in-sequence data, this data is passed to the application. This + might involve trimming the first edge of the data. The rcv_nxt + variable and the advertised window are adjusted. + + +) If the incoming segment has data that is above the next + sequence number expected (->rcv_nxt), the segment is placed on + the ->ooseq queue. This is done by finding the appropriate + place in the ->ooseq queue (which is ordered by sequence + number) and trim the segment in both ends if needed. An + immediate ACK is sent to indicate that we received an + out-of-sequence segment. + + +) Finally, we check if the first segment on the ->ooseq queue + now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If + rcv_nxt > ooseq->seqno, we must trim the first edge of the + segment on ->ooseq before we adjust rcv_nxt. The data in the + segments that are now on sequence are chained onto the + incoming segment so that we only need to call the application + once. + */ + + /* First, we check if we must trim the first edge. We have to do + this if the sequence number of the incoming segment is less + than rcv_nxt, and the sequence number plus the length of the + segment is larger than rcv_nxt. */ + /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { + if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ + if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)) { + /* Trimming the first edge is done by pushing the payload + pointer in the pbuf downwards. This is somewhat tricky since + we do not want to discard the full contents of the pbuf up to + the new starting point of the data since we have to keep the + TCP header which is present in the first pbuf in the chain. + + What is done is really quite a nasty hack: the first pbuf in + the pbuf chain is pointed to by inseg.p. Since we need to be + able to deallocate the whole pbuf, we cannot change this + inseg.p pointer to point to any of the later pbufs in the + chain. Instead, we point the ->payload pointer in the first + pbuf to data in one of the later pbufs. We also set the + inseg.data pointer to point to the right place. This way, the + ->p pointer will still point to the first pbuf, but the + ->p->payload pointer will point to data in another pbuf. + + After we are done with adjusting the pbuf pointers we must + adjust the ->data pointer in the seg and the segment + length.*/ + + struct pbuf *p = inseg.p; + off = pcb->rcv_nxt - seqno; + LWIP_ASSERT("inseg.p != NULL", inseg.p); + LWIP_ASSERT("insane offset!", (off < 0x7fff)); + if (inseg.p->len < off) { + LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); + new_tot_len = (u16_t)(inseg.p->tot_len - off); + while (p->len < off) { + off -= p->len; + /* KJM following line changed (with addition of new_tot_len var) + to fix bug #9076 + inseg.p->tot_len -= p->len; */ + p->tot_len = new_tot_len; + p->len = 0; + p = p->next; + } + if (pbuf_header(p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } else { + if (pbuf_header(inseg.p, (s16_t)-off)) { + /* Do we need to cope with this failing? Assert for now */ + LWIP_ASSERT("pbuf_header failed", 0); + } + } + inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); + inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; + } + else { + if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { + /* the whole segment is < rcv_nxt */ + /* must be a duplicate of a packet that has already been correctly handled */ + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); + tcp_ack_now(pcb); + } + } + + /* The sequence number must be within the window (above rcv_nxt + and below rcv_nxt + rcv_wnd) in order to be further + processed. */ + if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, + pcb->rcv_nxt + pcb->rcv_wnd - 1)) { + if (pcb->rcv_nxt == seqno) { + /* The incoming segment is the next in sequence. We check if + we have to trim the end of the segment and update rcv_nxt + and pass the data to the application. */ + tcplen = TCP_TCPLEN(&inseg); + + if (tcplen > pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) & ~(unsigned int)TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + TCPWND_CHECK16(pcb->rcv_wnd); + inseg.len = (u16_t)pcb->rcv_wnd; + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } +#if TCP_QUEUE_OOSEQ + /* Received in-sequence data, adjust ooseq data if: + - FIN has been received or + - inseq overlaps with ooseq */ + if (pcb->ooseq != NULL) { + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: received in-order FIN, binning ooseq queue\n")); + /* Received in-order FIN means anything that was received + * out of order must now have been received in-order, so + * bin the ooseq queue */ + while (pcb->ooseq != NULL) { + struct tcp_seg *old_ooseq = pcb->ooseq; + pcb->ooseq = pcb->ooseq->next; + tcp_seg_free(old_ooseq); + } + } else { + next = pcb->ooseq; + /* Remove all segments on ooseq that are covered by inseg already. + * FIN is copied from ooseq to inseg if present. */ + while (next && + TCP_SEQ_GEQ(seqno + tcplen, + next->tcphdr->seqno + next->len)) { + /* inseg cannot have FIN here (already processed above) */ + if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && + (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { + TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); + tcplen = TCP_TCPLEN(&inseg); + } + prev = next; + next = next->next; + tcp_seg_free(prev); + } + /* Now trim right side of inseg if it overlaps with the first + * segment on ooseq */ + if (next && + TCP_SEQ_GT(seqno + tcplen, + next->tcphdr->seqno)) { + /* inseg cannot have FIN here (already processed above) */ + inseg.len = (u16_t)(next->tcphdr->seqno - seqno); + if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { + inseg.len -= 1; + } + pbuf_realloc(inseg.p, inseg.len); + tcplen = TCP_TCPLEN(&inseg); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", + (seqno + tcplen) == next->tcphdr->seqno); + } + pcb->ooseq = next; + } + } +#endif /* TCP_QUEUE_OOSEQ */ + + pcb->rcv_nxt = seqno + tcplen; + + /* Update the receiver's (our) window. */ + LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); + pcb->rcv_wnd -= tcplen; + + tcp_update_rcv_ann_wnd(pcb); + + /* If there is data in the segment, we make preparations to + pass this up to the application. The ->recv_data variable + is used for holding the pbuf that goes to the + application. The code for reassembling out-of-sequence data + chains its data on this pbuf as well. + + If the segment was a FIN, we set the TF_GOT_FIN flag that will + be used to indicate to the application that the remote side has + closed its end of the connection. */ + if (inseg.p->tot_len > 0) { + recv_data = inseg.p; + /* Since this pbuf now is the responsibility of the + application, we delete our reference to it so that we won't + (mistakingly) deallocate it. */ + inseg.p = NULL; + } + if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); + recv_flags |= TF_GOT_FIN; + } + +#if TCP_QUEUE_OOSEQ + /* We now check if we have segments on the ->ooseq queue that + are now in sequence. */ + while (pcb->ooseq != NULL && + pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + + cseg = pcb->ooseq; + seqno = pcb->ooseq->tcphdr->seqno; + + pcb->rcv_nxt += TCP_TCPLEN(cseg); + LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", + pcb->rcv_wnd >= TCP_TCPLEN(cseg)); + pcb->rcv_wnd -= TCP_TCPLEN(cseg); + + tcp_update_rcv_ann_wnd(pcb); + + if (cseg->p->tot_len > 0) { + /* Chain this pbuf onto the pbuf that we will pass to + the application. */ + /* With window scaling, this can overflow recv_data->tot_len, but + that's not a problem since we explicitly fix that before passing + recv_data to the application. */ + if (recv_data) { + pbuf_cat(recv_data, cseg->p); + } else { + recv_data = cseg->p; + } + cseg->p = NULL; + } + if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); + recv_flags |= TF_GOT_FIN; + if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ + pcb->state = CLOSE_WAIT; + } + } + + pcb->ooseq = cseg->next; + tcp_seg_free(cseg); + } +#endif /* TCP_QUEUE_OOSEQ */ + + + /* Acknowledge the segment(s). */ + tcp_ack(pcb); + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (ip_current_is_v6()) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + + } else { + /* We get here if the incoming segment is out-of-sequence. */ + tcp_send_empty_ack(pcb); +#if TCP_QUEUE_OOSEQ + /* We queue the segment on the ->ooseq queue. */ + if (pcb->ooseq == NULL) { + pcb->ooseq = tcp_seg_copy(&inseg); + } else { + /* If the queue is not empty, we walk through the queue and + try to find a place where the sequence number of the + incoming segment is between the sequence numbers of the + previous and the next segment on the ->ooseq queue. That is + the place where we put the incoming segment. If needed, we + trim the second edges of the previous and the incoming + segment so that it will fit into the sequence. + + If the incoming segment has the same sequence number as a + segment on the ->ooseq queue, we discard the segment that + contains less data. */ + + prev = NULL; + for (next = pcb->ooseq; next != NULL; next = next->next) { + if (seqno == next->tcphdr->seqno) { + /* The sequence number of the incoming segment is the + same as the sequence number of the segment on + ->ooseq. We check the lengths to see which one to + discard. */ + if (inseg.len > next->len) { + /* The incoming segment is larger than the old + segment. We replace some segments with the new + one. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + if (prev != NULL) { + prev->next = cseg; + } else { + pcb->ooseq = cseg; + } + tcp_oos_insert_segment(cseg, next); + } + break; + } else { + /* Either the lengths are the same or the incoming + segment was smaller than the old one; in either + case, we ditch the incoming segment. */ + break; + } + } else { + if (prev == NULL) { + if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { + /* The sequence number of the incoming segment is lower + than the sequence number of the first segment on the + queue. We put the incoming segment first on the + queue. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + pcb->ooseq = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } else { + /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && + TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ + if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { + /* The sequence number of the incoming segment is in + between the sequence numbers of the previous and + the next segment on ->ooseq. We trim trim the previous + segment, delete next segments that included in received segment + and trim received, if needed. */ + cseg = tcp_seg_copy(&inseg); + if (cseg != NULL) { + if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { + /* We need to trim the prev segment. */ + prev->len = (u16_t)(seqno - prev->tcphdr->seqno); + pbuf_realloc(prev->p, prev->len); + } + prev->next = cseg; + tcp_oos_insert_segment(cseg, next); + } + break; + } + } + /* If the "next" segment is the last segment on the + ooseq queue, we add the incoming segment to the end + of the list. */ + if (next->next == NULL && + TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { + if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { + /* segment "next" already contains all data */ + break; + } + next->next = tcp_seg_copy(&inseg); + if (next->next != NULL) { + if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { + /* We need to trim the last segment. */ + next->len = (u16_t)(seqno - next->tcphdr->seqno); + pbuf_realloc(next->p, next->len); + } + /* check if the remote side overruns our receive window */ + if (TCP_SEQ_GT((u32_t)tcplen + seqno, pcb->rcv_nxt + (u32_t)pcb->rcv_wnd)) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) & ~TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + next->next->len = (u16_t)(pcb->rcv_nxt + pcb->rcv_wnd - seqno); + pbuf_realloc(next->next->p, next->next->len); + tcplen = TCP_TCPLEN(next->next); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } + } + break; + } + } + prev = next; + } + } +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS + /* Check that the data on ooseq doesn't exceed one of the limits + and throw away everything above that limit. */ + ooseq_blen = 0; + ooseq_qlen = 0; + prev = NULL; + for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { + struct pbuf *p = next->p; + ooseq_blen += p->tot_len; + ooseq_qlen += pbuf_clen(p); + if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || + (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { + /* too much ooseq data, dump this and everything after it */ + tcp_segs_free(next); + if (prev == NULL) { + /* first ooseq segment is too much, dump the whole queue */ + pcb->ooseq = NULL; + } else { + /* just dump 'next' and everything after it */ + prev->next = NULL; + } + break; + } + } +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ +#endif /* TCP_QUEUE_OOSEQ */ + } + } else { + /* The incoming segment is not within the window. */ + tcp_send_empty_ack(pcb); + } + } else { + /* Segments with length 0 is taken care of here. Segments that + fall out of the window are ACKed. */ + if (!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)) { + tcp_ack_now(pcb); + } + } +} + +static u8_t +tcp_getoptbyte(void) +{ + if ((tcphdr_opt2 == NULL) || (tcp_optidx < tcphdr_opt1len)) { + u8_t* opts = (u8_t *)tcphdr + TCP_HLEN; + return opts[tcp_optidx++]; + } else { + u8_t idx = (u8_t)(tcp_optidx++ - tcphdr_opt1len); + return tcphdr_opt2[idx]; + } +} + +/** + * Parses the options contained in the incoming segment. + * + * Called from tcp_listen_input() and tcp_process(). + * Currently, only the MSS option is supported! + * + * @param pcb the tcp_pcb for which a segment arrived + */ +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ + u8_t data; + u16_t mss; +#if LWIP_TCP_TIMESTAMPS + u32_t tsval; +#endif + + /* Parse the TCP MSS option, if present. */ + if (tcphdr_optlen != 0) { + for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { + u8_t opt = tcp_getoptbyte(); + switch (opt) { + case LWIP_TCP_OPT_EOL: + /* End of options. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); + return; + case LWIP_TCP_OPT_NOP: + /* NOP option. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); + break; + case LWIP_TCP_OPT_MSS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); + if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* An MSS option with the right option length. */ + mss = (tcp_getoptbyte() << 8); + mss |= tcp_getoptbyte(); + /* Limit the mss to the configured TCP_MSS and prevent division by zero */ + pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; + break; +#if LWIP_WND_SCALE + case LWIP_TCP_OPT_WS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); + if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* If syn was received with wnd scale option, + activate wnd scale opt, but only if this is not a retransmission */ + if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) { + /* An WND_SCALE option with the right option length. */ + data = tcp_getoptbyte(); + pcb->snd_scale = data; + if (pcb->snd_scale > 14U) { + pcb->snd_scale = 14U; + } + pcb->rcv_scale = TCP_RCV_SCALE; + pcb->flags |= TF_WND_SCALE; + /* window scaling is enabled, we can use the full receive window */ + LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); + LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); + pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; + } + break; +#endif +#if LWIP_TCP_TIMESTAMPS + case LWIP_TCP_OPT_TS: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); + if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > tcphdr_optlen) { + /* Bad length */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + return; + } + /* TCP timestamp option with valid length */ + tsval = tcp_getoptbyte(); + tsval |= (tcp_getoptbyte() << 8); + tsval |= (tcp_getoptbyte() << 16); + tsval |= (tcp_getoptbyte() << 24); + if (flags & TCP_SYN) { + pcb->ts_recent = lwip_ntohl(tsval); + /* Enable sending timestamps in every segment now that we know + the remote host supports it. */ + pcb->flags |= TF_TIMESTAMP; + } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { + pcb->ts_recent = lwip_ntohl(tsval); + } + /* Advance to next option (6 bytes already read) */ + tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; + break; +#endif + default: + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); + data = tcp_getoptbyte(); + if (data < 2) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); + /* If the length field is zero, the options are malformed + and we don't process them further. */ + return; + } + /* All other options have a length field, so that we easily + can skip past them. */ + tcp_optidx += data - 2; + } + } + } +} + +void +tcp_trigger_input_pcb_close(void) +{ + recv_flags |= TF_CLOSED; +} + +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/tcp_out.c b/Sming/third-party/lwip2/lwip2-src/src/core/tcp_out.c new file mode 100644 index 0000000000..2435408aeb --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/tcp_out.c @@ -0,0 +1,1671 @@ +/** + * @file + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/priv/tcp_priv.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#if LWIP_TCP_TIMESTAMPS +#include "lwip/sys.h" +#endif + +#include + +/* Define some copy-macros for checksum-on-copy so that the code looks + nicer by preventing too many ifdef's. */ +#if TCP_CHECKSUM_ON_COPY +#define TCP_DATA_COPY(dst, src, len, seg) do { \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ + len, &seg->chksum, &seg->chksum_swapped); \ + seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); +#else /* TCP_CHECKSUM_ON_COPY*/ +#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) +#endif /* TCP_CHECKSUM_ON_COPY*/ + +/** Define this to 1 for an extra check that the output checksum is valid + * (usefule when the checksum is generated by the application, not the stack) */ +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 +#endif +/* Allow to override the failure of sanity check from warning to e.g. hard failure */ +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(msg) LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, msg) +#endif +#endif + +#if TCP_OVERSIZE +/** The size of segment pbufs created when TCP_OVERSIZE is enabled */ +#ifndef TCP_OVERSIZE_CALC_LENGTH +#define TCP_OVERSIZE_CALC_LENGTH(length) ((length) + TCP_OVERSIZE) +#endif +#endif + +/* Forward declarations.*/ +static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif); + +/** Allocate a pbuf and create a tcphdr at p->payload, used for output + * functions other than the default tcp_output -> tcp_output_segment + * (e.g. tcp_send_empty_ack, etc.) + * + * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) + * @param optlen length of header-options + * @param datalen length of tcp data to reserve in pbuf + * @param seqno_be seqno in network byte order (big-endian) + * @return pbuf with p->payload being the tcp_hdr + */ +static struct pbuf * +tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, + u32_t seqno_be /* already in network byte order */) +{ + struct tcp_hdr *tcphdr; + struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= TCP_HLEN + optlen)); + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = lwip_htons(pcb->local_port); + tcphdr->dest = lwip_htons(pcb->remote_port); + tcphdr->seqno = seqno_be; + tcphdr->ackno = lwip_htonl(pcb->rcv_nxt); + TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); + tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + + /* If we're sending a packet, update the announced right window edge */ + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + } + return p; +} + +/** + * Called by tcp_close() to send a segment including FIN flag but not data. + * + * @param pcb the tcp_pcb over which to send a segment + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_fin(struct tcp_pcb *pcb) +{ + /* first, try to add the fin to the last unsent segment */ + if (pcb->unsent != NULL) { + struct tcp_seg *last_unsent; + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { + /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ + TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); + pcb->flags |= TF_FIN; + return ERR_OK; + } + } + /* no data, no length, flags, copy=1, no optdata */ + return tcp_enqueue_flags(pcb, TCP_FIN); +} + +/** + * Create a TCP segment with prefilled header. + * + * Called by tcp_write and tcp_enqueue_flags. + * + * @param pcb Protocol control block for the TCP connection. + * @param p pbuf that is used to hold the TCP header. + * @param flags TCP flags for header. + * @param seqno TCP sequence number of this packet + * @param optflags options to include in TCP header + * @return a new tcp_seg pointing to p, or NULL. + * The TCP header is filled in except ackno and wnd. + * p is freed on failure. + */ +static struct tcp_seg * +tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) +{ + struct tcp_seg *seg; + u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); + + if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n")); + pbuf_free(p); + return NULL; + } + seg->flags = optflags; + seg->next = NULL; + seg->p = p; + LWIP_ASSERT("p->tot_len >= optlen", p->tot_len >= optlen); + seg->len = p->tot_len - optlen; +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = 0; + seg->chksum_swapped = 0; + /* check optflags */ + LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", + (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* build TCP header */ + if (pbuf_header(p, TCP_HLEN)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no room for TCP header in pbuf.\n")); + TCP_STATS_INC(tcp.err); + tcp_seg_free(seg); + return NULL; + } + seg->tcphdr = (struct tcp_hdr *)seg->p->payload; + seg->tcphdr->src = lwip_htons(pcb->local_port); + seg->tcphdr->dest = lwip_htons(pcb->remote_port); + seg->tcphdr->seqno = lwip_htonl(seqno); + /* ackno is set in tcp_output */ + TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); + /* wnd and chksum are set in tcp_output */ + seg->tcphdr->urgp = 0; + return seg; +} + +/** + * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. + * + * This function is like pbuf_alloc(layer, length, PBUF_RAM) except + * there may be extra bytes available at the end. + * + * @param layer flag to define header size. + * @param length size of the pbuf's payload. + * @param max_length maximum usable size of payload+oversize. + * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. + * @param pcb The TCP connection that will enqueue the pbuf. + * @param apiflags API flags given to tcp_write. + * @param first_seg true when this pbuf will be used in the first enqueued segment. + */ +#if TCP_OVERSIZE +static struct pbuf * +tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, + u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, + u8_t first_seg) +{ + struct pbuf *p; + u16_t alloc = length; + +#if LWIP_NETIF_TX_SINGLE_PBUF + LWIP_UNUSED_ARG(max_length); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(apiflags); + LWIP_UNUSED_ARG(first_seg); + alloc = max_length; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (length < max_length) { + /* Should we allocate an oversized pbuf, or just the minimum + * length required? If tcp_write is going to be called again + * before this segment is transmitted, we want the oversized + * buffer. If the segment will be transmitted immediately, we can + * save memory by allocating only length. We use a simple + * heuristic based on the following information: + * + * Did the user set TCP_WRITE_FLAG_MORE? + * + * Will the Nagle algorithm defer transmission of this segment? + */ + if ((apiflags & TCP_WRITE_FLAG_MORE) || + (!(pcb->flags & TF_NODELAY) && + (!first_seg || + pcb->unsent != NULL || + pcb->unacked != NULL))) { + alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(TCP_OVERSIZE_CALC_LENGTH(length))); + } + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(layer, alloc, PBUF_RAM); + if (p == NULL) { + return NULL; + } + LWIP_ASSERT("need unchained pbuf", p->next == NULL); + *oversize = p->len - length; + /* trim p->len to the currently used size */ + p->len = p->tot_len = length; + return p; +} +#else /* TCP_OVERSIZE */ +#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) +#endif /* TCP_OVERSIZE */ + +#if TCP_CHECKSUM_ON_COPY +/** Add a checksum of newly added data to the segment */ +static void +tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, + u8_t *seg_chksum_swapped) +{ + u32_t helper; + /* add chksum to old chksum and fold to u16_t */ + helper = chksum + *seg_chksum; + chksum = FOLD_U32T(helper); + if ((len & 1) != 0) { + *seg_chksum_swapped = 1 - *seg_chksum_swapped; + chksum = SWAP_BYTES_IN_WORD(chksum); + } + *seg_chksum = chksum; +} +#endif /* TCP_CHECKSUM_ON_COPY */ + +/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). + * + * @param pcb the tcp pcb to check for + * @param len length of data to send (checked agains snd_buf) + * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise + */ +static err_t +tcp_write_checks(struct tcp_pcb *pcb, u16_t len) +{ + /* connection is in invalid state for data transmission? */ + if ((pcb->state != ESTABLISHED) && + (pcb->state != CLOSE_WAIT) && + (pcb->state != SYN_SENT) && + (pcb->state != SYN_RCVD)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); + return ERR_CONN; + } else if (len == 0) { + return ERR_OK; + } + + /* fail on too much data */ + if (len > pcb->snd_buf) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"TCPWNDSIZE_F")\n", + len, pcb->snd_buf)); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); + + /* If total number of pbufs on the unsent/unacked queues exceeds the + * configured maximum, return an error */ + /* check for configured max queuelen and possible overflow */ + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", + pcb->unacked != NULL || pcb->unsent != NULL); + } else { + LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", + pcb->unacked == NULL && pcb->unsent == NULL); + } + return ERR_OK; +} + +/** + * @ingroup tcp_raw + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + * + * @param pcb Protocol control block for the TCP connection to enqueue data for. + * @param arg Pointer to the data to be enqueued for sending. + * @param len Data length in bytes + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will not be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) +{ + struct pbuf *concat_p = NULL; + struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; + u16_t pos = 0; /* position in 'arg' data */ + u16_t queuelen; + u8_t optlen = 0; + u8_t optflags = 0; +#if TCP_OVERSIZE + u16_t oversize = 0; + u16_t oversize_used = 0; +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_add = 0; +#endif /* TCP_OVERSIZE_DBGCHECK*/ +#endif /* TCP_OVERSIZE */ + u16_t extendlen = 0; +#if TCP_CHECKSUM_ON_COPY + u16_t concat_chksum = 0; + u8_t concat_chksum_swapped = 0; + u16_t concat_chksummed = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + err_t err; + /* don't allocate segments bigger than half the maximum window we ever received */ + u16_t mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max/2)); + mss_local = mss_local ? mss_local : pcb->mss; + +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Always copy to try to create single pbufs for TX */ + apiflags |= TCP_WRITE_FLAG_COPY; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)apiflags)); + LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", + arg != NULL, return ERR_ARG;); + + err = tcp_write_checks(pcb, len); + if (err != ERR_OK) { + return err; + } + queuelen = pcb->snd_queuelen; + +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + /* Make sure the timestamp option is only included in data segments if we + agreed about it with the remote host. */ + optflags = TF_SEG_OPTS_TS; + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + /* ensure that segments can hold at least one data byte... */ + mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); + } +#endif /* LWIP_TCP_TIMESTAMPS */ + + + /* + * TCP segmentation is done in three phases with increasing complexity: + * + * 1. Copy data directly into an oversized pbuf. + * 2. Chain a new pbuf to the end of pcb->unsent. + * 3. Create new segments. + * + * We may run out of memory at any point. In that case we must + * return ERR_MEM and not change anything in pcb. Therefore, all + * changes are recorded in local variables and committed at the end + * of the function. Some pcb fields are maintained in local copies: + * + * queuelen = pcb->snd_queuelen + * oversize = pcb->unsent_oversize + * + * These variables are set consistently by the phases: + * + * seg points to the last segment tampered with. + * + * pos records progress as data is segmented. + */ + + /* Find the tail of the unsent queue. */ + if (pcb->unsent != NULL) { + u16_t space; + u16_t unsent_optlen; + + /* @todo: this could be sped up by keeping last_unsent in the pcb */ + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + /* Usable space at the end of the last unsent segment */ + unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); + LWIP_ASSERT("mss_local is too small", mss_local >= last_unsent->len + unsent_optlen); + space = mss_local - (last_unsent->len + unsent_optlen); + + /* + * Phase 1: Copy data directly into an oversized pbuf. + * + * The number of bytes copied is recorded in the oversize_used + * variable. The actual copying is done at the bottom of the + * function. + */ +#if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->oversize_left */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ + oversize = pcb->unsent_oversize; + if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize <= space); + seg = last_unsent; + oversize_used = LWIP_MIN(space, LWIP_MIN(oversize, len)); + pos += oversize_used; + oversize -= oversize_used; + space -= oversize_used; + } + /* now we are either finished or oversize is zero */ + LWIP_ASSERT("inconsistent oversize vs. len", (oversize == 0) || (pos == len)); +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: Chain a new pbuf to the end of pcb->unsent. + * + * As an exception when NOT copying the data, if the given data buffer + * directly follows the last unsent data buffer in memory, extend the last + * ROM pbuf reference to the buffer, thus saving a ROM pbuf allocation. + * + * We don't extend segments containing SYN/FIN flags or options + * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at + * the end. + */ + if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { + u16_t seglen = LWIP_MIN(space, len - pos); + seg = last_unsent; + + /* Create a pbuf with a copy or reference to seglen bytes. We + * can use PBUF_RAW here since the data appears in the middle of + * a segment. A header will never be prepended. */ + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* Data is copied */ + if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", + seglen)); + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + oversize_add = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ + TCP_DATA_COPY2(concat_p->payload, (const u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); +#if TCP_CHECKSUM_ON_COPY + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + queuelen += pbuf_clen(concat_p); + } else { + /* Data is not copied */ + /* If the last unsent pbuf is of type PBUF_ROM, try to extend it. */ + struct pbuf *p; + for (p = last_unsent->p; p->next != NULL; p = p->next); + if (p->type == PBUF_ROM && (const u8_t *)p->payload + p->len == (const u8_t *)arg) { + LWIP_ASSERT("tcp_write: ROM pbufs cannot be oversized", pos == 0); + extendlen = seglen; + } else { + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } + /* reference the non-volatile payload data */ + ((struct pbuf_rom*)concat_p)->payload = (const u8_t*)arg + pos; + queuelen += pbuf_clen(concat_p); + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + tcp_seg_add_chksum(~inet_chksum((const u8_t*)arg + pos, seglen), seglen, + &concat_chksum, &concat_chksum_swapped); + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + } + + pos += seglen; + } + } else { +#if TCP_OVERSIZE + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); +#endif /* TCP_OVERSIZE */ + } + + /* + * Phase 3: Create new segments. + * + * The new segments are chained together in the local 'queue' + * variable, ready to be appended to pcb->unsent. + */ + while (pos < len) { + struct pbuf *p; + u16_t left = len - pos; + u16_t max_len = mss_local - optlen; + u16_t seglen = LWIP_MIN(left, max_len); +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* If copy is set, memory should be allocated and data copied + * into pbuf */ + if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + goto memerr; + } + LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", + (p->len >= seglen)); + TCP_DATA_COPY2((char *)p->payload + optlen, (const u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); + } else { + /* Copy is not set: First allocate a pbuf for holding the data. + * Since the referenced data is available at least until it is + * sent out on the link (as it has to be ACKed by the remote + * party) we can safely use PBUF_ROM instead of PBUF_REF here. + */ + struct pbuf *p2; +#if TCP_OVERSIZE + LWIP_ASSERT("oversize == 0", oversize == 0); +#endif /* TCP_OVERSIZE */ + if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + chksum = ~inet_chksum((const u8_t*)arg + pos, seglen); + if (seglen & 1) { + chksum_swapped = 1; + chksum = SWAP_BYTES_IN_WORD(chksum); + } +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + ((struct pbuf_rom*)p2)->payload = (const u8_t*)arg + pos; + + /* Second, allocate a pbuf for the headers. */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + /* If allocation fails, we have to deallocate the data pbuf as + * well. */ + pbuf_free(p2); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: could not allocate memory for header pbuf\n")); + goto memerr; + } + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(p/*header*/, p2/*data*/); + } + + queuelen += pbuf_clen(p); + + /* Now that there are more segments queued, we check again if the + * length of the queue exceeds the configured maximum or + * overflows. */ + if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n", + queuelen, (int)TCP_SND_QUEUELEN)); + pbuf_free(p); + goto memerr; + } + + if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = chksum; + seg->chksum_swapped = chksum_swapped; + seg->flags |= TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* first segment of to-be-queued data? */ + if (queue == NULL) { + queue = seg; + } else { + /* Attach the segment to the end of the queued segments */ + LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); + prev_seg->next = seg; + } + /* remember last segment of to-be-queued data for next iteration */ + prev_seg = seg; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", + lwip_ntohl(seg->tcphdr->seqno), + lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); + + pos += seglen; + } + + /* + * All three segmentation phases were successful. We can commit the + * transaction. + */ +#if TCP_OVERSIZE_DBGCHECK + if ((last_unsent != NULL) && (oversize_add != 0)) { + last_unsent->oversize_left += oversize_add; + } +#endif /* TCP_OVERSIZE_DBGCHECK */ + + /* + * Phase 1: If data has been added to the preallocated tail of + * last_unsent, we update the length fields of the pbuf chain. + */ +#if TCP_OVERSIZE + if (oversize_used > 0) { + struct pbuf *p; + /* Bump tot_len of whole chain, len of tail */ + for (p = last_unsent->p; p; p = p->next) { + p->tot_len += oversize_used; + if (p->next == NULL) { + TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); + p->len += oversize_used; + } + } + last_unsent->len += oversize_used; +#if TCP_OVERSIZE_DBGCHECK + LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", + last_unsent->oversize_left >= oversize_used); + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ + } + pcb->unsent_oversize = oversize; +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: concat_p can be concatenated onto last_unsent->p, unless we + * determined that the last ROM pbuf can be extended to include the new data. + */ + if (concat_p != NULL) { + LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", + (last_unsent != NULL)); + pbuf_cat(last_unsent->p, concat_p); + last_unsent->len += concat_p->tot_len; + } else if (extendlen > 0) { + struct pbuf *p; + LWIP_ASSERT("tcp_write: extension of reference requires reference", + last_unsent != NULL && last_unsent->p != NULL); + for (p = last_unsent->p; p->next != NULL; p = p->next) { + p->tot_len += extendlen; + } + p->tot_len += extendlen; + p->len += extendlen; + last_unsent->len += extendlen; + } + +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + LWIP_ASSERT("tcp_write: concat checksum needs concatenated data", + concat_p != NULL || extendlen > 0); + /*if concat checksumm swapped - swap it back */ + if (concat_chksum_swapped) { + concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); + } + tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, + &last_unsent->chksum_swapped); + last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; + } +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* + * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that + * is harmless + */ + if (last_unsent == NULL) { + pcb->unsent = queue; + } else { + last_unsent->next = queue; + } + + /* + * Finally update the pcb state. + */ + pcb->snd_lbb += len; + pcb->snd_buf -= len; + pcb->snd_queuelen = queuelen; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", + pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + /* Set the PSH flag in the last segment that we enqueued. */ + if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { + TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); + } + + return ERR_OK; +memerr: + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + + if (concat_p != NULL) { + pbuf_free(concat_p); + } + if (queue != NULL) { + tcp_segs_free(queue); + } + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || + pcb->unsent != NULL); + } + LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); + return ERR_MEM; +} + +/** + * Enqueue TCP options for transmission. + * + * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). + * + * @param pcb Protocol control block for the TCP connection. + * @param flags TCP header flags to set in the outgoing segment. + */ +err_t +tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) +{ + struct pbuf *p; + struct tcp_seg *seg; + u8_t optflags = 0; + u8_t optlen = 0; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", + (flags & (TCP_SYN | TCP_FIN)) != 0); + + /* check for configured max queuelen and possible overflow (FIN flag should always come through!) */ + if (((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) && + ((flags & TCP_FIN) == 0)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, (u16_t)TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + + if (flags & TCP_SYN) { + optflags = TF_SEG_OPTS_MSS; +#if LWIP_WND_SCALE + if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) { + /* In a (sent in state SYN_RCVD), the window scale option may only + be sent if we received a window scale option from the remote host. */ + optflags |= TF_SEG_OPTS_WND_SCALE; + } +#endif /* LWIP_WND_SCALE */ + } +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + /* Make sure the timestamp option is only included in data segments if we + agreed about it with the remote host. */ + optflags |= TF_SEG_OPTS_TS; + } +#endif /* LWIP_TCP_TIMESTAMPS */ + optlen = LWIP_TCP_OPT_LENGTH(optflags); + + /* Allocate pbuf with room for TCP header + options */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", + (p->len >= optlen)); + + /* Allocate memory for tcp_seg, and fill in fields. */ + if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % LWIP_MIN(MEM_ALIGNMENT, 4)) == 0); + LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, + ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", + lwip_ntohl(seg->tcphdr->seqno), + lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), + (u16_t)flags)); + + /* Now append seg to pcb->unsent queue */ + if (pcb->unsent == NULL) { + pcb->unsent = seg; + } else { + struct tcp_seg *useg; + for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); + useg->next = seg; + } +#if TCP_OVERSIZE + /* The new unsent tail has no space */ + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + + /* SYN and FIN bump the sequence number */ + if ((flags & TCP_SYN) || (flags & TCP_FIN)) { + pcb->snd_lbb++; + /* optlen does not influence snd_buf */ + } + if (flags & TCP_FIN) { + pcb->flags |= TF_FIN; + } + + /* update number of segments on the queues */ + pcb->snd_queuelen += pbuf_clen(seg->p); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + return ERR_OK; +} + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void +tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) +{ + /* Pad with two NOP options to make everything nicely aligned */ + opts[0] = PP_HTONL(0x0101080A); + opts[1] = lwip_htonl(sys_now()); + opts[2] = lwip_htonl(pcb->ts_recent); +} +#endif + +#if LWIP_WND_SCALE +/** Build a window scale option (3 bytes long) at the specified options pointer) + * + * @param opts option pointer where to store the window scale option + */ +static void +tcp_build_wnd_scale_option(u32_t *opts) +{ + /* Pad with one NOP option to make everything nicely aligned */ + opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE); +} +#endif + +/** + * Send an ACK without data. + * + * @param pcb Protocol control block for the TCP connection to send the ACK + */ +err_t +tcp_send_empty_ack(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + u8_t optlen = 0; + struct netif *netif; +#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP + struct tcp_hdr *tcphdr; +#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ + +#if LWIP_TCP_TIMESTAMPS + if (pcb->flags & TF_TIMESTAMP) { + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif + + p = tcp_output_alloc_header(pcb, optlen, 0, lwip_htonl(pcb->snd_nxt)); + if (p == NULL) { + /* let tcp_fasttmr retry sending this ACK */ + pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); + return ERR_BUF; + } +#if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP + tcphdr = (struct tcp_hdr *)p->payload; +#endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, + ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); + + /* NB. MSS and window scale options are only sent on SYNs, so ignore them here */ +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (pcb->flags & TF_TIMESTAMP) { + tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); + } +#endif + + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } +#endif + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, pcb->tos, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + } + pbuf_free(p); + + if (err != ERR_OK) { + /* let tcp_fasttmr retry sending this ACK */ + pcb->flags |= (TF_ACK_DELAY | TF_ACK_NOW); + } else { + /* remove ACK flags from the PCB, as we sent an empty ACK now */ + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + + return err; +} + +/** + * @ingroup tcp_raw + * Find out what we can send and send it + * + * @param pcb Protocol control block for the TCP connection to send data + * @return ERR_OK if data has been sent or nothing to send + * another err_t on error + */ +err_t +tcp_output(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg, *useg; + u32_t wnd, snd_nxt; + err_t err; + struct netif *netif; +#if TCP_CWND_DEBUG + s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ + + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_output for listen-pcbs", + pcb->state != LISTEN); + + /* First, check if we are invoked by the TCP input processing + code. If so, we do not output anything. Instead, we rely on the + input processing code to call us when input processing is done + with. */ + if (tcp_input_pcb == pcb) { + return ERR_OK; + } + + wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + + seg = pcb->unsent; + + /* If the TF_ACK_NOW flag is set and no data will be sent (either + * because the ->unsent queue is empty or because the window does + * not allow it), construct an empty ACK segment and send it. + * + * If data is to be sent, we will just piggyback the ACK (see below). + */ + if (pcb->flags & TF_ACK_NOW && + (seg == NULL || + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { + return tcp_send_empty_ack(pcb); + } + + /* useg should point to last segment on unacked queue */ + useg = pcb->unacked; + if (useg != NULL) { + for (; useg->next != NULL; useg = useg->next); + } + + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + return ERR_RTE; + } + + /* If we don't have a local IP address, we get one from netif */ + if (ip_addr_isany(&pcb->local_ip)) { + const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, &pcb->remote_ip); + if (local_ip == NULL) { + return ERR_RTE; + } + ip_addr_copy(pcb->local_ip, *local_ip); + } + +#if TCP_OUTPUT_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", + (void*)pcb->unsent)); + } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG + if (seg == NULL) { + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F + ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F + ", seg == NULL, ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); + } else { + LWIP_DEBUGF(TCP_CWND_DEBUG, + ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F + ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, + lwip_ntohl(seg->tcphdr->seqno), pcb->lastack)); + } +#endif /* TCP_CWND_DEBUG */ + /* Check if we need to start the persistent timer when the next unsent segment + * does not fit within the remaining send window and RTO timer is not running (we + * have no in-flight data). A traditional approach would fill the remaining window + * with part of the unsent segment (which will engage zero-window probing upon + * reception of the zero window update from the receiver). This ensures the + * subsequent window update is reliably received. With the goal of being lightweight, + * we avoid splitting the unsent segment and treat the window as already zero. + */ + if (seg != NULL && + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd && + wnd > 0 && wnd == pcb->snd_wnd && pcb->unacked == NULL) { + /* Start the persist timer */ + if (pcb->persist_backoff == 0) { + pcb->persist_cnt = 0; + pcb->persist_backoff = 1; + } + goto output_done; + } + /* data available and window allows it to be sent? */ + while (seg != NULL && + lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { + LWIP_ASSERT("RST not expected here!", + (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); + /* Stop sending if the nagle algorithm would prevent it + * Don't stop: + * - if tcp_write had a memory error before (prevent delayed ACK timeout) or + * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - + * either seg->next != NULL or pcb->unacked == NULL; + * RST is no sent using tcp_write/tcp_output. + */ + if ((tcp_do_output_nagle(pcb) == 0) && + ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) { + break; + } +#if TCP_CWND_DEBUG + LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", + pcb->snd_wnd, pcb->cwnd, wnd, + lwip_ntohl(seg->tcphdr->seqno) + seg->len - + pcb->lastack, + lwip_ntohl(seg->tcphdr->seqno), pcb->lastack, i)); + ++i; +#endif /* TCP_CWND_DEBUG */ + + if (pcb->state != SYN_SENT) { + TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); + } + +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ + err = tcp_output_segment(seg, pcb, netif); + if (err != ERR_OK) { + /* segment could not be sent, for whatever reason */ + pcb->flags |= TF_NAGLEMEMERR; + return err; + } + pcb->unsent = seg->next; + if (pcb->state != SYN_SENT) { + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + } + snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; + } + /* put segment on unacknowledged list if length > 0 */ + if (TCP_TCPLEN(seg) > 0) { + seg->next = NULL; + /* unacked list is empty? */ + if (pcb->unacked == NULL) { + pcb->unacked = seg; + useg = seg; + /* unacked list is not empty? */ + } else { + /* In the case of fast retransmit, the packet should not go to the tail + * of the unacked queue, but rather somewhere before it. We need to check for + * this case. -STJ Jul 27, 2004 */ + if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) { + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; + } else { + /* add segment to tail of unacked list */ + useg->next = seg; + useg = useg->next; + } + } + /* do not queue empty segments on the unacked list */ + } else { + tcp_seg_free(seg); + } + seg = pcb->unsent; + } +output_done: +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + pcb->flags &= ~TF_NAGLEMEMERR; + return ERR_OK; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + * @param netif the netif used to send the segment + */ +static err_t +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif) +{ + err_t err; + u16_t len; + u32_t *opts; + + if (seg->p->ref != 1) { + /* This can happen if the pbuf of this segment is still referenced by the + netif driver due to deferred transmission. Since this function modifies + p->len, we must not continue in this case. */ + return ERR_OK; + } + + /* The TCP header has already been constructed, but the ackno and + wnd fields remain. */ + seg->tcphdr->ackno = lwip_htonl(pcb->rcv_nxt); + + /* advertise our receive window size in this TCP segment */ +#if LWIP_WND_SCALE + if (seg->flags & TF_SEG_OPTS_WND_SCALE) { + /* The Window field in a SYN segment itself (the only type where we send + the window scale option) is never scaled. */ + seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(pcb->rcv_ann_wnd)); + } else +#endif /* LWIP_WND_SCALE */ + { + seg->tcphdr->wnd = lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd))); + } + + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + + /* Add any requested options. NB MSS option is only set on SYN + packets, so ignore it here */ + /* cast through void* to get rid of alignment warnings */ + opts = (u32_t *)(void *)(seg->tcphdr + 1); + if (seg->flags & TF_SEG_OPTS_MSS) { + u16_t mss; +#if TCP_CALCULATE_EFF_SEND_MSS + mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip); +#else /* TCP_CALCULATE_EFF_SEND_MSS */ + mss = TCP_MSS; +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + *opts = TCP_BUILD_MSS_OPTION(mss); + opts += 1; + } +#if LWIP_TCP_TIMESTAMPS + pcb->ts_lastacksent = pcb->rcv_nxt; + + if (seg->flags & TF_SEG_OPTS_TS) { + tcp_build_timestamp_option(pcb, opts); + opts += 3; + } +#endif +#if LWIP_WND_SCALE + if (seg->flags & TF_SEG_OPTS_WND_SCALE) { + tcp_build_wnd_scale_option(opts); + opts += 1; + } +#endif + + /* Set retransmission timer running if it is not currently enabled + This must be set before checking the route. */ + if (pcb->rtime < 0) { + pcb->rtime = 0; + } + + if (pcb->rttest == 0) { + pcb->rttest = tcp_ticks; + pcb->rtseq = lwip_ntohl(seg->tcphdr->seqno); + + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); + } + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", + lwip_htonl(seg->tcphdr->seqno), lwip_htonl(seg->tcphdr->seqno) + + seg->len)); + + len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + if (len == 0) { + /** Exclude retransmitted segments from this count. */ + MIB2_STATS_INC(mib2.tcpoutsegs); + } + + seg->p->len -= len; + seg->p->tot_len -= len; + + seg->p->payload = seg->tcphdr; + + seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { +#if TCP_CHECKSUM_ON_COPY + u32_t acc; +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { + LWIP_ASSERT("data included but not checksummed", + seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); + } + + /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ + acc = ip_chksum_pseudo_partial(seg->p, IP_PROTO_TCP, + seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip); + /* add payload checksum */ + if (seg->chksum_swapped) { + seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); + seg->chksum_swapped = 0; + } + acc += (u16_t)~(seg->chksum); + seg->tcphdr->chksum = FOLD_U32T(acc); +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + if (chksum_slow != seg->tcphdr->chksum) { + TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL( + ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", + seg->tcphdr->chksum, chksum_slow)); + seg->tcphdr->chksum = chksum_slow; + } +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ +#else /* TCP_CHECKSUM_ON_COPY */ + seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); +#endif /* TCP_CHECKSUM_ON_COPY */ + } +#endif /* CHECKSUM_GEN_TCP */ + TCP_STATS_INC(tcp.xmit); + + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + pcb->tos, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + return err; +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) either to + * abort a connection or to show that there is no matching local connection + * for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + struct netif *netif; + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= sizeof(struct tcp_hdr))); + + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = lwip_htons(local_port); + tcphdr->dest = lwip_htons(remote_port); + tcphdr->seqno = lwip_htonl(seqno); + tcphdr->ackno = lwip_htonl(ackno); + TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); +#if LWIP_WND_SCALE + tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); +#else + tcphdr->wnd = PP_HTONS(TCP_WND); +#endif + tcphdr->chksum = 0; + tcphdr->urgp = 0; + + TCP_STATS_INC(tcp.xmit); + MIB2_STATS_INC(mib2.tcpoutrsts); + + netif = ip_route(local_ip, remote_ip); + if (netif != NULL) { +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + local_ip, remote_ip); + } +#endif + /* Send output with hardcoded TTL/HL since we have no access to the pcb */ + ip_output_if(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP, netif); + } + pbuf_free(p); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move all unacked segments to the head of the unsent queue */ + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); + /* concatenate unsent queue after unacked queue */ + seg->next = pcb->unsent; +#if TCP_OVERSIZE_DBGCHECK + /* if last unsent changed, we need to update unsent_oversize */ + if (pcb->unsent == NULL) { + pcb->unsent_oversize = seg->oversize_left; + } +#endif /* TCP_OVERSIZE_DBGCHECK */ + /* unsent queue is the concatenated queue (of unacked, unsent) */ + pcb->unsent = pcb->unacked; + /* unacked queue is now empty */ + pcb->unacked = NULL; + + /* increment number of retransmissions */ + if (pcb->nrtx < 0xFF) { + ++pcb->nrtx; + } + + /* Don't take any RTT measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission */ + tcp_output(pcb); +} + +/** + * Requeue the first unacked segment for retransmission + * + * Called by tcp_receive() for fast retransmit. + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + struct tcp_seg **cur_seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move the first unacked segment to the unsent queue */ + /* Keep the unsent queue sorted. */ + seg = pcb->unacked; + pcb->unacked = seg->next; + + cur_seg = &(pcb->unsent); + while (*cur_seg && + TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = *cur_seg; + *cur_seg = seg; +#if TCP_OVERSIZE + if (seg->next == NULL) { + /* the retransmitted segment is last in unsent, so reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ + + if (pcb->nrtx < 0xFF) { + ++pcb->nrtx; + } + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + MIB2_STATS_INC(mib2.tcpretranssegs); + /* No need to call tcp_output: we are always called from tcp_input() + and thus tcp_output directly returns. */ +} + + +/** + * Handle retransmission after three dupacks received + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit_fast(struct tcp_pcb *pcb) +{ + if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: dupacks %"U16_F" (%"U32_F + "), fast retransmit %"U32_F"\n", + (u16_t)pcb->dupacks, pcb->lastack, + lwip_ntohl(pcb->unacked->tcphdr->seqno))); + tcp_rexmit(pcb); + + /* Set ssthresh to half of the minimum of the current + * cwnd and the advertised window */ + pcb->ssthresh = LWIP_MIN(pcb->cwnd, pcb->snd_wnd) / 2; + + /* The minimum value for ssthresh should be 2 MSS */ + if (pcb->ssthresh < (2U * pcb->mss)) { + LWIP_DEBUGF(TCP_FR_DEBUG, + ("tcp_receive: The minimum value for ssthresh %"TCPWNDSIZE_F + " should be min 2 mss %"U16_F"...\n", + pcb->ssthresh, (u16_t)(2*pcb->mss))); + pcb->ssthresh = 2*pcb->mss; + } + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + pcb->flags |= TF_INFR; + + /* Reset the retransmission timer to prevent immediate rto retransmissions */ + pcb->rtime = 0; + } +} + + +/** + * Send keepalive packets to keep a connection active although + * no data is sent over it. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a keepalive packet + */ +err_t +tcp_keepalive(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + struct netif *netif; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent)); + + p = tcp_output_alloc_header(pcb, 0, 0, lwip_htonl(pcb->snd_nxt - 1)); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_keepalive: could not allocate memory for pbuf\n")); + return ERR_MEM; + } + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } +#endif /* CHECKSUM_GEN_TCP */ + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + } + pbuf_free(p); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F" err %d.\n", + pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); + return err; +} + + +/** + * Send persist timer zero-window probes to keep a connection active + * when a window update is lost. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a zero-window probe packet + */ +err_t +tcp_zero_window_probe(struct tcp_pcb *pcb) +{ + err_t err; + struct pbuf *p; + struct tcp_hdr *tcphdr; + struct tcp_seg *seg; + u16_t len; + u8_t is_fin; + u32_t snd_nxt; + struct netif *netif; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip); + LWIP_DEBUGF(TCP_DEBUG, ("\n")); + + LWIP_DEBUGF(TCP_DEBUG, + ("tcp_zero_window_probe: tcp_ticks %"U32_F + " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", + tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent)); + + seg = pcb->unacked; + + if (seg == NULL) { + seg = pcb->unsent; + } + if (seg == NULL) { + /* nothing to send, zero window probe not needed */ + return ERR_OK; + } + + is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); + /* we want to send one seqno: either FIN or data (no options) */ + len = is_fin ? 0 : 1; + + p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); + return ERR_MEM; + } + tcphdr = (struct tcp_hdr *)p->payload; + + if (is_fin) { + /* FIN segment, no data */ + TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); + } else { + /* Data segment, copy in one byte from the head of the unacked queue */ + char *d = ((char *)p->payload + TCP_HLEN); + /* Depending on whether the segment has already been sent (unacked) or not + (unsent), seg->p->payload points to the IP header or TCP header. + Ensure we copy the first TCP data byte: */ + pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); + } + + /* The byte may be acknowledged without the window being opened. */ + snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + 1; + if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { + pcb->snd_nxt = snd_nxt; + } + + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } +#endif + TCP_STATS_INC(tcp.xmit); + + /* Send output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + } + + pbuf_free(p); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F + " ackno %"U32_F" err %d.\n", + pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err)); + return err; +} +#endif /* LWIP_TCP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/timeouts.c b/Sming/third-party/lwip2/lwip2-src/src/core/timeouts.c new file mode 100644 index 0000000000..227d71fc9b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/timeouts.c @@ -0,0 +1,433 @@ +/** + * @file + * Stack-internal timers implementation. + * This file includes timer callbacks for stack-internal timers as well as + * functions to set up or stop timers and check for expired timers. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#include "lwip/timeouts.h" +#include "lwip/priv/tcp_priv.h" + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/priv/tcpip_priv.h" + +#include "lwip/ip4_frag.h" +#include "lwip/etharp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" +#include "lwip/sys.h" +#include "lwip/pbuf.h" + +#if LWIP_DEBUG_TIMERNAMES +#define HANDLER(x) x, #x +#else /* LWIP_DEBUG_TIMERNAMES */ +#define HANDLER(x) x +#endif /* LWIP_DEBUG_TIMERNAMES */ + +/** This array contains all stack-internal cyclic timers. To get the number of + * timers, use LWIP_ARRAYSIZE() */ +const struct lwip_cyclic_timer lwip_cyclic_timers[] = { +#if LWIP_TCP + /* The TCP timer is a special case: it does not have to run always and + is triggered to start from TCP using tcp_timer_needed() */ + {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, +#endif /* LWIP_TCP */ +#if LWIP_IPV4 +#if IP_REASSEMBLY + {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, +#endif /* IP_REASSEMBLY */ +#if LWIP_ARP + {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, +#endif /* LWIP_ARP */ +#if LWIP_DHCP + {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, + {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP + {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4 */ +#if LWIP_DNS + {DNS_TMR_INTERVAL, HANDLER(dns_tmr)}, +#endif /* LWIP_DNS */ +#if LWIP_IPV6 + {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)}, +#if LWIP_IPV6_REASS + {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)}, +#endif /* LWIP_IPV6_REASS */ +#if LWIP_IPV6_MLD + {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)}, +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ +}; + +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM + +/** The one and only timeout list */ +static struct sys_timeo *next_timeout; +static u32_t timeouts_last_time; + +#if LWIP_TCP +/** global variable that shows if the tcp timer is currently scheduled or not */ +static int tcpip_tcp_timer_active; + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +tcpip_tcp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + /* call TCP timer handler */ + tcp_tmr(); + /* timer still needed? */ + if (tcp_active_pcbs || tcp_tw_pcbs) { + /* restart timer */ + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } else { + /* disable timer */ + tcpip_tcp_timer_active = 0; + } +} + +/** + * Called from TCP_REG when registering a new PCB: + * the reason is to have the TCP timer only running when + * there are active (or time-wait) PCBs. + */ +void +tcp_timer_needed(void) +{ + /* timer is off but needed again? */ + if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { + /* enable and start timer */ + tcpip_tcp_timer_active = 1; + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } +} +#endif /* LWIP_TCP */ + +/** + * Timer callback function that calls mld6_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +cyclic_timer(void *arg) +{ + const struct lwip_cyclic_timer* cyclic = (const struct lwip_cyclic_timer*)arg; +#if LWIP_DEBUG_TIMERNAMES + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name)); +#endif + cyclic->handler(); + sys_timeout(cyclic->interval_ms, cyclic_timer, arg); +} + +/** Initialize this module */ +void sys_timeouts_init(void) +{ + size_t i; + /* tcp_tmr() at index 0 is started on demand */ + for (i = 1; i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) { + /* we have to cast via size_t to get rid of const warning + (this is OK as cyclic_timer() casts back to const* */ + sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i])); + } + + /* Initialise timestamp for sys_check_timeouts */ + timeouts_last_time = sys_now(); +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_timeouts_mbox_fetch() + * - by calling sys_check_timeouts() (NO_SYS==1 only) + * + * @param msecs time in milliseconds after that the timer should expire + * @param handler callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +#if LWIP_DEBUG_TIMERNAMES +void +sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) +#else /* LWIP_DEBUG_TIMERNAMES */ +void +sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +#endif /* LWIP_DEBUG_TIMERNAMES */ +{ + struct sys_timeo *timeout, *t; + u32_t now, diff; + + timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); + return; + } + + now = sys_now(); + if (next_timeout == NULL) { + diff = 0; + timeouts_last_time = now; + } else { + diff = now - timeouts_last_time; + } + + timeout->next = NULL; + timeout->h = handler; + timeout->arg = arg; + timeout->time = msecs + diff; +#if LWIP_DEBUG_TIMERNAMES + timeout->handler_name = handler_name; + LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", + (void *)timeout, msecs, handler_name, (void *)arg)); +#endif /* LWIP_DEBUG_TIMERNAMES */ + + if (next_timeout == NULL) { + next_timeout = timeout; + return; + } + + if (next_timeout->time > msecs) { + next_timeout->time -= msecs; + timeout->next = next_timeout; + next_timeout = timeout; + } else { + for (t = next_timeout; t != NULL; t = t->next) { + timeout->time -= t->time; + if (t->next == NULL || t->next->time > timeout->time) { + if (t->next != NULL) { + t->next->time -= timeout->time; + } else if (timeout->time > msecs) { + /* If this is the case, 'timeouts_last_time' and 'now' differs too much. + This can be due to sys_check_timeouts() not being called at the right + times, but also when stopping in a breakpoint. Anyway, let's assume + this is not wanted, so add the first timer's time instead of 'diff' */ + timeout->time = msecs + next_timeout->time; + } + timeout->next = t->next; + t->next = timeout; + break; + } + } + } +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry (subsequent entries remain untouched), even though the timeout has not + * triggered yet. + * + * @param handler callback function that would be called by the timeout + * @param arg callback argument that would be passed to handler +*/ +void +sys_untimeout(sys_timeout_handler handler, void *arg) +{ + struct sys_timeo *prev_t, *t; + + if (next_timeout == NULL) { + return; + } + + for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { + if ((t->h == handler) && (t->arg == arg)) { + /* We have a match */ + /* Unlink from previous in list */ + if (prev_t == NULL) { + next_timeout = t->next; + } else { + prev_t->next = t->next; + } + /* If not the last one, add time of this one back to next */ + if (t->next != NULL) { + t->next->time += t->time; + } + memp_free(MEMP_SYS_TIMEOUT, t); + return; + } + } + return; +} + +/** + * @ingroup lwip_nosys + * Handle timeouts for NO_SYS==1 (i.e. without using + * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout + * handler functions when timeouts expire. + * + * Must be called periodically from your main loop. + */ +#if !NO_SYS && !defined __DOXYGEN__ +static +#endif /* !NO_SYS */ +void +sys_check_timeouts(void) +{ + if (next_timeout) { + struct sys_timeo *tmptimeout; + u32_t diff; + sys_timeout_handler handler; + void *arg; + u8_t had_one; + u32_t now; + + now = sys_now(); + /* this cares for wraparounds */ + diff = now - timeouts_last_time; + do { + PBUF_CHECK_FREE_OOSEQ(); + had_one = 0; + tmptimeout = next_timeout; + if (tmptimeout && (tmptimeout->time <= diff)) { + /* timeout has expired */ + had_one = 1; + timeouts_last_time += tmptimeout->time; + diff -= tmptimeout->time; + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", + tmptimeout->handler_name, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { +#if !NO_SYS + /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the + timeout handler function. */ + LOCK_TCPIP_CORE(); +#endif /* !NO_SYS */ + handler(arg); +#if !NO_SYS + UNLOCK_TCPIP_CORE(); +#endif /* !NO_SYS */ + } + LWIP_TCPIP_THREAD_ALIVE(); + } + /* repeat until all expired timers have been called */ + } while (had_one); + } +} + +/** Set back the timestamp of the last call to sys_check_timeouts() + * This is necessary if sys_check_timeouts() hasn't been called for a long + * time (e.g. while saving energy) to prevent all timer functions of that + * period being called. + */ +void +sys_restart_timeouts(void) +{ + timeouts_last_time = sys_now(); +} + +/** Return the time left before the next timeout is due. If no timeouts are + * enqueued, returns 0xffffffff + */ +#if !NO_SYS +static +#endif /* !NO_SYS */ +u32_t +sys_timeouts_sleeptime(void) +{ + u32_t diff; + if (next_timeout == NULL) { + return 0xffffffff; + } + diff = sys_now() - timeouts_last_time; + if (diff > next_timeout->time) { + return 0; + } else { + return next_timeout->time - diff; + } +} + +#if !NO_SYS + +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +void +sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +{ + u32_t sleeptime; + +again: + if (!next_timeout) { + sys_arch_mbox_fetch(mbox, msg, 0); + return; + } + + sleeptime = sys_timeouts_sleeptime(); + if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) { + /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred + before a message could be fetched. */ + sys_check_timeouts(); + /* We try again to fetch a message from the mbox. */ + goto again; + } +} + +#endif /* NO_SYS */ + +#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ +/* Satisfy the TCP code which calls this function */ +void +tcp_timer_needed(void) +{ +} +#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/core/udp.c b/Sming/third-party/lwip2/lwip2-src/src/core/udp.c new file mode 100644 index 0000000000..ce2e3d295f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/core/udp.c @@ -0,0 +1,1191 @@ +/** + * @file + * User Datagram Protocol module\n + * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n + * See also @ref udp_raw + * + * @defgroup udp_raw UDP + * @ingroup callbackstyle_api + * User Datagram Protocol module\n + * @see @ref raw_api and @ref netconn + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! + */ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/icmp6.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" + +#include + +#ifndef UDP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define UDP_LOCAL_PORT_RANGE_START 0xc000 +#define UDP_LOCAL_PORT_RANGE_END 0xffff +#define UDP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)) +#endif + +/* last local UDP port */ +static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * Initialize this module. + */ +void +udp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + +/** + * Allocate a new local UDP port. + * + * @return a new (free) local UDP port number + */ +static u16_t +udp_new_port(void) +{ + u16_t n = 0; + struct udp_pcb *pcb; + +again: + if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { + udp_port = UDP_LOCAL_PORT_RANGE_START; + } + /* Check all PCBs. */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == udp_port) { + if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + return udp_port; +} + +/** Common code to see if the current input packet matches the pcb + * (current input packet is accessed via ip(4/6)_current_* macros) + * + * @param pcb pcb to check + * @param inp network interface on which the datagram was received (only used for IPv4) + * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4) + * @return 1 on match, 0 otherwise + */ +static u8_t +udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) +{ + LWIP_UNUSED_ARG(inp); /* in IPv6 only case */ + LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ + + /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { +#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV + if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { + return 0; + } +#endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */ + return 1; + } + + /* Only need to check PCB if incoming IP version matches PCB IP version */ + if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { +#if LWIP_IPV4 + /* Special case: IPv4 broadcast: all or broadcasts in my subnet + * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ + if (broadcast != 0) { +#if IP_SOF_BROADCAST_RECV + if (ip_get_option(pcb, SOF_BROADCAST)) +#endif /* IP_SOF_BROADCAST_RECV */ + { + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || + ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || + ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { + return 1; + } + } + } else +#endif /* LWIP_IPV4 */ + /* Handle IPv4 and IPv6: all or exact match */ + if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { + return 1; + } + } + + return 0; +} + +/** + * Process an incoming UDP datagram. + * + * Given an incoming UDP datagram (as a chain of pbufs) this function + * finds a corresponding UDP PCB and hands over the pbuf to the pcbs + * recv function. If no pcb is found or the datagram is incorrect, the + * pbuf is freed. + * + * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) + * @param inp network interface on which the datagram was received. + * + */ +void +udp_input(struct pbuf *p, struct netif *inp) +{ + struct udp_hdr *udphdr; + struct udp_pcb *pcb, *prev; + struct udp_pcb *uncon_pcb; + u16_t src, dest; + u8_t broadcast; + u8_t for_us = 0; + + LWIP_UNUSED_ARG(inp); + + PERF_START; + + UDP_STATS_INC(udp.recv); + + /* Check minimum length (UDP header) */ + if (p->len < UDP_HLEN) { + /* drop short packets */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); + UDP_STATS_INC(udp.lenerr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + goto end; + } + + udphdr = (struct udp_hdr *)p->payload; + + /* is broadcast packet ? */ + broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); + + LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); + + /* convert src and dest ports to host byte order */ + src = lwip_ntohs(udphdr->src); + dest = lwip_ntohs(udphdr->dest); + + udp_debug_print(udphdr); + + /* print the UDP source and destination */ + LWIP_DEBUGF(UDP_DEBUG, ("udp (")); + ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); + ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr()); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); + + pcb = NULL; + prev = NULL; + uncon_pcb = NULL; + /* Iterate through the UDP pcb list for a matching pcb. + * 'Perfect match' pcbs (connected to the remote port & ip address) are + * preferred. If no perfect match is found, the first unconnected pcb that + * matches the local port and ip address gets the datagram. */ + for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + /* print the PCB local and remote address */ + LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); + ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); + ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip); + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); + + /* compare PCB local addr+port to UDP destination addr+port */ + if ((pcb->local_port == dest) && + (udp_input_local_match(pcb, inp, broadcast) != 0)) { + if (((pcb->flags & UDP_FLAGS_CONNECTED) == 0) && + ((uncon_pcb == NULL) +#if SO_REUSE + /* prefer specific IPs over cath-all */ + || !ip_addr_isany(&pcb->local_ip) +#endif /* SO_REUSE */ + )) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; + } + + /* compare PCB remote addr+port to UDP source addr+port */ + if ((pcb->remote_port == src) && + (ip_addr_isany_val(pcb->remote_ip) || + ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { + /* the first fully matching PCB */ + if (prev != NULL) { + /* move the pcb to the front of udp_pcbs so that is + found faster next time */ + prev->next = pcb->next; + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } else { + UDP_STATS_INC(udp.cachehit); + } + break; + } + } + + prev = pcb; + } + /* no fully matching pcb found? then look for an unconnected pcb */ + if (pcb == NULL) { + pcb = uncon_pcb; + } + + /* Check checksum if this is a match or if it was directed at us. */ + if (pcb != NULL) { + for_us = 1; + } else { +#if LWIP_IPV6 + if (ip_current_is_v6()) { + for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 + if (!ip_current_is_v6()) { + for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); + } +#endif /* LWIP_IPV4 */ + } + + if (for_us) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); +#if CHECKSUM_CHECK_UDP + IF__NETIF_CHECKSUM_ENABLED(inp, CHECKSUM_CHECK_UDP) { +#if LWIP_UDPLITE + if (ip_current_header_proto() == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ + u16_t chklen = lwip_ntohs(udphdr->len); + if (chklen < sizeof(struct udp_hdr)) { + if (chklen == 0) { + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet (See RFC 3828 chap. 3.1) */ + chklen = p->tot_len; + } else { + /* At least the UDP-Lite header must be covered by the + checksum! (Again, see RFC 3828 chap. 3.1) */ + goto chkerr; + } + } + if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, + p->tot_len, chklen, + ip_current_src_addr(), ip_current_dest_addr()) != 0) { + goto chkerr; + } + } else +#endif /* LWIP_UDPLITE */ + { + if (udphdr->chksum != 0) { + if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, + ip_current_src_addr(), + ip_current_dest_addr()) != 0) { + goto chkerr; + } + } + } + } +#endif /* CHECKSUM_CHECK_UDP */ + if (pbuf_header(p, -UDP_HLEN)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + goto end; + } + + if (pcb != NULL) { + MIB2_STATS_INC(mib2.udpindatagrams); +#if SO_REUSE && SO_REUSE_RXTOALL + if (ip_get_option(pcb, SOF_REUSEADDR) && + (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { + /* pass broadcast- or multicast packets to all multicast pcbs + if SOF_REUSEADDR is set on the first match */ + struct udp_pcb *mpcb; + u8_t p_header_changed = 0; + s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); + for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { + if (mpcb != pcb) { + /* compare PCB local addr+port to UDP destination addr+port */ + if ((mpcb->local_port == dest) && + (udp_input_local_match(mpcb, inp, broadcast) != 0)) { + /* pass a copy of the packet to all local matches */ + if (mpcb->recv != NULL) { + struct pbuf *q; + /* for that, move payload to IP header again */ + if (p_header_changed == 0) { + pbuf_header_force(p, hdrs_len); + p_header_changed = 1; + } + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + err_t err = pbuf_copy(q, p); + if (err == ERR_OK) { + /* move payload to UDP data */ + pbuf_header(q, -hdrs_len); + mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + } + } + } + } + } + } + if (p_header_changed) { + /* and move payload to UDP data again */ + pbuf_header(p, -hdrs_len); + } + } +#endif /* SO_REUSE && SO_REUSE_RXTOALL */ + /* callback */ + if (pcb->recv != NULL) { + /* now the recv function is responsible for freeing p */ + pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); + } else { + /* no recv function registered? then we have to free the pbuf! */ + pbuf_free(p); + goto end; + } + } else { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); + +#if LWIP_ICMP || LWIP_ICMP6 + /* No match was found, send ICMP destination port unreachable unless + destination address was broadcast/multicast. */ + if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { + /* move payload pointer back to ip header */ + pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN)); + icmp_port_unreach(ip_current_is_v6(), p); + } +#endif /* LWIP_ICMP || LWIP_ICMP6 */ + UDP_STATS_INC(udp.proterr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpnoports); + pbuf_free(p); + } + } else { + pbuf_free(p); + } +end: + PERF_STOP("udp_input"); + return; +#if CHECKSUM_CHECK_UDP +chkerr: + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + MIB2_STATS_INC(mib2.udpinerrors); + pbuf_free(p); + PERF_STOP("udp_input"); +#endif /* CHECKSUM_CHECK_UDP */ +} + +/** + * @ingroup udp_raw + * Send data using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * + * The datagram will be sent to the current remote_ip & remote_port + * stored in pcb. If the pcb is not bound to a port, it will + * automatically be bound to a random port. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * - ERR_VAL. No PCB or PCB is dual-stack + * - More errors could be returned by lower protocol layers. + * + * @see udp_disconnect() udp_sendto() + */ +err_t +udp_send(struct udp_pcb *pcb, struct pbuf *p) +{ + if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { + return ERR_VAL; + } + + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); +} + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +/** @ingroup udp_raw + * Same as udp_send() but with checksum + */ +err_t +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { + return ERR_VAL; + } + + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +/** + * @ingroup udp_raw + * Send data to a specified address using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * If the PCB already has a remote address association, it will + * be restored after the data is sent. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** @ingroup udp_raw + * Same as udp_sendto(), but with checksum */ +err_t +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct netif *netif; + const ip_addr_t *dst_ip_route = dst_ip; + + if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); + +#if LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) + if (ip_addr_ismulticast(dst_ip_route)) { +#if LWIP_IPV6 + if (IP_IS_V6(dst_ip)) { + /* For multicast, find a netif based on source address. */ + dst_ip_route = &pcb->local_ip; + } else +#endif /* LWIP_IPV6 */ + { +#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS + /* IPv4 does not use source-based routing by default, so we use an + administratively selected interface for multicast by default. + However, this can be overridden by setting an interface address + in pcb->multicast_ip that is used for routing. */ + if (!ip_addr_isany_val(pcb->multicast_ip) && + !ip4_addr_cmp(ip_2_ip4(&pcb->multicast_ip), IP4_ADDR_BROADCAST)) { + dst_ip_route = &pcb->multicast_ip; + } +#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */ + } + } +#endif /* LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) */ + + /* find the outgoing network interface for this packet */ + if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + /* Don't call ip_route() with IP_ANY_TYPE */ + netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route); + } else { + netif = ip_route(&pcb->local_ip, dst_ip_route); + } + + /* no outgoing network interface could be found? */ + if (netif == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip); + LWIP_DEBUGF(UDP_DEBUG, ("\n")); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +} + +/** + * @ingroup udp_raw + * Send data to a specified address using UDP. + * The netif used for sending can be specified. + * + * This function exists mainly for DHCP, to be able to send UDP packets + * on a netif that is still down. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * @param netif the netif used for sending. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + const ip_addr_t *src_ip; + + if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + + /* PCB local address is IP_ANY_ADDR? */ +#if LWIP_IPV6 + if (IP_IS_V6(dst_ip)) { + if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip))) { + src_ip = ip6_select_source_address(netif, ip_2_ip6(dst_ip)); + if (src_ip == NULL) { + /* No suitable source address was found. */ + return ERR_RTE; + } + } else { + /* use UDP PCB local IPv6 address as source address, if still valid. */ + if (netif_get_ip6_addr_match(netif, ip_2_ip6(&pcb->local_ip)) < 0) { + /* Address isn't valid anymore. */ + return ERR_RTE; + } + src_ip = &pcb->local_ip; + } + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || + ip4_addr_ismulticast(ip_2_ip4(&pcb->local_ip))) { + /* if the local_ip is any or multicast + * use the outgoing network interface IP address as source address */ + src_ip = netif_ip_addr4(netif); + } else { + /* check if UDP PCB local IP address is correct + * this could be an old address if netif->ip_addr has changed */ + if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { + /* local_ip doesn't match, drop the packet */ + return ERR_RTE; + } + /* use UDP PCB local IP address as source address */ + src_ip = &pcb->local_ip; + } +#endif /* LWIP_IPV4 */ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); +#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +} + +/** @ingroup udp_raw + * Same as @ref udp_sendto_if, but with source address */ +err_t +udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); +} + +/** Same as udp_sendto_if_src(), but with checksum */ +err_t +udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum, const ip_addr_t *src_ip) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct udp_hdr *udphdr; + err_t err; + struct pbuf *q; /* q will be sent down the stack */ + u8_t ip_proto; + u8_t ttl; + + if ((pcb == NULL) || (dst_ip == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || + !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { + return ERR_VAL; + } + +#if LWIP_IPV4 && IP_SOF_BROADCAST + /* broadcast filter? */ + if (!ip_get_option(pcb, SOF_BROADCAST) && +#if LWIP_IPV6 + IP_IS_V4(dst_ip) && +#endif /* LWIP_IPV6 */ + ip_addr_isbroadcast(dst_ip, netif)) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + return ERR_VAL; + } +#endif /* LWIP_IPV4 && IP_SOF_BROADCAST */ + + /* if the PCB is not yet bound to a port, bind it here */ + if (pcb->local_port == 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); + err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); + return err; + } + } + + /* not enough space to add an UDP header to first pbuf in given p chain? */ + if (pbuf_header(p, UDP_HLEN)) { + /* allocate header in a separate new pbuf */ + q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); + return ERR_MEM; + } + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p (only if p contains data) */ + pbuf_chain(q, p); + } + /* first pbuf q points to header pbuf */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* adding space for header within p succeeded */ + /* first pbuf q equals given pbuf */ + q = p; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); + } + LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", + (q->len >= sizeof(struct udp_hdr))); + /* q now represents the packet to be sent */ + udphdr = (struct udp_hdr *)q->payload; + udphdr->src = lwip_htons(pcb->local_port); + udphdr->dest = lwip_htons(dst_port); + /* in UDP, 0 checksum means 'no checksum' */ + udphdr->chksum = 0x0000; + + /* Multicast Loop? */ +#if (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) + if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS) || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); + +#if LWIP_UDPLITE + /* UDP Lite protocol? */ + if (pcb->flags & UDP_FLAGS_UDPLITE) { + u16_t chklen, chklen_hdr; + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); + /* set UDP message length in UDP header */ + chklen_hdr = chklen = pcb->chksum_len_tx; + if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { + if (chklen != 0) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); + } + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet. (See RFC 3828 chap. 3.1) + At least the UDP-Lite header must be covered by the + checksum, therefore, if chksum_len has an illegal + value, we generate the checksum over the complete + packet to be safe. */ + chklen_hdr = 0; + chklen = q->tot_len; + } + udphdr->len = lwip_htons(chklen_hdr); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + chklen = UDP_HLEN; + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, + q->tot_len, chklen, src_ip, dst_ip); +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } + } +#endif /* CHECKSUM_GEN_UDP */ + + ip_proto = IP_PROTO_UDPLITE; + } else +#endif /* LWIP_UDPLITE */ + { /* UDP */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); + udphdr->len = lwip_htons(q->tot_len); + /* calculate checksum */ +#if CHECKSUM_GEN_UDP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { + /* Checksum is mandatory over IPv6. */ + if (IP_IS_V6(dst_ip) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, + q->tot_len, UDP_HLEN, src_ip, dst_ip); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, + src_ip, dst_ip); + } + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; + } + } +#endif /* CHECKSUM_GEN_UDP */ + ip_proto = IP_PROTO_UDP; + } + + /* Determine TTL to use */ +#if LWIP_MULTICAST_TX_OPTIONS + ttl = (ip_addr_ismulticast(dst_ip) ? udp_get_multicast_ttl(pcb) : pcb->ttl); +#else /* LWIP_MULTICAST_TX_OPTIONS */ + ttl = pcb->ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); + /* output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + + /* @todo: must this be increased even if error occurred? */ + MIB2_STATS_INC(mib2.udpoutdatagrams); + + /* did we chain a separate header pbuf earlier? */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + q = NULL; + /* p is still referenced by the caller, and will live on */ + } + + UDP_STATS_INC(udp.xmit); + return err; +} + +/** + * @ingroup udp_raw + * Bind an UDP PCB. + * + * @param pcb UDP PCB to be bound with a local address ipaddr and port. + * @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to + * bind to all local interfaces. + * @param port local UDP port to bind with. Use 0 to automatically bind + * to a random port between UDP_LOCAL_PORT_RANGE_START and + * UDP_LOCAL_PORT_RANGE_END. + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occurred. + * - ERR_USE. The specified ipaddr and port are already bound to by + * another UDP PCB. + * + * @see udp_disconnect() + */ +err_t +udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + u8_t rebind; + +#if LWIP_IPV4 + /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ + if (ipaddr == NULL) { + ipaddr = IP4_ADDR_ANY; + } +#endif /* LWIP_IPV4 */ + + /* still need to check for ipaddr == NULL in IPv6 only case */ + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); + + rebind = 0; + /* Check for double bind and rebind of the same pcb */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + /* is this UDP PCB already on active list? */ + if (pcb == ipcb) { + rebind = 1; + break; + } + } + + /* no port specified? */ + if (port == 0) { + port = udp_new_port(); + if (port == 0) { + /* no more ports available in local range */ + LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); + return ERR_USE; + } + } else { + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb != ipcb) { + /* By default, we don't allow to bind to a port that any other udp + PCB is already bound to, unless *all* PCBs with that port have tha + REUSEADDR flag set. */ +#if SO_REUSE + if (!ip_get_option(pcb, SOF_REUSEADDR) || + !ip_get_option(ipcb, SOF_REUSEADDR)) +#endif /* SO_REUSE */ + { + /* port matches that of PCB in list and REUSEADDR not set -> reject */ + if ((ipcb->local_port == port) && + /* IP address matches? */ + ip_addr_cmp(&ipcb->local_ip, ipaddr)) { + /* other PCB already binds to this local IP and port */ + LWIP_DEBUGF(UDP_DEBUG, + ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); + return ERR_USE; + } + } + } + } + } + + ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); + + pcb->local_port = port; + mib2_udp_bind(pcb); + /* pcb not active yet? */ + if (rebind == 0) { + /* place the PCB on the active list if not already there */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + } + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); + return ERR_OK; +} + +/** + * @ingroup udp_raw + * Connect an UDP PCB. + * + * This will associate the UDP PCB with the remote address. + * + * @param pcb UDP PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * @param port remote UDP port to connect with. + * + * @return lwIP error code + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * The udp pcb is bound to a random local port if not already bound. + * + * @see udp_disconnect() + */ +err_t +udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) +{ + struct udp_pcb *ipcb; + + if ((pcb == NULL) || (ipaddr == NULL)) { + return ERR_VAL; + } + + if (pcb->local_port == 0) { + err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + if (err != ERR_OK) { + return err; + } + } + + ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); + pcb->remote_port = port; + pcb->flags |= UDP_FLAGS_CONNECTED; + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + &pcb->remote_ip); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); + + /* Insert UDP PCB into the list of active UDP PCBs. */ + for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { + if (pcb == ipcb) { + /* already on the list, just return */ + return ERR_OK; + } + } + /* PCB not yet on the list, add PCB now */ + pcb->next = udp_pcbs; + udp_pcbs = pcb; + return ERR_OK; +} + +/** + * @ingroup udp_raw + * Disconnect a UDP PCB + * + * @param pcb the udp pcb to disconnect. + */ +void +udp_disconnect(struct udp_pcb *pcb) +{ + /* reset remote address association */ +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { + ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); + } else { +#endif + ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); +#if LWIP_IPV4 && LWIP_IPV6 + } +#endif + pcb->remote_port = 0; + /* mark PCB as unconnected */ + pcb->flags &= ~UDP_FLAGS_CONNECTED; +} + +/** + * @ingroup udp_raw + * Set a receive callback for a UDP PCB + * + * This callback will be called when receiving a datagram for the pcb. + * + * @param pcb the pcb for which to set the recv callback + * @param recv function pointer of the callback function + * @param recv_arg additional argument to pass to the callback function + */ +void +udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) +{ + /* remember recv() callback and user data */ + pcb->recv = recv; + pcb->recv_arg = recv_arg; +} + +/** + * @ingroup udp_raw + * Remove an UDP PCB. + * + * @param pcb UDP PCB to be removed. The PCB is removed from the list of + * UDP PCB's and the data structure is freed from memory. + * + * @see udp_new() + */ +void +udp_remove(struct udp_pcb *pcb) +{ + struct udp_pcb *pcb2; + + mib2_udp_unbind(pcb); + /* pcb to be removed is first in list? */ + if (udp_pcbs == pcb) { + /* make list start at 2nd pcb */ + udp_pcbs = udp_pcbs->next; + /* pcb not 1st in list */ + } else { + for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { + /* find pcb in udp_pcbs list */ + if (pcb2->next != NULL && pcb2->next == pcb) { + /* remove pcb from list */ + pcb2->next = pcb->next; + break; + } + } + } + memp_free(MEMP_UDP_PCB, pcb); +} + +/** + * @ingroup udp_raw + * Create a UDP PCB. + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new(void) +{ + struct udp_pcb *pcb; + pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); + /* could allocate UDP PCB? */ + if (pcb != NULL) { + /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 + * which means checksum is generated over the whole datagram per default + * (recommended as default by RFC 3828). */ + /* initialize PCB to all zeroes */ + memset(pcb, 0, sizeof(struct udp_pcb)); + pcb->ttl = UDP_TTL; +#if LWIP_MULTICAST_TX_OPTIONS + udp_set_multicast_ttl(pcb, UDP_TTL); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + } + return pcb; +} + +/** + * @ingroup udp_raw + * Create a UDP PCB for specific IP type. + * + * @param type IP address type, see @ref lwip_ip_addr_type definitions. + * If you want to listen to IPv4 and IPv6 (dual-stack) packets, + * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new_ip_type(u8_t type) +{ + struct udp_pcb *pcb; + pcb = udp_new(); +#if LWIP_IPV4 && LWIP_IPV6 + if (pcb != NULL) { + IP_SET_TYPE_VAL(pcb->local_ip, type); + IP_SET_TYPE_VAL(pcb->remote_ip, type); + } +#else + LWIP_UNUSED_ARG(type); +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + return pcb; +} + +/** This function is called from netif.c when address is changed + * + * @param old_addr IP address of the netif before change + * @param new_addr IP address of the netif after change + */ +void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr) +{ + struct udp_pcb* upcb; + + if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { + for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { + /* PCB bound to current local interface address? */ + if (ip_addr_cmp(&upcb->local_ip, old_addr)) { + /* The PCB is bound to the old ipaddr and + * is set to bound to the new one instead */ + ip_addr_copy(upcb->local_ip, *new_addr); + } + } + } +} + +#if UDP_DEBUG +/** + * Print UDP header information for debug purposes. + * + * @param udphdr pointer to the udp header in memory. + */ +void +udp_debug_print(struct udp_hdr *udphdr) +{ + LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", + lwip_ntohs(udphdr->src), lwip_ntohs(udphdr->dest))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); + LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", + lwip_ntohs(udphdr->len), lwip_ntohs(udphdr->chksum))); + LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/api.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/api.h new file mode 100644 index 0000000000..516bd163dd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/api.h @@ -0,0 +1,400 @@ +/** + * @file + * netconn API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_H +#define LWIP_HDR_API_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/arch.h" +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 +#if LWIP_IPV6 +/** If this flag is set then only IPv6 communication is allowed on the + netconn. As per RFC#3493 this features defaults to OFF allowing + dual-stack usage by default. */ +#define NETCONN_FLAG_IPV6_V6ONLY 0x20 +#endif /* LWIP_IPV6 */ + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#if LWIP_IPV6 +#define NETCONN_TYPE_IPV6 0x08 +#define NETCONNTYPE_ISIPV6(t) (((t)&NETCONN_TYPE_IPV6) != 0) +#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF3) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF3) == NETCONN_UDPNOCHKSUM) +#else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISIPV6(t) (0) +#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) +#endif /* LWIP_IPV6 */ + +/** @ingroup netconn_common + * Protocol family and type of the netconn + */ +enum netconn_type { + NETCONN_INVALID = 0, + /** TCP IPv4 */ + NETCONN_TCP = 0x10, +#if LWIP_IPV6 + /** TCP IPv6 */ + NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, +#endif /* LWIP_IPV6 */ + /** UDP IPv4 */ + NETCONN_UDP = 0x20, + /** UDP IPv4 lite */ + NETCONN_UDPLITE = 0x21, + /** UDP IPv4 no checksum */ + NETCONN_UDPNOCHKSUM = 0x22, + +#if LWIP_IPV6 + /** UDP IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, + /** UDP IPv6 lite (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, + /** UDP IPv6 no checksum (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, +#endif /* LWIP_IPV6 */ + + /** Raw connection IPv4 */ + NETCONN_RAW = 0x40 +#if LWIP_IPV6 + /** Raw connection IPv6 (dual-stack by default, unless you call @ref netconn_set_ipv6only) */ + , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ +#endif /* LWIP_IPV6 */ +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Used to inform the callback function about changes + * + * Event explanation: + * + * In the netconn implementation, there are three ways to block a client: + * + * - accept mbox (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); in netconn_accept()) + * - receive mbox (sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); in netconn_recv_data()) + * - send queue is full (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0); in lwip_netconn_do_write()) + * + * The events have to be seen as events signaling the state of these mboxes/semaphores. For non-blocking + * connections, you need to know in advance whether a call to a netconn function call would block or not, + * and these events tell you about that. + * + * RCVPLUS events say: Safe to perform a potentially blocking call call once more. + * They are counted in sockets - three RCVPLUS events for accept mbox means you are safe + * to call netconn_accept 3 times without being blocked. + * Same thing for receive mbox. + * + * RCVMINUS events say: Your call to to a possibly blocking function is "acknowledged". + * Socket implementation decrements the counter. + * + * For TX, there is no need to count, its merely a flag. SENDPLUS means you may send something. + * SENDPLUS occurs when enough data was delivered to peer so netconn_send() can be called again. + * A SENDMINUS event occurs when the next call to a netconn_send() would be blocking. + */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +/* Used for netconn_gethostbyname_addrtype(), these should match the DNS_ADDRTYPE defines in dns.h */ +#define NETCONN_DNS_DEFAULT NETCONN_DNS_IPV4_IPV6 +#define NETCONN_DNS_IPV4 0 +#define NETCONN_DNS_IPV6 1 +#define NETCONN_DNS_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define NETCONN_DNS_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#endif /* LWIP_DNS */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last error this netconn had */ + err_t last_err; +#if !LWIP_NETCONN_SEM_PER_THREAD + /** sem that is used to synchronously execute functions in the core context */ + sys_sem_t op_completed; +#endif + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_SNDTIMEO + /** timeout to wait for sending data (which means enqueueing data for sending + in internal buffers) in milliseconds */ + s32_t send_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVTIMEO + /** timeout in milliseconds to wait for new data to be received + (or connections to arrive for listening netconns) */ + int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + int recv_avail; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_SO_LINGER + /** values <0 mean linger is disabled, values > 0 are seconds to linger */ + s16_t linger; +#endif /* LWIP_SO_LINGER */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores how much is already sent. */ + size_t write_offset; + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { if ((conn) != NULL) { \ + SYS_ARCH_DECL_PROTECT(netconn_set_safe_err_lev); \ + SYS_ARCH_PROTECT(netconn_set_safe_err_lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(netconn_set_safe_err_lev); \ +}} while(0); + +/* Network connection functions: */ + +/** @ingroup netconn_common + * Create new netconn connection + * @param t @ref netconn_type */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +/** @ingroup netconn_common */ +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +/** @ingroup netconn_common */ +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +/** @ingroup netconn_tcp */ +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + const ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written); +/** @ingroup netconn_tcp */ +#define netconn_write(conn, dataptr, size, apiflags) \ + netconn_write_partly(conn, dataptr, size, apiflags, NULL) +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +err_t netconn_join_leave_group(struct netconn *conn, const ip_addr_t *multiaddr, + const ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if LWIP_DNS +#if LWIP_IPV4 && LWIP_IPV6 +err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); +#define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) +#else /* LWIP_IPV4 && LWIP_IPV6 */ +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#define netconn_gethostbyname_addrtype(name, addr, dns_addrtype) netconn_gethostbyname(name, addr) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#endif /* LWIP_DNS */ + +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +#if LWIP_IPV6 +/** @ingroup netconn_common + * TCP: Set the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_set_ipv6only(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_IPV6_V6ONLY; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_IPV6_V6ONLY; }} while(0) +/** @ingroup netconn_common + * TCP: Get the IPv6 ONLY status of netconn calls (see NETCONN_FLAG_IPV6_V6ONLY) + */ +#define netconn_get_ipv6only(conn) (((conn)->flags & NETCONN_FLAG_IPV6_V6ONLY) != 0) +#endif /* LWIP_IPV6 */ + +#if LWIP_SO_SNDTIMEO +/** Set the send timeout in milliseconds */ +#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) +/** Get the send timeout in milliseconds */ +#define netconn_get_sendtimeout(conn) ((conn)->send_timeout) +#endif /* LWIP_SO_SNDTIMEO */ +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#if LWIP_NETCONN_SEM_PER_THREAD +void netconn_thread_init(void); +void netconn_thread_cleanup(void); +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define netconn_thread_init() +#define netconn_thread_cleanup() +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_API_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/FILES b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/FILES new file mode 100644 index 0000000000..adfc0f3345 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/FILES @@ -0,0 +1,2 @@ +This directory contains application headers. +Every application shall provide one api file APP.h and optionally one options file APP_opts.h diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/fs.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/fs.h new file mode 100644 index 0000000000..bb176fa010 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/fs.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_APPS_FS_H +#define LWIP_HDR_APPS_FS_H + +#include "httpd_opts.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FS_READ_EOF -1 +#define FS_READ_DELAYED -2 + +#if HTTPD_PRECALCULATED_CHECKSUM +struct fsdata_chksum { + u32_t offset; + u16_t chksum; + u16_t len; +}; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + +#define FS_FILE_FLAGS_HEADER_INCLUDED 0x01 +#define FS_FILE_FLAGS_HEADER_PERSISTENT 0x02 + +struct fs_file { + const char *data; + int len; + int index; + void *pextension; +#if HTTPD_PRECALCULATED_CHECKSUM + const struct fsdata_chksum *chksum; + u16_t chksum_count; +#endif /* HTTPD_PRECALCULATED_CHECKSUM */ + u8_t flags; +#if LWIP_HTTPD_CUSTOM_FILES + u8_t is_custom_file; +#endif /* LWIP_HTTPD_CUSTOM_FILES */ +#if LWIP_HTTPD_FILE_STATE + void *state; +#endif /* LWIP_HTTPD_FILE_STATE */ +}; + +#if LWIP_HTTPD_FS_ASYNC_READ +typedef void (*fs_wait_cb)(void *arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ + +err_t fs_open(struct fs_file *file, const char *name); +void fs_close(struct fs_file *file); +#if LWIP_HTTPD_DYNAMIC_FILE_READ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); +#else /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_read(struct fs_file *file, char *buffer, int count); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +#endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ +#if LWIP_HTTPD_FS_ASYNC_READ +int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); +#endif /* LWIP_HTTPD_FS_ASYNC_READ */ +int fs_bytes_left(struct fs_file *file); + +#if LWIP_HTTPD_FILE_STATE +/** This user-defined function is called when a file is opened. */ +void *fs_state_init(struct fs_file *file, const char *name); +/** This user-defined function is called when a file is closed. */ +void fs_state_free(struct fs_file *file, void *state); +#endif /* #if LWIP_HTTPD_FILE_STATE */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_FS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd.h new file mode 100644 index 0000000000..40f1811e57 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd.h @@ -0,0 +1,236 @@ +/** + * @file + * HTTP server + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_H +#define LWIP_HDR_APPS_HTTPD_H + +#include "httpd_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_HTTPD_CGI + +/* + * Function pointer for a CGI script handler. + * + * This function is called each time the HTTPD server is asked for a file + * whose name was previously registered as a CGI function using a call to + * http_set_cgi_handler. The iIndex parameter provides the index of the + * CGI within the ppcURLs array passed to http_set_cgi_handler. Parameters + * pcParam and pcValue provide access to the parameters provided along with + * the URI. iNumParams provides a count of the entries in the pcParam and + * pcValue arrays. Each entry in the pcParam array contains the name of a + * parameter with the corresponding entry in the pcValue array containing the + * value for that parameter. Note that pcParam may contain multiple elements + * with the same name if, for example, a multi-selection list control is used + * in the form generating the data. + * + * The function should return a pointer to a character string which is the + * path and filename of the response that is to be sent to the connected + * browser, for example "/thanks.htm" or "/response/error.ssi". + * + * The maximum number of parameters that will be passed to this function via + * iNumParams is defined by LWIP_HTTPD_MAX_CGI_PARAMETERS. Any parameters in the incoming + * HTTP request above this number will be discarded. + * + * Requests intended for use by this CGI mechanism must be sent using the GET + * method (which encodes all parameters within the URI rather than in a block + * later in the request). Attempts to use the POST method will result in the + * request being ignored. + * + */ +typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], + char *pcValue[]); + +/* + * Structure defining the base filename (URL) of a CGI and the associated + * function which is to be called when that URL is requested. + */ +typedef struct +{ + const char *pcCGIName; + tCGIHandler pfnCGIHandler; +} tCGI; + +void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); + +#endif /* LWIP_HTTPD_CGI */ + +#if LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI + +#if LWIP_HTTPD_CGI_SSI +/** Define this generic CGI handler in your application. + * It is called once for every URI with parameters. + * The parameters can be stored to + */ +extern void httpd_cgi_handler(const char* uri, int iNumParams, char **pcParam, char **pcValue +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); +#endif /* LWIP_HTTPD_CGI_SSI */ + +#endif /* LWIP_HTTPD_CGI || LWIP_HTTPD_CGI_SSI */ + +#if LWIP_HTTPD_SSI + +/* + * Function pointer for the SSI tag handler callback. + * + * This function will be called each time the HTTPD server detects a tag of the + * form in a .shtml, .ssi or .shtm file where "name" appears as + * one of the tags supplied to http_set_ssi_handler in the ppcTags array. The + * returned insert string, which will be appended after the the string + * "" in file sent back to the client,should be written to pointer + * pcInsert. iInsertLen contains the size of the buffer pointed to by + * pcInsert. The iIndex parameter provides the zero-based index of the tag as + * found in the ppcTags array and identifies the tag that is to be processed. + * + * The handler returns the number of characters written to pcInsert excluding + * any terminating NULL or a negative number to indicate a failure (tag not + * recognized, for example). + * + * Note that the behavior of this SSI mechanism is somewhat different from the + * "normal" SSI processing as found in, for example, the Apache web server. In + * this case, the inserted text is appended following the SSI tag rather than + * replacing the tag entirely. This allows for an implementation that does not + * require significant additional buffering of output data yet which will still + * offer usable SSI functionality. One downside to this approach is when + * attempting to use SSI within JavaScript. The SSI tag is structured to + * resemble an HTML comment but this syntax does not constitute a comment + * within JavaScript and, hence, leaving the tag in place will result in + * problems in these cases. To work around this, any SSI tag which needs to + * output JavaScript code must do so in an encapsulated way, sending the whole + * HTML section as a single include. + */ +typedef u16_t (*tSSIHandler)( +#if LWIP_HTTPD_SSI_RAW + const char* ssi_tag_name, +#else /* LWIP_HTTPD_SSI_RAW */ + int iIndex, +#endif /* LWIP_HTTPD_SSI_RAW */ + char *pcInsert, int iInsertLen +#if LWIP_HTTPD_SSI_MULTIPART + , u16_t current_tag_part, u16_t *next_tag_part +#endif /* LWIP_HTTPD_SSI_MULTIPART */ +#if defined(LWIP_HTTPD_FILE_STATE) && LWIP_HTTPD_FILE_STATE + , void *connection_state +#endif /* LWIP_HTTPD_FILE_STATE */ + ); + +/** Set the SSI handler function + * (if LWIP_HTTPD_SSI_RAW==1, only the first argument is used) + */ +void http_set_ssi_handler(tSSIHandler pfnSSIHandler, + const char **ppcTags, int iNumTags); + +/** For LWIP_HTTPD_SSI_RAW==1, return this to indicate the tag is unknown. + * In this case, the webserver writes a warning into the page. + * You can also just return 0 to write nothing for unknown tags. + */ +#define HTTPD_SSI_TAG_UNKNOWN 0xFFFF + +#endif /* LWIP_HTTPD_SSI */ + +#if LWIP_HTTPD_SUPPORT_POST + +/* These functions must be implemented by the application */ + +/** Called when a POST request has been received. The application can decide + * whether to accept it or not. + * + * @param connection Unique connection identifier, valid until httpd_post_end + * is called. + * @param uri The HTTP header URI receiving the POST request. + * @param http_request The raw HTTP request (the first packet, normally). + * @param http_request_len Size of 'http_request'. + * @param content_len Content-Length from HTTP header. + * @param response_uri Filename of response file, to be filled when denying the + * request + * @param response_uri_len Size of the 'response_uri' buffer. + * @param post_auto_wnd Set this to 0 to let the callback code handle window + * updates by calling 'httpd_post_data_recved' (to throttle rx speed) + * default is 1 (httpd handles window updates automatically) + * @return ERR_OK: Accept the POST request, data may be passed in + * another err_t: Deny the POST request, send back 'bad request'. + */ +err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, + u16_t http_request_len, int content_len, char *response_uri, + u16_t response_uri_len, u8_t *post_auto_wnd); + +/** Called for each pbuf of data that has been received for a POST. + * ATTENTION: The application is responsible for freeing the pbufs passed in! + * + * @param connection Unique connection identifier. + * @param p Received data. + * @return ERR_OK: Data accepted. + * another err_t: Data denied, http_post_get_response_uri will be called. + */ +err_t httpd_post_receive_data(void *connection, struct pbuf *p); + +/** Called when all data is received or when the connection is closed. + * The application must return the filename/URI of a file to send in response + * to this POST request. If the response_uri buffer is untouched, a 404 + * response is returned. + * + * @param connection Unique connection identifier. + * @param response_uri Filename of response file, to be filled when denying the request + * @param response_uri_len Size of the 'response_uri' buffer. + */ +void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); + +#if LWIP_HTTPD_POST_MANUAL_WND +void httpd_post_data_recved(void *connection, u16_t recved_len); +#endif /* LWIP_HTTPD_POST_MANUAL_WND */ + +#endif /* LWIP_HTTPD_SUPPORT_POST */ + +void httpd_init(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HTTPD_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd_opts.h new file mode 100644 index 0000000000..340db15f66 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/httpd_opts.h @@ -0,0 +1,323 @@ +/** + * @file + * HTTP server options list + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + * This version of the file has been modified by Texas Instruments to offer + * simple server-side-include (SSI) and Common Gateway Interface (CGI) + * capability. + */ + +#ifndef LWIP_HDR_APPS_HTTPD_OPTS_H +#define LWIP_HDR_APPS_HTTPD_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup httpd_opts Options + * @ingroup httpd + * @{ + */ + +/** Set this to 1 to support CGI (old style) */ +#if !defined LWIP_HTTPD_CGI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI 0 +#endif + +/** Set this to 1 to support CGI (new style) */ +#if !defined LWIP_HTTPD_CGI_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_CGI_SSI 0 +#endif + +/** Set this to 1 to support SSI (Server-Side-Includes) */ +#if !defined LWIP_HTTPD_SSI || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI 0 +#endif + +/** Set this to 1 to implement an SSI tag handler callback that gets a const char* + * to the tag (instead of an index into a pre-registered array of known tags) */ +#if !defined LWIP_HTTPD_SSI_RAW || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_RAW 0 +#endif + +/** Set this to 1 to support HTTP POST */ +#if !defined LWIP_HTTPD_SUPPORT_POST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_POST 0 +#endif + +/* The maximum number of parameters that the CGI handler can be sent. */ +#if !defined LWIP_HTTPD_MAX_CGI_PARAMETERS || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 +#endif + +/** LWIP_HTTPD_SSI_MULTIPART==1: SSI handler function is called with 2 more + * arguments indicating a counter for insert string that are too long to be + * inserted at once: the SSI handler function must then set 'next_tag_part' + * which will be passed back to it in the next call. */ +#if !defined LWIP_HTTPD_SSI_MULTIPART || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_MULTIPART 0 +#endif + +/* The maximum length of the string comprising the tag name */ +#if !defined LWIP_HTTPD_MAX_TAG_NAME_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 +#endif + +/* The maximum length of string that can be returned to replace any given tag */ +#if !defined LWIP_HTTPD_MAX_TAG_INSERT_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 +#endif + +#if !defined LWIP_HTTPD_POST_MANUAL_WND || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MANUAL_WND 0 +#endif + +/** This string is passed in the HTTP header as "Server: " */ +#if !defined HTTPD_SERVER_AGENT || defined __DOXYGEN__ +#define HTTPD_SERVER_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)" +#endif + +/** Set this to 1 if you want to include code that creates HTTP headers + * at runtime. Default is off: HTTP headers are then created statically + * by the makefsdata tool. Static headers mean smaller code size, but + * the (readonly) fsdata will grow a bit as every file includes the HTTP + * header. */ +#if !defined LWIP_HTTPD_DYNAMIC_HEADERS || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_HEADERS 0 +#endif + +#if !defined HTTPD_DEBUG || defined __DOXYGEN__ +#define HTTPD_DEBUG LWIP_DBG_OFF +#endif + +/** Set this to 1 to use a memp pool for allocating + * struct http_state instead of the heap. + */ +#if !defined HTTPD_USE_MEM_POOL || defined __DOXYGEN__ +#define HTTPD_USE_MEM_POOL 0 +#endif + +/** The server port for HTTPD to use */ +#if !defined HTTPD_SERVER_PORT || defined __DOXYGEN__ +#define HTTPD_SERVER_PORT 80 +#endif + +/** Maximum retries before the connection is aborted/closed. + * - number of times pcb->poll is called -> default is 4*500ms = 2s; + * - reset when pcb->sent is called + */ +#if !defined HTTPD_MAX_RETRIES || defined __DOXYGEN__ +#define HTTPD_MAX_RETRIES 4 +#endif + +/** The poll delay is X*500ms */ +#if !defined HTTPD_POLL_INTERVAL || defined __DOXYGEN__ +#define HTTPD_POLL_INTERVAL 4 +#endif + +/** Priority for tcp pcbs created by HTTPD (very low by default). + * Lower priorities get killed first when running out of memory. + */ +#if !defined HTTPD_TCP_PRIO || defined __DOXYGEN__ +#define HTTPD_TCP_PRIO TCP_PRIO_MIN +#endif + +/** Set this to 1 to enable timing each file sent */ +#if !defined LWIP_HTTPD_TIMING || defined __DOXYGEN__ +#define LWIP_HTTPD_TIMING 0 +#endif +/** Set this to 1 to enable timing each file sent */ +#if !defined HTTPD_DEBUG_TIMING || defined __DOXYGEN__ +#define HTTPD_DEBUG_TIMING LWIP_DBG_OFF +#endif + +/** Set this to one to show error pages when parsing a request fails instead + of simply closing the connection. */ +#if !defined LWIP_HTTPD_SUPPORT_EXTSTATUS || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_EXTSTATUS 0 +#endif + +/** Set this to 0 to drop support for HTTP/0.9 clients (to save some bytes) */ +#if !defined LWIP_HTTPD_SUPPORT_V09 || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_V09 1 +#endif + +/** Set this to 1 to enable HTTP/1.1 persistent connections. + * ATTENTION: If the generated file system includes HTTP headers, these must + * include the "Connection: keep-alive" header (pass argument "-11" to makefsdata). + */ +#if !defined LWIP_HTTPD_SUPPORT_11_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_11_KEEPALIVE 0 +#endif + +/** Set this to 1 to support HTTP request coming in in multiple packets/pbufs */ +#if !defined LWIP_HTTPD_SUPPORT_REQUESTLIST || defined __DOXYGEN__ +#define LWIP_HTTPD_SUPPORT_REQUESTLIST 1 +#endif + +#if LWIP_HTTPD_SUPPORT_REQUESTLIST +/** Number of rx pbufs to enqueue to parse an incoming request (up to the first + newline) */ +#if !defined LWIP_HTTPD_REQ_QUEUELEN || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_QUEUELEN 5 +#endif + +/** Number of (TCP payload-) bytes (in pbufs) to enqueue to parse and incoming + request (up to the first double-newline) */ +#if !defined LWIP_HTTPD_REQ_BUFSIZE || defined __DOXYGEN__ +#define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH +#endif + +/** Defines the maximum length of a HTTP request line (up to the first CRLF, + copied from pbuf into this a global buffer when pbuf- or packet-queues + are received - otherwise the input pbuf is used directly) */ +#if !defined LWIP_HTTPD_MAX_REQ_LENGTH || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQ_LENGTH LWIP_MIN(1023, (LWIP_HTTPD_REQ_QUEUELEN * PBUF_POOL_BUFSIZE)) +#endif +#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ + +/** This is the size of a static buffer used when URIs end with '/'. + * In this buffer, the directory requested is concatenated with all the + * configured default file names. + * Set to 0 to disable checking default filenames on non-root directories. + */ +#if !defined LWIP_HTTPD_MAX_REQUEST_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_MAX_REQUEST_URI_LEN 63 +#endif + +/** Maximum length of the filename to send as response to a POST request, + * filled in by the application when a POST is finished. + */ +#if !defined LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63 +#endif + +/** Set this to 0 to not send the SSI tag (default is on, so the tag will + * be sent in the HTML page */ +#if !defined LWIP_HTTPD_SSI_INCLUDE_TAG || defined __DOXYGEN__ +#define LWIP_HTTPD_SSI_INCLUDE_TAG 1 +#endif + +/** Set this to 1 to call tcp_abort when tcp_close fails with memory error. + * This can be used to prevent consuming all memory in situations where the + * HTTP server has low priority compared to other communication. */ +#if !defined LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR || defined __DOXYGEN__ +#define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0 +#endif + +/** Set this to 1 to kill the oldest connection when running out of + * memory for 'struct http_state' or 'struct http_ssi_state'. + * ATTENTION: This puts all connections on a linked list, so may be kind of slow. + */ +#if !defined LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED || defined __DOXYGEN__ +#define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 +#endif + +/** Set this to 1 to send URIs without extension without headers + * (who uses this at all??) */ +#if !defined LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI || defined __DOXYGEN__ +#define LWIP_HTTPD_OMIT_HEADER_FOR_EXTENSIONLESS_URI 0 +#endif + +/** Default: Tags are sent from struct http_state and are therefore volatile */ +#if !defined HTTP_IS_TAG_VOLATILE || defined __DOXYGEN__ +#define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY +#endif + +/* By default, the httpd is limited to send 2*pcb->mss to keep resource usage low + when http is not an important protocol in the device. */ +#if !defined HTTPD_LIMIT_SENDING_TO_2MSS || defined __DOXYGEN__ +#define HTTPD_LIMIT_SENDING_TO_2MSS 1 +#endif + +/* Define this to a function that returns the maximum amount of data to enqueue. + The function have this signature: u16_t fn(struct tcp_pcb* pcb); */ +#if !defined HTTPD_MAX_WRITE_LEN || defined __DOXYGEN__ +#if HTTPD_LIMIT_SENDING_TO_2MSS +#define HTTPD_MAX_WRITE_LEN(pcb) (2 * tcp_mss(pcb)) +#endif +#endif + +/*------------------- FS OPTIONS -------------------*/ + +/** Set this to 1 and provide the functions: + * - "int fs_open_custom(struct fs_file *file, const char *name)" + * Called first for every opened file to allow opening files + * that are not included in fsdata(_custom).c + * - "void fs_close_custom(struct fs_file *file)" + * Called to free resources allocated by fs_open_custom(). + */ +#if !defined LWIP_HTTPD_CUSTOM_FILES || defined __DOXYGEN__ +#define LWIP_HTTPD_CUSTOM_FILES 0 +#endif + +/** Set this to 1 to support fs_read() to dynamically read file data. + * Without this (default=off), only one-block files are supported, + * and the contents must be ready after fs_open(). + */ +#if !defined LWIP_HTTPD_DYNAMIC_FILE_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_DYNAMIC_FILE_READ 0 +#endif + +/** Set this to 1 to include an application state argument per file + * that is opened. This allows to keep a state per connection/file. + */ +#if !defined LWIP_HTTPD_FILE_STATE || defined __DOXYGEN__ +#define LWIP_HTTPD_FILE_STATE 0 +#endif + +/** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for + * predefined (MSS-sized) chunks of the files to prevent having to calculate + * the checksums at runtime. */ +#if !defined HTTPD_PRECALCULATED_CHECKSUM || defined __DOXYGEN__ +#define HTTPD_PRECALCULATED_CHECKSUM 0 +#endif + +/** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations + * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). + */ +#if !defined LWIP_HTTPD_FS_ASYNC_READ || defined __DOXYGEN__ +#define LWIP_HTTPD_FS_ASYNC_READ 0 +#endif + +/** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the + * file system (to prevent changing the file included in CVS) */ +#if !defined HTTPD_USE_CUSTOM_FSDATA || defined __DOXYGEN__ +#define HTTPD_USE_CUSTOM_FSDATA 0 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_HTTPD_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/lwiperf.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/lwiperf.h new file mode 100644 index 0000000000..7dbebb0826 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/lwiperf.h @@ -0,0 +1,84 @@ +/** + * @file + * lwIP iPerf server implementation + */ + +/* + * Copyright (c) 2014 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_LWIPERF_H +#define LWIP_HDR_APPS_LWIPERF_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIPERF_TCP_PORT_DEFAULT 5001 + +/** lwIPerf test results */ +enum lwiperf_report_type +{ + /** The server side test is done */ + LWIPERF_TCP_DONE_SERVER, + /** The client side test is done */ + LWIPERF_TCP_DONE_CLIENT, + /** Local error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL, + /** Data check error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, + /** Transmit error lead to test abort */ + LWIPERF_TCP_ABORTED_LOCAL_TXERROR, + /** Remote side aborted the test */ + LWIPERF_TCP_ABORTED_REMOTE +}; + +/** Prototype of a report function that is called when a session is finished. + This report function can show the test results. + @param report_type contains the test result */ +typedef void (*lwiperf_report_fn)(void *arg, enum lwiperf_report_type report_type, + const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port, + u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec); + + +void* lwiperf_start_tcp_server(const ip_addr_t* local_addr, u16_t local_port, + lwiperf_report_fn report_fn, void* report_arg); +void* lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void* report_arg); +void lwiperf_abort(void* lwiperf_session); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_LWIPERF_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns.h new file mode 100644 index 0000000000..d036816115 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns.h @@ -0,0 +1,69 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ +#ifndef LWIP_HDR_MDNS_H +#define LWIP_HDR_MDNS_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/netif.h" + +#if LWIP_MDNS_RESPONDER + +enum mdns_sd_proto { + DNSSD_PROTO_UDP = 0, + DNSSD_PROTO_TCP = 1 +}; + +#define MDNS_LABEL_MAXLEN 63 + +struct mdns_host; +struct mdns_service; + +/** Callback function to add text to a reply, called when generating the reply */ +typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata); + +void mdns_resp_init(void); + +err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl); +err_t mdns_resp_remove_netif(struct netif *netif); + +err_t mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata); +err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len); +void mdns_resp_netif_settings_changed(struct netif *netif); + +#endif /* LWIP_MDNS_RESPONDER */ + +#endif /* LWIP_HDR_MDNS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_opts.h new file mode 100644 index 0000000000..bf186bcce1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_opts.h @@ -0,0 +1,74 @@ +/** + * @file + * MDNS responder + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#ifndef LWIP_HDR_APPS_MDNS_OPTS_H +#define LWIP_HDR_APPS_MDNS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup mdns_opts Options + * @ingroup mdns + * @{ + */ + +/** + * LWIP_MDNS_RESPONDER==1: Turn on multicast DNS module. UDP must be available for MDNS + * transport. IGMP is needed for IPv4 multicast. + */ +#ifndef LWIP_MDNS_RESPONDER +#define LWIP_MDNS_RESPONDER 0 +#endif /* LWIP_MDNS_RESPONDER */ + +/** The maximum number of services per netif */ +#ifndef MDNS_MAX_SERVICES +#define MDNS_MAX_SERVICES 1 +#endif + +/** + * MDNS_DEBUG: Enable debugging for multicast DNS. + */ +#ifndef MDNS_DEBUG +#define MDNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_MDNS_OPTS_H */ + diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_priv.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_priv.h new file mode 100644 index 0000000000..8ee6db86af --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mdns_priv.h @@ -0,0 +1,66 @@ +/** + * @file + * MDNS responder private definitions + */ + + /* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ +#ifndef LWIP_HDR_MDNS_PRIV_H +#define LWIP_HDR_MDNS_PRIV_H + +#include "lwip/apps/mdns_opts.h" +#include "lwip/pbuf.h" + +#if LWIP_MDNS_RESPONDER + +/* Domain struct and methods - visible for unit tests */ + +#define MDNS_DOMAIN_MAXLEN 256 +#define MDNS_READNAME_ERROR 0xFFFF + +struct mdns_domain { + /* Encoded domain name */ + u8_t name[MDNS_DOMAIN_MAXLEN]; + /* Total length of domain name, including zero */ + u16_t length; + /* Set if compression of this domain is not allowed */ + u8_t skip_compression; +}; + +err_t mdns_domain_add_label(struct mdns_domain *domain, const char *label, u8_t len); +u16_t mdns_readname(struct pbuf *p, u16_t offset, struct mdns_domain *domain); +int mdns_domain_eq(struct mdns_domain *a, struct mdns_domain *b); +u16_t mdns_compress_domain(struct pbuf *pbuf, u16_t *offset, struct mdns_domain *domain); + +#endif /* LWIP_MDNS_RESPONDER */ + +#endif /* LWIP_HDR_MDNS_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt.h new file mode 100644 index 0000000000..34b230b888 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt.h @@ -0,0 +1,244 @@ +/** + * @file + * MQTT client + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H +#define LWIP_HDR_APPS_MQTT_CLIENT_H + +#include "lwip/apps/mqtt_opts.h" +#include "lwip/err.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mqtt_client_t mqtt_client_t; + +/** @ingroup mqtt + * Default MQTT port */ +#define MQTT_PORT 1883 + +/*---------------------------------------------------------------------------------------------- */ +/* Connection with server */ + +/** + * @ingroup mqtt + * Client information and connection parameters */ +struct mqtt_connect_client_info_t { + /** Client identifier, must be set by caller */ + const char *client_id; + /** User name and password, set to NULL if not used */ + const char* client_user; + const char* client_pass; + /** keep alive time in seconds, 0 to disable keep alive functionality*/ + u16_t keep_alive; + /** will topic, set to NULL if will is not to be used, + will_msg, will_qos and will retain are then ignored */ + const char* will_topic; + const char* will_msg; + u8_t will_qos; + u8_t will_retain; +}; + +/** + * @ingroup mqtt + * Connection status codes */ +typedef enum +{ + MQTT_CONNECT_ACCEPTED = 0, + MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1, + MQTT_CONNECT_REFUSED_IDENTIFIER = 2, + MQTT_CONNECT_REFUSED_SERVER = 3, + MQTT_CONNECT_REFUSED_USERNAME_PASS = 4, + MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_ = 5, + MQTT_CONNECT_DISCONNECTED = 256, + MQTT_CONNECT_TIMEOUT = 257 +} mqtt_connection_status_t; + +/** + * @ingroup mqtt + * Function prototype for mqtt connection status callback. Called when + * client has connected to the server after initiating a mqtt connection attempt by + * calling mqtt_connect() or when connection is closed by server or an error + * + * @param client MQTT client itself + * @param arg Additional argument to pass to the callback function + * @param status Connect result code or disconnection notification @see mqtt_connection_status_t + * + */ +typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status); + + +/** + * @ingroup mqtt + * Data callback flags */ +enum { + /** Flag set when last fragment of data arrives in data callback */ + MQTT_DATA_FLAG_LAST = 1 +}; + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish data callback function. Called when data + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param data User data, pointed object, data may not be referenced after callback return, + NULL is passed when all publish data are delivered + * @param len Length of publish data fragment + * @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message + * + */ +typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags); + + +/** + * @ingroup mqtt + * Function prototype for MQTT incoming publish function. Called when an incoming publish + * arrives to a subscribed topic @see mqtt_subscribe + * + * @param arg Additional argument to pass to the callback function + * @param topic Zero terminated Topic text string, topic may not be referenced after callback return + * @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked + */ +typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len); + + +/** + * @ingroup mqtt + * Function prototype for mqtt request callback. Called when a subscribe, unsubscribe + * or publish request has completed + * @param arg Pointer to user data supplied when invoking request + * @param err ERR_OK on success + * ERR_TIMEOUT if no response was received within timeout, + * ERR_ABRT if (un)subscribe was denied + */ +typedef void (*mqtt_request_cb_t)(void *arg, err_t err); + + +/** + * Pending request item, binds application callback to pending server requests + */ +struct mqtt_request_t +{ + /** Next item in list, NULL means this is the last in chain, + next pointing at itself means request is unallocated */ + struct mqtt_request_t *next; + /** Callback to upper layer */ + mqtt_request_cb_t cb; + void *arg; + /** MQTT packet identifier */ + u16_t pkt_id; + /** Expire time relative to element before this */ + u16_t timeout_diff; +}; + +/** Ring buffer */ +struct mqtt_ringbuf_t { + u16_t put; + u16_t get; + u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE]; +}; + +/** MQTT client */ +struct mqtt_client_t +{ + /** Timers and timeouts */ + u16_t cyclic_tick; + u16_t keep_alive; + u16_t server_watchdog; + /** Packet identifier generator*/ + u16_t pkt_id_seq; + /** Packet identifier of pending incoming publish */ + u16_t inpub_pkt_id; + /** Connection state */ + u8_t conn_state; + struct tcp_pcb *conn; + /** Connection callback */ + void *connect_arg; + mqtt_connection_cb_t connect_cb; + /** Pending requests to server */ + struct mqtt_request_t *pend_req_queue; + struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT]; + void *inpub_arg; + /** Incoming data callback */ + mqtt_incoming_data_cb_t data_cb; + mqtt_incoming_publish_cb_t pub_cb; + /** Input */ + u32_t msg_idx; + u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN]; + /** Output ring-buffer */ + struct mqtt_ringbuf_t output; +}; + + +/** Connect to server */ +err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg, + const struct mqtt_connect_client_info_t *client_info); + +/** Disconnect from server */ +void mqtt_disconnect(mqtt_client_t *client); + +/** Create new client */ +mqtt_client_t *mqtt_client_new(void); + +/** Check connection status */ +u8_t mqtt_client_is_connected(mqtt_client_t *client); + +/** Set callback to call for incoming publish */ +void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t, + mqtt_incoming_data_cb_t data_cb, void *arg); + +/** Common function for subscribe and unsubscribe */ +err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub); + +/** @ingroup mqtt + *Subscribe to topic */ +#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1) +/** @ingroup mqtt + * Unsubscribe to topic */ +#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0) + + +/** Publish data to topic */ +err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain, + mqtt_request_cb_t cb, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt_opts.h new file mode 100644 index 0000000000..ffefacd259 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/mqtt_opts.h @@ -0,0 +1,103 @@ +/** + * @file + * MQTT client options + */ + +/* + * Copyright (c) 2016 Erik Andersson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Andersson + * + */ +#ifndef LWIP_HDR_APPS_MQTT_OPTS_H +#define LWIP_HDR_APPS_MQTT_OPTS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mqtt_opts Options + * @ingroup mqtt + * @{ + */ + +/** + * Output ring-buffer size, must be able to fit largest outgoing publish message topic+payloads + */ +#ifndef MQTT_OUTPUT_RINGBUF_SIZE +#define MQTT_OUTPUT_RINGBUF_SIZE 256 +#endif + +/** + * Number of bytes in receive buffer, must be at least the size of the longest incoming topic + 8 + * If one wants to avoid fragmented incoming publish, set length to max incoming topic length + max payload length + 8 + */ +#ifndef MQTT_VAR_HEADER_BUFFER_LEN +#define MQTT_VAR_HEADER_BUFFER_LEN 128 +#endif + +/** + * Maximum number of pending subscribe, unsubscribe and publish requests to server . + */ +#ifndef MQTT_REQ_MAX_IN_FLIGHT +#define MQTT_REQ_MAX_IN_FLIGHT 4 +#endif + +/** + * Seconds between each cyclic timer call. + */ +#ifndef MQTT_CYCLIC_TIMER_INTERVAL +#define MQTT_CYCLIC_TIMER_INTERVAL 5 +#endif + +/** + * Publish, subscribe and unsubscribe request timeout in seconds. + */ +#ifndef MQTT_REQ_TIMEOUT +#define MQTT_REQ_TIMEOUT 30 +#endif + +/** + * Seconds for MQTT connect response timeout after sending connect request + */ +#ifndef MQTT_CONNECT_TIMOUT +#define MQTT_CONNECT_TIMOUT 100 +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_MQTT_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns.h new file mode 100644 index 0000000000..c9f68d8d12 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns.h @@ -0,0 +1,43 @@ +/** + * @file + * NETBIOS name service responder + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_H +#define LWIP_HDR_APPS_NETBIOS_H + +#include "lwip/apps/netbiosns_opts.h" + +void netbiosns_init(void); +#ifndef NETBIOS_LWIP_NAME +void netbiosns_set_name(const char* hostname); +#endif +void netbiosns_stop(void); + +#endif /* LWIP_HDR_APPS_NETBIOS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns_opts.h new file mode 100644 index 0000000000..0909ef7b94 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/netbiosns_opts.h @@ -0,0 +1,59 @@ +/** + * @file + * NETBIOS name service responder options + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_APPS_NETBIOS_OPTS_H +#define LWIP_HDR_APPS_NETBIOS_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup netbiosns_opts Options + * @ingroup netbiosns + * @{ + */ + +/** NetBIOS name of lwip device + * This must be uppercase until NETBIOS_STRCMP() is defined to a string + * comparision function that is case insensitive. + * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): + * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") + * + * If this is not defined, netbiosns_set_name() can be called at runtime to change the name. + */ +#ifdef __DOXYGEN__ +#define NETBIOS_LWIP_NAME "NETBIOSLWIPDEV" +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_NETBIOS_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp.h new file mode 100644 index 0000000000..10e8ff434b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp.h @@ -0,0 +1,128 @@ +/** + * @file + * SNMP server main API - start and basic configuration + */ + +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * Martin Hentschel + * + */ +#ifndef LWIP_HDR_APPS_SNMP_H +#define LWIP_HDR_APPS_SNMP_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/apps/snmp_core.h" + +/** SNMP variable binding descriptor (publically needed for traps) */ +struct snmp_varbind +{ + /** pointer to next varbind, NULL for last in list */ + struct snmp_varbind *next; + /** pointer to previous varbind, NULL for first in list */ + struct snmp_varbind *prev; + + /** object identifier */ + struct snmp_obj_id oid; + + /** value ASN1 type */ + u8_t type; + /** object value length */ + u16_t value_len; + /** object value */ + void *value; +}; + +/** + * @ingroup snmp_core + * Agent setup, start listening to port 161. + */ +void snmp_init(void); +void snmp_set_mibs(const struct snmp_mib **mibs, u8_t num_mibs); + +void snmp_set_device_enterprise_oid(const struct snmp_obj_id* device_enterprise_oid); +const struct snmp_obj_id* snmp_get_device_enterprise_oid(void); + +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst); + +/** Generic trap: cold start */ +#define SNMP_GENTRAP_COLDSTART 0 +/** Generic trap: warm start */ +#define SNMP_GENTRAP_WARMSTART 1 +/** Generic trap: link down */ +#define SNMP_GENTRAP_LINKDOWN 2 +/** Generic trap: link up */ +#define SNMP_GENTRAP_LINKUP 3 +/** Generic trap: authentication failure */ +#define SNMP_GENTRAP_AUTH_FAILURE 4 +/** Generic trap: EGP neighbor lost */ +#define SNMP_GENTRAP_EGP_NEIGHBOR_LOSS 5 +/** Generic trap: enterprise specific */ +#define SNMP_GENTRAP_ENTERPRISE_SPECIFIC 6 + +err_t snmp_send_trap_generic(s32_t generic_trap); +err_t snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds); +err_t snmp_send_trap(const struct snmp_obj_id* oid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds); + +#define SNMP_AUTH_TRAPS_DISABLED 0 +#define SNMP_AUTH_TRAPS_ENABLED 1 +void snmp_set_auth_traps_enabled(u8_t enable); +u8_t snmp_get_auth_traps_enabled(void); + +const char * snmp_get_community(void); +const char * snmp_get_community_write(void); +const char * snmp_get_community_trap(void); +void snmp_set_community(const char * const community); +void snmp_set_community_write(const char * const community); +void snmp_set_community_trap(const char * const community); + +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +typedef void (*snmp_write_callback_fct)(const u32_t* oid, u8_t oid_len, void* callback_arg); +void snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_core.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_core.h new file mode 100644 index 0000000000..e781c532b3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_core.h @@ -0,0 +1,364 @@ +/** + * @file + * SNMP core API for implementing MIBs + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + * Martin Hentschel + */ + +#ifndef LWIP_HDR_APPS_SNMP_CORE_H +#define LWIP_HDR_APPS_SNMP_CORE_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* basic ASN1 defines */ +#define SNMP_ASN1_CLASS_UNIVERSAL 0x00 +#define SNMP_ASN1_CLASS_APPLICATION 0x40 +#define SNMP_ASN1_CLASS_CONTEXT 0x80 +#define SNMP_ASN1_CLASS_PRIVATE 0xC0 + +#define SNMP_ASN1_CONTENTTYPE_PRIMITIVE 0x00 +#define SNMP_ASN1_CONTENTTYPE_CONSTRUCTED 0x20 + +/* universal tags (from ASN.1 spec.) */ +#define SNMP_ASN1_UNIVERSAL_END_OF_CONTENT 0 +#define SNMP_ASN1_UNIVERSAL_INTEGER 2 +#define SNMP_ASN1_UNIVERSAL_OCTET_STRING 4 +#define SNMP_ASN1_UNIVERSAL_NULL 5 +#define SNMP_ASN1_UNIVERSAL_OBJECT_ID 6 +#define SNMP_ASN1_UNIVERSAL_SEQUENCE_OF 16 + +/* application specific (SNMP) tags (from SNMPv2-SMI) */ +#define SNMP_ASN1_APPLICATION_IPADDR 0 /* [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4)) */ +#define SNMP_ASN1_APPLICATION_COUNTER 1 /* [APPLICATION 1] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_GAUGE 2 /* [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_TIMETICKS 3 /* [APPLICATION 3] IMPLICIT INTEGER (0..4294967295) => u32_t */ +#define SNMP_ASN1_APPLICATION_OPAQUE 4 /* [APPLICATION 4] IMPLICIT OCTET STRING */ +#define SNMP_ASN1_APPLICATION_COUNTER64 6 /* [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615) */ + +/* context specific (SNMP) tags (from RFC 1905) */ +#define SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE 1 + +/* full ASN1 type defines */ +#define SNMP_ASN1_TYPE_END_OF_CONTENT (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_END_OF_CONTENT) +#define SNMP_ASN1_TYPE_INTEGER (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_INTEGER) +#define SNMP_ASN1_TYPE_OCTET_STRING (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OCTET_STRING) +#define SNMP_ASN1_TYPE_NULL (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_NULL) +#define SNMP_ASN1_TYPE_OBJECT_ID (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_UNIVERSAL_OBJECT_ID) +#define SNMP_ASN1_TYPE_SEQUENCE (SNMP_ASN1_CLASS_UNIVERSAL | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_UNIVERSAL_SEQUENCE_OF) +#define SNMP_ASN1_TYPE_IPADDR (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_IPADDR) +#define SNMP_ASN1_TYPE_IPADDRESS SNMP_ASN1_TYPE_IPADDR +#define SNMP_ASN1_TYPE_COUNTER (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER) +#define SNMP_ASN1_TYPE_COUNTER32 SNMP_ASN1_TYPE_COUNTER +#define SNMP_ASN1_TYPE_GAUGE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_GAUGE) +#define SNMP_ASN1_TYPE_GAUGE32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_UNSIGNED32 SNMP_ASN1_TYPE_GAUGE +#define SNMP_ASN1_TYPE_TIMETICKS (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_TIMETICKS) +#define SNMP_ASN1_TYPE_OPAQUE (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_OPAQUE) +#define SNMP_ASN1_TYPE_COUNTER64 (SNMP_ASN1_CLASS_APPLICATION | SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_APPLICATION_COUNTER64) + +#define SNMP_VARBIND_EXCEPTION_OFFSET 0xF0 +#define SNMP_VARBIND_EXCEPTION_MASK 0x0F + +/** error codes predefined by SNMP prot. */ +typedef enum { + SNMP_ERR_NOERROR = 0, +/* +outdated v1 error codes. do not use anmore! +#define SNMP_ERR_NOSUCHNAME 2 use SNMP_ERR_NOSUCHINSTANCE instead +#define SNMP_ERR_BADVALUE 3 use SNMP_ERR_WRONGTYPE,SNMP_ERR_WRONGLENGTH,SNMP_ERR_WRONGENCODING or SNMP_ERR_WRONGVALUE instead +#define SNMP_ERR_READONLY 4 use SNMP_ERR_NOTWRITABLE instead +*/ + SNMP_ERR_GENERROR = 5, + SNMP_ERR_NOACCESS = 6, + SNMP_ERR_WRONGTYPE = 7, + SNMP_ERR_WRONGLENGTH = 8, + SNMP_ERR_WRONGENCODING = 9, + SNMP_ERR_WRONGVALUE = 10, + SNMP_ERR_NOCREATION = 11, + SNMP_ERR_INCONSISTENTVALUE = 12, + SNMP_ERR_RESOURCEUNAVAILABLE = 13, + SNMP_ERR_COMMITFAILED = 14, + SNMP_ERR_UNDOFAILED = 15, + SNMP_ERR_NOTWRITABLE = 17, + SNMP_ERR_INCONSISTENTNAME = 18, + + SNMP_ERR_NOSUCHINSTANCE = SNMP_VARBIND_EXCEPTION_OFFSET + SNMP_ASN1_CONTEXT_VARBIND_NO_SUCH_INSTANCE +} snmp_err_t; + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + u32_t id[SNMP_MAX_OBJ_ID_LEN]; +}; + +struct snmp_obj_id_const_ref +{ + u8_t len; + const u32_t* id; +}; + +extern const struct snmp_obj_id_const_ref snmp_zero_dot_zero; /* administrative identifier from SNMPv2-SMI */ + +/** SNMP variant value, used as reference in struct snmp_node_instance and table implementation */ +union snmp_variant_value +{ + void* ptr; + const void* const_ptr; + u32_t u32; + s32_t s32; +}; + + +/** +SNMP MIB node types + tree node is the only node the stack can process in order to walk the tree, + all other nodes are assumed to be leaf nodes. + This cannot be an enum because users may want to define their own node types. +*/ +#define SNMP_NODE_TREE 0x00 +/* predefined leaf node types */ +#define SNMP_NODE_SCALAR 0x01 +#define SNMP_NODE_SCALAR_ARRAY 0x02 +#define SNMP_NODE_TABLE 0x03 +#define SNMP_NODE_THREADSYNC 0x04 + +/** node "base class" layout, the mandatory fields for a node */ +struct snmp_node +{ + /** one out of SNMP_NODE_TREE or any leaf node type (like SNMP_NODE_SCALAR) */ + u8_t node_type; + /** the number assigned to this node which used as part of the full OID */ + u32_t oid; +}; + +/** SNMP node instance access types */ +typedef enum { + SNMP_NODE_INSTANCE_ACCESS_READ = 1, + SNMP_NODE_INSTANCE_ACCESS_WRITE = 2, + SNMP_NODE_INSTANCE_READ_ONLY = SNMP_NODE_INSTANCE_ACCESS_READ, + SNMP_NODE_INSTANCE_READ_WRITE = (SNMP_NODE_INSTANCE_ACCESS_READ | SNMP_NODE_INSTANCE_ACCESS_WRITE), + SNMP_NODE_INSTANCE_WRITE_ONLY = SNMP_NODE_INSTANCE_ACCESS_WRITE, + SNMP_NODE_INSTANCE_NOT_ACCESSIBLE = 0 +} snmp_access_t; + +struct snmp_node_instance; + +typedef s16_t (*node_instance_get_value_method)(struct snmp_node_instance*, void*); +typedef snmp_err_t (*node_instance_set_test_method)(struct snmp_node_instance*, u16_t, void*); +typedef snmp_err_t (*node_instance_set_value_method)(struct snmp_node_instance*, u16_t, void*); +typedef void (*node_instance_release_method)(struct snmp_node_instance*); + +#define SNMP_GET_VALUE_RAW_DATA 0x8000 + +/** SNMP node instance */ +struct snmp_node_instance +{ + /** prefilled with the node, get_instance() is called on; may be changed by user to any value to pass an arbitrary node between calls to get_instance() and get_value/test_value/set_value */ + const struct snmp_node* node; + /** prefilled with the instance id requested; for get_instance() this is the exact oid requested; for get_next_instance() this is the relative starting point, stack expects relative oid of next node here */ + struct snmp_obj_id instance_oid; + + /** ASN type for this object (see snmp_asn1.h for definitions) */ + u8_t asn1_type; + /** one out of instance access types defined above (SNMP_NODE_INSTANCE_READ_ONLY,...) */ + snmp_access_t access; + + /** returns object value for the given object identifier. Return values <0 to indicate an error */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; + /** called in any case when the instance is not required anymore by stack (useful for freeing memory allocated in get_instance/get_next_instance methods) */ + node_instance_release_method release_instance; + + /** reference to pass arbitrary value between calls to get_instance() and get_value/test_value/set_value */ + union snmp_variant_value reference; + /** see reference (if reference is a pointer, the length of underlying data may be stored here or anything else) */ + u32_t reference_len; +}; + + +/** SNMP tree node */ +struct snmp_tree_node +{ + /** inherited "base class" members */ + struct snmp_node node; + u16_t subnode_count; + const struct snmp_node* const *subnodes; +}; + +#define SNMP_CREATE_TREE_NODE(oid, subnodes) \ + {{ SNMP_NODE_TREE, (oid) }, \ + (u16_t)LWIP_ARRAYSIZE(subnodes), (subnodes) } + +#define SNMP_CREATE_EMPTY_TREE_NODE(oid) \ + {{ SNMP_NODE_TREE, (oid) }, \ + 0, NULL } + +/** SNMP leaf node */ +struct snmp_leaf_node +{ + /** inherited "base class" members */ + struct snmp_node node; + snmp_err_t (*get_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + snmp_err_t (*get_next_instance)(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +}; + +/** represents a single mib with its base oid and root node */ +struct snmp_mib +{ + const u32_t *base_oid; + u8_t base_oid_len; + const struct snmp_node *root_node; +}; + +#define SNMP_MIB_CREATE(oid_list, root_node) { (oid_list), (u8_t)LWIP_ARRAYSIZE(oid_list), root_node } + +/** OID range structure */ +struct snmp_oid_range +{ + u32_t min; + u32_t max; +}; + +/** checks if incoming OID length and values are in allowed ranges */ +u8_t snmp_oid_in_range(const u32_t *oid_in, u8_t oid_len, const struct snmp_oid_range *oid_ranges, u8_t oid_ranges_len); + +typedef enum { + SNMP_NEXT_OID_STATUS_SUCCESS, + SNMP_NEXT_OID_STATUS_NO_MATCH, + SNMP_NEXT_OID_STATUS_BUF_TO_SMALL +} snmp_next_oid_status_t; + +/** state for next_oid_init / next_oid_check functions */ +struct snmp_next_oid_state +{ + const u32_t* start_oid; + u8_t start_oid_len; + + u32_t* next_oid; + u8_t next_oid_len; + u8_t next_oid_max_len; + + snmp_next_oid_status_t status; + void* reference; +}; + +void snmp_next_oid_init(struct snmp_next_oid_state *state, + const u32_t *start_oid, u8_t start_oid_len, + u32_t *next_oid_buf, u8_t next_oid_max_len); +u8_t snmp_next_oid_precheck(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len); +u8_t snmp_next_oid_check(struct snmp_next_oid_state *state, const u32_t *oid, const u8_t oid_len, void* reference); + +void snmp_oid_assign(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_combine(struct snmp_obj_id* target, const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +void snmp_oid_prefix(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +void snmp_oid_append(struct snmp_obj_id* target, const u32_t *oid, u8_t oid_len); +u8_t snmp_oid_equal(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); +s8_t snmp_oid_compare(const u32_t *oid1, u8_t oid1_len, const u32_t *oid2, u8_t oid2_len); + +#if LWIP_IPV4 +u8_t snmp_oid_to_ip4(const u32_t *oid, ip4_addr_t *ip); +void snmp_ip4_to_oid(const ip4_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +u8_t snmp_oid_to_ip6(const u32_t *oid, ip6_addr_t *ip); +void snmp_ip6_to_oid(const ip6_addr_t *ip, u32_t *oid); +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 || LWIP_IPV6 +u8_t snmp_ip_to_oid(const ip_addr_t *ip, u32_t *oid); +u8_t snmp_ip_port_to_oid(const ip_addr_t *ip, u16_t port, u32_t *oid); + +u8_t snmp_oid_to_ip(const u32_t *oid, u8_t oid_len, ip_addr_t *ip); +u8_t snmp_oid_to_ip_port(const u32_t *oid, u8_t oid_len, ip_addr_t *ip, u16_t *port); +#endif /* LWIP_IPV4 || LWIP_IPV6 */ + +struct netif; +u8_t netif_to_num(const struct netif *netif); + +snmp_err_t snmp_set_test_ok(struct snmp_node_instance* instance, u16_t value_len, void* value); /* generic function which can be used if test is always successful */ + +err_t snmp_decode_bits(const u8_t *buf, u32_t buf_len, u32_t *bit_value); +err_t snmp_decode_truthvalue(const s32_t *asn1_value, u8_t *bool_value); +u8_t snmp_encode_bits(u8_t *buf, u32_t buf_len, u32_t bit_value, u8_t bit_count); +u8_t snmp_encode_truthvalue(s32_t *asn1_value, u32_t bool_value); + +struct snmp_statistics +{ + u32_t inpkts; + u32_t outpkts; + u32_t inbadversions; + u32_t inbadcommunitynames; + u32_t inbadcommunityuses; + u32_t inasnparseerrs; + u32_t intoobigs; + u32_t innosuchnames; + u32_t inbadvalues; + u32_t inreadonlys; + u32_t ingenerrs; + u32_t intotalreqvars; + u32_t intotalsetvars; + u32_t ingetrequests; + u32_t ingetnexts; + u32_t insetrequests; + u32_t ingetresponses; + u32_t intraps; + u32_t outtoobigs; + u32_t outnosuchnames; + u32_t outbadvalues; + u32_t outgenerrs; + u32_t outgetrequests; + u32_t outgetnexts; + u32_t outsetrequests; + u32_t outgetresponses; + u32_t outtraps; +}; + +extern struct snmp_statistics snmp_stats; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* LWIP_HDR_APPS_SNMP_CORE_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_mib2.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_mib2.h new file mode 100644 index 0000000000..2f4a68935e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_mib2.h @@ -0,0 +1,78 @@ +/** + * @file + * SNMP MIB2 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_APPS_SNMP_MIB2_H +#define LWIP_HDR_APPS_SNMP_MIB2_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ +#if SNMP_LWIP_MIB2 + +#include "lwip/apps/snmp_core.h" + +extern const struct snmp_mib mib2; + +#if SNMP_USE_NETCONN +#include "lwip/apps/snmp_threadsync.h" +void snmp_mib2_lwip_synchronizer(snmp_threadsync_called_fn fn, void* arg); +extern struct snmp_threadsync_instance snmp_mib2_lwip_locks; +#endif + +#ifndef SNMP_SYSSERVICES +#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) +#endif + +void snmp_mib2_set_sysdescr(const u8_t* str, const u16_t* len); /* read-only be defintion */ +void snmp_mib2_set_syscontact(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syscontact_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_sysname(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_sysname_readonly(const u8_t *ocstr, const u16_t *ocstrlen); +void snmp_mib2_set_syslocation(u8_t *ocstr, u16_t *ocstrlen, u16_t bufsize); +void snmp_mib2_set_syslocation_readonly(const u8_t *ocstr, const u16_t *ocstrlen); + +#endif /* SNMP_LWIP_MIB2 */ +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_MIB2_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_opts.h new file mode 100644 index 0000000000..6c9ba7beb3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_opts.h @@ -0,0 +1,293 @@ +/** + * @file + * SNMP server options list + */ + +/* + * Copyright (c) 2015 Dirk Ziegelmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_OPTS_H +#define LWIP_HDR_SNMP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup snmp_opts Options + * @ingroup snmp + * @{ + */ + +/** + * LWIP_SNMP==1: This enables the lwIP SNMP agent. UDP must be available + * for SNMP transport. + * If you want to use your own SNMP agent, leave this disabled. + * To integrate MIB2 of an external agent, you need to enable + * LWIP_MIB2_CALLBACKS and MIB2_STATS. This will give you the callbacks + * and statistics counters you need to get MIB2 working. + */ +#if !defined LWIP_SNMP || defined __DOXYGEN__ +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_USE_NETCONN: Use netconn API instead of raw API. + * Makes SNMP agent run in a worker thread, so blocking operations + * can be done in MIB calls. + */ +#if !defined SNMP_USE_NETCONN || defined __DOXYGEN__ +#define SNMP_USE_NETCONN 0 +#endif + +/** + * SNMP_USE_RAW: Use raw API. + * SNMP agent does not run in a worker thread, so blocking operations + * should not be done in MIB calls. + */ +#if !defined SNMP_USE_RAW || defined __DOXYGEN__ +#define SNMP_USE_RAW 1 +#endif + +#if SNMP_USE_NETCONN && SNMP_USE_RAW +#error SNMP stack can use only one of the APIs {raw, netconn} +#endif + +#if LWIP_SNMP && !SNMP_USE_NETCONN && !SNMP_USE_RAW +#error SNMP stack needs a receive API and UDP {raw, netconn} +#endif + +#if SNMP_USE_NETCONN +/** + * SNMP_STACK_SIZE: Stack size of SNMP netconn worker thread + */ +#if !defined SNMP_STACK_SIZE || defined __DOXYGEN__ +#define SNMP_STACK_SIZE DEFAULT_THREAD_STACKSIZE +#endif + +/** + * SNMP_THREAD_PRIO: SNMP netconn worker thread priority + */ +#if !defined SNMP_THREAD_PRIO || defined __DOXYGEN__ +#define SNMP_THREAD_PRIO DEFAULT_THREAD_PRIO +#endif +#endif /* SNMP_USE_NETCONN */ + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#if !defined SNMP_TRAP_DESTINATIONS || defined __DOXYGEN__ +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#if !defined SNMP_SAFE_REQUESTS || defined __DOXYGEN__ +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. + */ +#if !defined SNMP_MAX_OCTET_STRING_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum number of Sub ID's inside an object identifier. + * Indirectly this also limits the maximum depth of SNMP tree. + */ +#if !defined SNMP_MAX_OBJ_ID_LEN || defined __DOXYGEN__ +#define SNMP_MAX_OBJ_ID_LEN 50 +#endif + +#if !defined SNMP_MAX_VALUE_SIZE || defined __DOXYGEN__ +/** + * The maximum size of a value. + */ +#define SNMP_MIN_VALUE_SIZE (2 * sizeof(u32_t*)) /* size required to store the basic types (8 bytes for counter64) */ +/** + * The minimum size of a value. + */ +#define SNMP_MAX_VALUE_SIZE LWIP_MAX(LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN), sizeof(u32_t)*(SNMP_MAX_OBJ_ID_LEN)), SNMP_MIN_VALUE_SIZE) +#endif + +/** + * The snmp read-access community. Used for write-access and traps, too + * unless SNMP_COMMUNITY_WRITE or SNMP_COMMUNITY_TRAP are enabled, respectively. + */ +#if !defined SNMP_COMMUNITY || defined __DOXYGEN__ +#define SNMP_COMMUNITY "public" +#endif + +/** + * The snmp write-access community. + * Set this community to "" in order to disallow any write access. + */ +#if !defined SNMP_COMMUNITY_WRITE || defined __DOXYGEN__ +#define SNMP_COMMUNITY_WRITE "private" +#endif + +/** + * The snmp community used for sending traps. + */ +#if !defined SNMP_COMMUNITY_TRAP || defined __DOXYGEN__ +#define SNMP_COMMUNITY_TRAP "public" +#endif + +/** + * The maximum length of community string. + * If community names shall be adjusted at runtime via snmp_set_community() calls, + * enter here the possible maximum length (+1 for terminating null character). + */ +#if !defined SNMP_MAX_COMMUNITY_STR_LEN || defined __DOXYGEN__ +#define SNMP_MAX_COMMUNITY_STR_LEN LWIP_MAX(LWIP_MAX(sizeof(SNMP_COMMUNITY), sizeof(SNMP_COMMUNITY_WRITE)), sizeof(SNMP_COMMUNITY_TRAP)) +#endif + +/** + * The OID identifiying the device. This may be the enterprise OID itself or any OID located below it in tree. + */ +#if !defined SNMP_DEVICE_ENTERPRISE_OID || defined __DOXYGEN__ +#define SNMP_LWIP_ENTERPRISE_OID 26381 +/** + * IANA assigned enterprise ID for lwIP is 26381 + * @see http://www.iana.org/assignments/enterprise-numbers + * + * @note this enterprise ID is assigned to the lwIP project, + * all object identifiers living under this ID are assigned + * by the lwIP maintainers! + * @note don't change this define, use snmp_set_device_enterprise_oid() + * + * If you need to create your own private MIB you'll need + * to apply for your own enterprise ID with IANA: + * http://www.iana.org/numbers.html + */ +#define SNMP_DEVICE_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, SNMP_LWIP_ENTERPRISE_OID} +/** + * Length of SNMP_DEVICE_ENTERPRISE_OID + */ +#define SNMP_DEVICE_ENTERPRISE_OID_LEN 7 +#endif + +/** + * SNMP_DEBUG: Enable debugging for SNMP messages. + */ +#if !defined SNMP_DEBUG || defined __DOXYGEN__ +#define SNMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#if !defined SNMP_MIB_DEBUG || defined __DOXYGEN__ +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * Indicates if the MIB2 implementation of LWIP SNMP stack is used. + */ +#if !defined SNMP_LWIP_MIB2 || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2 LWIP_SNMP +#endif + +/** + * Value return for sysDesc field of MIB2. + */ +#if !defined SNMP_LWIP_MIB2_SYSDESC || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSDESC "lwIP" +#endif + +/** + * Value return for sysName field of MIB2. + * To make sysName field settable, call snmp_mib2_set_sysname() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSNAME || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSNAME "FQDN-unk" +#endif + +/** + * Value return for sysContact field of MIB2. + * To make sysContact field settable, call snmp_mib2_set_syscontact() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSCONTACT || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSCONTACT "" +#endif + +/** + * Value return for sysLocation field of MIB2. + * To make sysLocation field settable, call snmp_mib2_set_syslocation() to provide the necessary buffers. + */ +#if !defined SNMP_LWIP_MIB2_SYSLOCATION || defined __DOXYGEN__ +#define SNMP_LWIP_MIB2_SYSLOCATION "" +#endif + +/** + * This value is used to limit the repetitions processed in GetBulk requests (value == 0 means no limitation). + * This may be useful to limit the load for a single request. + * According to SNMP RFC 1905 it is allowed to not return all requested variables from a GetBulk request if system load would be too high. + * so the effect is that the client will do more requests to gather all data. + * For the stack this could be useful in case that SNMP processing is done in TCP/IP thread. In this situation a request with many + * repetitions could block the thread for a longer time. Setting limit here will keep the stack more responsive. + */ +#if !defined SNMP_LWIP_GETBULK_MAX_REPETITIONS || defined __DOXYGEN__ +#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0 +#endif + +/** + * @} + */ + +/* + ------------------------------------ + ---------- SNMPv3 options ---------- + ------------------------------------ +*/ + +/** + * LWIP_SNMP_V3==1: This enables EXPERIMENTAL SNMPv3 support. LWIP_SNMP must + * also be enabled. + * THIS IS UNDER DEVELOPMENT AND SHOULD NOT BE ENABLED IN PRODUCTS. + */ +#ifndef LWIP_SNMP_V3 +#define LWIP_SNMP_V3 0 +#endif + +#ifndef LWIP_SNMP_V3_CRYPTO +#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3 +#endif + +#ifndef LWIP_SNMP_V3_MBEDTLS +#define LWIP_SNMP_V3_MBEDTLS LWIP_SNMP_V3 +#endif + +#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_scalar.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_scalar.h new file mode 100644 index 0000000000..40a060c640 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_scalar.h @@ -0,0 +1,113 @@ +/** + * @file + * SNMP server MIB API to implement scalar nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_SCALAR_H +#define LWIP_HDR_APPS_SNMP_SCALAR_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** basic scalar node */ +struct snmp_scalar_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u8_t asn1_type; + snmp_access_t access; + node_instance_get_value_method get_value; + node_instance_set_test_method set_test; + node_instance_set_value_method set_value; +}; + + +snmp_err_t snmp_scalar_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_NODE(oid, access, asn1_type, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR, (oid) }, \ + snmp_scalar_get_instance, \ + snmp_scalar_get_next_instance }, \ + (asn1_type), (access), (get_value_method), (set_test_method), (set_value_method) } + +#define SNMP_SCALAR_CREATE_NODE_READONLY(oid, asn1_type, get_value_method) SNMP_SCALAR_CREATE_NODE(oid, SNMP_NODE_INSTANCE_READ_ONLY, asn1_type, get_value_method, NULL, NULL) + +/** scalar array node - a tree node which contains scalars only as children */ +struct snmp_scalar_array_node_def +{ + u32_t oid; + u8_t asn1_type; + snmp_access_t access; +}; + +typedef s16_t (*snmp_scalar_array_get_value_method)(const struct snmp_scalar_array_node_def*, void*); +typedef snmp_err_t (*snmp_scalar_array_set_test_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); +typedef snmp_err_t (*snmp_scalar_array_set_value_method)(const struct snmp_scalar_array_node_def*, u16_t, void*); + +/** basic scalar array node */ +struct snmp_scalar_array_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t array_node_count; + const struct snmp_scalar_array_node_def* array_nodes; + snmp_scalar_array_get_value_method get_value; + snmp_scalar_array_set_test_method set_test; + snmp_scalar_array_set_value_method set_value; +}; + +snmp_err_t snmp_scalar_array_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_scalar_array_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_SCALAR_CREATE_ARRAY_NODE(oid, array_nodes, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_SCALAR_ARRAY, (oid) }, \ + snmp_scalar_array_get_instance, \ + snmp_scalar_array_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(array_nodes), (array_nodes), (get_value_method), (set_test_method), (set_value_method) } + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_SCALAR_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_table.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_table.h new file mode 100644 index 0000000000..4988b51c25 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_table.h @@ -0,0 +1,134 @@ +/** + * @file + * SNMP server MIB API to implement table nodes + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Martin Hentschel + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_TABLE_H +#define LWIP_HDR_APPS_SNMP_TABLE_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/apps/snmp_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** default (customizable) read/write table */ +struct snmp_table_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_access_t access; +}; + +/** table node */ +struct snmp_table_node +{ + /** inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_col_def* columns; + snmp_err_t (*get_cell_instance)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, struct snmp_node_instance* cell_instance); + snmp_err_t (*get_next_cell_instance)(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance); + /** returns object value for the given object identifier */ + node_instance_get_value_method get_value; + /** tests length and/or range BEFORE setting */ + node_instance_set_test_method set_test; + /** sets object value, only called when set_test() was successful */ + node_instance_set_value_method set_value; +}; + +snmp_err_t snmp_table_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE(oid, columns, get_cell_instance_method, get_next_cell_instance_method, get_value_method, set_test_method, set_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_get_instance, \ + snmp_table_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), \ + (get_cell_instance_method), (get_next_cell_instance_method), \ + (get_value_method), (set_test_method), (set_value_method)} + +#define SNMP_TABLE_GET_COLUMN_FROM_OID(oid) ((oid)[1]) /* first array value is (fixed) row entry (fixed to 1) and 2nd value is column, follow3ed by instance */ + + +/** simple read-only table */ +typedef enum { + SNMP_VARIANT_VALUE_TYPE_U32, + SNMP_VARIANT_VALUE_TYPE_S32, + SNMP_VARIANT_VALUE_TYPE_PTR, + SNMP_VARIANT_VALUE_TYPE_CONST_PTR +} snmp_table_column_data_type_t; + +struct snmp_table_simple_col_def +{ + u32_t index; + u8_t asn1_type; + snmp_table_column_data_type_t data_type; /* depending of what union member is used to store the value*/ +}; + +/** simple read-only table node */ +struct snmp_table_simple_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + u16_t column_count; + const struct snmp_table_simple_col_def* columns; + snmp_err_t (*get_cell_value)(const u32_t* column, const u32_t* row_oid, u8_t row_oid_len, union snmp_variant_value* value, u32_t* value_len); + snmp_err_t (*get_next_cell_instance_and_value)(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len); +}; + +snmp_err_t snmp_table_simple_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +#define SNMP_TABLE_CREATE_SIMPLE(oid, columns, get_cell_value_method, get_next_cell_instance_and_value_method) \ + {{{ SNMP_NODE_TABLE, (oid) }, \ + snmp_table_simple_get_instance, \ + snmp_table_simple_get_next_instance }, \ + (u16_t)LWIP_ARRAYSIZE(columns), (columns), (get_cell_value_method), (get_next_cell_instance_and_value_method) } + +s16_t snmp_table_extract_value_from_s32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_u32ref(struct snmp_node_instance* instance, void* value); +s16_t snmp_table_extract_value_from_refconstptr(struct snmp_node_instance* instance, void* value); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_TABLE_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_threadsync.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_threadsync.h new file mode 100644 index 0000000000..a25dbf2d0f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmp_threadsync.h @@ -0,0 +1,114 @@ +/** + * @file + * SNMP server MIB API to implement thread synchronization + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ + +#ifndef LWIP_HDR_APPS_SNMP_THREADSYNC_H +#define LWIP_HDR_APPS_SNMP_THREADSYNC_H + +#include "lwip/apps/snmp_opts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/snmp_core.h" +#include "lwip/sys.h" + +typedef void (*snmp_threadsync_called_fn)(void* arg); +typedef void (*snmp_threadsync_synchronizer_fn)(snmp_threadsync_called_fn fn, void* arg); + + +/** Thread sync runtime data. For internal usage only. */ +struct threadsync_data +{ + union { + snmp_err_t err; + s16_t s16; + } retval; + union { + const u32_t *root_oid; + void *value; + } arg1; + union { + u8_t root_oid_len; + u16_t len; + } arg2; + const struct snmp_threadsync_node *threadsync_node; + struct snmp_node_instance proxy_instance; +}; + +/** Thread sync instance. Needed EXCATLY once for every thread to be synced into. */ +struct snmp_threadsync_instance +{ + sys_sem_t sem; + sys_mutex_t sem_usage_mutex; + snmp_threadsync_synchronizer_fn sync_fn; + struct threadsync_data data; +}; + +/** SNMP thread sync proxy leaf node */ +struct snmp_threadsync_node +{ + /* inherited "base class" members */ + struct snmp_leaf_node node; + + const struct snmp_leaf_node *target; + struct snmp_threadsync_instance *instance; +}; + +snmp_err_t snmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); +snmp_err_t snmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance); + +/** Create thread sync proxy node */ +#define SNMP_CREATE_THREAD_SYNC_NODE(oid, target_leaf_node, threadsync_instance) \ + {{{ SNMP_NODE_THREADSYNC, (oid) }, \ + snmp_threadsync_get_instance, \ + snmp_threadsync_get_next_instance }, \ + (target_leaf_node), \ + (threadsync_instance) } + +/** Create thread sync instance data */ +void snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn); + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNMP_THREADSYNC_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmpv3.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmpv3.h new file mode 100644 index 0000000000..c99fed4e10 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/snmpv3.h @@ -0,0 +1,90 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_H +#define LWIP_HDR_APPS_SNMP_V3_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#define SNMP_V3_AUTH_ALGO_INVAL 0 +#define SNMP_V3_AUTH_ALGO_MD5 1 +#define SNMP_V3_AUTH_ALGO_SHA 2 + +#define SNMP_V3_PRIV_ALGO_INVAL 0 +#define SNMP_V3_PRIV_ALGO_DES 1 +#define SNMP_V3_PRIV_ALGO_AES 2 + +#define SNMP_V3_PRIV_MODE_DECRYPT 0 +#define SNMP_V3_PRIV_MODE_ENCRYPT 1 + +/* + * The following callback functions must be implemented by the application. + * There is a dummy implementation in snmpv3_dummy.c. + */ + +void snmpv3_get_engine_id(const char **id, u8_t *len); +err_t snmpv3_set_engine_id(const char* id, u8_t len); + +u32_t snmpv3_get_engine_boots(void); +void snmpv3_set_engine_boots(u32_t boots); + +u32_t snmpv3_get_engine_time(void); +void snmpv3_reset_engine_time(void); + +err_t snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key); + +/* The following functions are provided by the SNMPv3 agent */ + +void snmpv3_engine_id_changed(void); + +void snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 16-octet buffer */ + +void snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 20-octet buffer */ + +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp.h new file mode 100644 index 0000000000..40df9cc590 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp.h @@ -0,0 +1,76 @@ +/** + * @file + * SNTP client API + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_H +#define LWIP_HDR_APPS_SNTP_H + +#include "lwip/apps/sntp_opts.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* SNTP operating modes: default is to poll using unicast. + The mode has to be set before calling sntp_init(). */ +#define SNTP_OPMODE_POLL 0 +#define SNTP_OPMODE_LISTENONLY 1 +void sntp_setoperatingmode(u8_t operating_mode); +u8_t sntp_getoperatingmode(void); + +void sntp_init(void); +void sntp_stop(void); +u8_t sntp_enabled(void); + +void sntp_setserver(u8_t idx, const ip_addr_t *addr); +const ip_addr_t* sntp_getserver(u8_t idx); + +#if SNTP_SERVER_DNS +void sntp_setservername(u8_t idx, char *server); +char *sntp_getservername(u8_t idx); +#endif /* SNTP_SERVER_DNS */ + +#if SNTP_GET_SERVERS_FROM_DHCP +void sntp_servermode_dhcp(int set_servers_from_dhcp); +#else /* SNTP_GET_SERVERS_FROM_DHCP */ +#define sntp_servermode_dhcp(x) +#endif /* SNTP_GET_SERVERS_FROM_DHCP */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_SNTP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp_opts.h new file mode 100644 index 0000000000..f3651f90e6 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/sntp_opts.h @@ -0,0 +1,173 @@ +/** + * @file + * SNTP client options list + */ + +/* + * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Frédéric Bernon, Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_APPS_SNTP_OPTS_H +#define LWIP_HDR_APPS_SNTP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup sntp_opts Options + * @ingroup sntp + * @{ + */ + +/** SNTP macro to change system time in seconds + * Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds instead of this one + * if you need the additional precision. + */ +#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec) +#endif + +/** The maximum number of SNTP servers that can be set */ +#if !defined SNTP_MAX_SERVERS || defined __DOXYGEN__ +#define SNTP_MAX_SERVERS LWIP_DHCP_MAX_NTP_SERVERS +#endif + +/** Set this to 1 to implement the callback function called by dhcp when + * NTP servers are received. */ +#if !defined SNTP_GET_SERVERS_FROM_DHCP || defined __DOXYGEN__ +#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV +#endif + +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ +#define SNTP_SERVER_DNS 0 +#endif + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#if !defined SNTP_DEBUG || defined __DOXYGEN__ +#define SNTP_DEBUG LWIP_DBG_OFF +#endif + +/** SNTP server port */ +#if !defined SNTP_PORT || defined __DOXYGEN__ +#define SNTP_PORT 123 +#endif + +/** Set this to 1 to allow config of SNTP server(s) by DNS name */ +#if !defined SNTP_SERVER_DNS || defined __DOXYGEN__ +#define SNTP_SERVER_DNS 0 +#endif + +/** Sanity check: + * Define this to + * - 0 to turn off sanity checks (default; smaller code) + * - >= 1 to check address and port of the response packet to ensure the + * response comes from the server we sent the request to. + * - >= 2 to check returned Originate Timestamp against Transmit Timestamp + * sent to the server (to ensure response to older request). + * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp + * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). + * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each + * greater than or equal to 0 and less than infinity, where infinity is + * currently a cozy number like one second. This check avoids using a + * server whose synchronization source has expired for a very long time. + */ +#if !defined SNTP_CHECK_RESPONSE || defined __DOXYGEN__ +#define SNTP_CHECK_RESPONSE 0 +#endif + +/** According to the RFC, this shall be a random delay + * between 1 and 5 minutes (in milliseconds) to prevent load peaks. + * This can be defined to a random generation function, + * which must return the delay in milliseconds as u32_t. + * Turned off by default. + */ +#if !defined SNTP_STARTUP_DELAY || defined __DOXYGEN__ +#define SNTP_STARTUP_DELAY 0 +#endif + +/** If you want the startup delay to be a function, define this + * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. + */ +#if !defined SNTP_STARTUP_DELAY_FUNC || defined __DOXYGEN__ +#define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY +#endif + +/** SNTP receive timeout - in milliseconds + * Also used as retry timeout - this shouldn't be too low. + * Default is 3 seconds. + */ +#if !defined SNTP_RECV_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RECV_TIMEOUT 3000 +#endif + +/** SNTP update delay - in milliseconds + * Default is 1 hour. Must not be beolw 15 seconds by specification (i.e. 15000) + */ +#if !defined SNTP_UPDATE_DELAY || defined __DOXYGEN__ +#define SNTP_UPDATE_DELAY 3600000 +#endif + +/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 + * to send in request and compare in response. + */ +#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__ +#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) +#endif + +/** Default retry timeout (in milliseconds) if the response + * received is invalid. + * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. + */ +#if !defined SNTP_RETRY_TIMEOUT || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT +#endif + +/** Maximum retry timeout (in milliseconds). */ +#if !defined SNTP_RETRY_TIMEOUT_MAX || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) +#endif + +/** Increase retry timeout with every retry sent + * Default is on to conform to RFC. + */ +#if !defined SNTP_RETRY_TIMEOUT_EXP || defined __DOXYGEN__ +#define SNTP_RETRY_TIMEOUT_EXP 1 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_opts.h new file mode 100644 index 0000000000..6968a803b4 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_opts.h @@ -0,0 +1,105 @@ +/****************************************************************//** + * + * @file tftp_opts.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) implementation options + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_OPTS_H +#define LWIP_HDR_APPS_TFTP_OPTS_H + +#include "lwip/opt.h" + +/** + * @defgroup tftp_opts Options + * @ingroup tftp + * @{ + */ + +/** + * Enable TFTP debug messages + */ +#if !defined TFTP_DEBUG || defined __DOXYGEN__ +#define TFTP_DEBUG LWIP_DBG_ON +#endif + +/** + * TFTP server port + */ +#if !defined TFTP_PORT || defined __DOXYGEN__ +#define TFTP_PORT 69 +#endif + +/** + * TFTP timeout + */ +#if !defined TFTP_TIMEOUT_MSECS || defined __DOXYGEN__ +#define TFTP_TIMEOUT_MSECS 10000 +#endif + +/** + * Max. number of retries when a file is read from server + */ +#if !defined TFTP_MAX_RETRIES || defined __DOXYGEN__ +#define TFTP_MAX_RETRIES 5 +#endif + +/** + * TFTP timer cyclic interval + */ +#if !defined TFTP_TIMER_MSECS || defined __DOXYGEN__ +#define TFTP_TIMER_MSECS 50 +#endif + +/** + * Max. length of TFTP filename + */ +#if !defined TFTP_MAX_FILENAME_LEN || defined __DOXYGEN__ +#define TFTP_MAX_FILENAME_LEN 20 +#endif + +/** + * Max. length of TFTP mode + */ +#if !defined TFTP_MAX_MODE_LEN || defined __DOXYGEN__ +#define TFTP_MAX_MODE_LEN 7 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_TFTP_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_server.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_server.h new file mode 100644 index 0000000000..3fbe701e0a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/apps/tftp_server.h @@ -0,0 +1,94 @@ +/****************************************************************//** + * + * @file tftp_server.h + * + * @author Logan Gunthorpe + * + * @brief Trivial File Transfer Protocol (RFC 1350) + * + * Copyright (c) Deltatee Enterprises Ltd. 2013 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Logan Gunthorpe + * + */ + +#ifndef LWIP_HDR_APPS_TFTP_SERVER_H +#define LWIP_HDR_APPS_TFTP_SERVER_H + +#include "lwip/apps/tftp_opts.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup tftp + * TFTP context containing callback functions for TFTP transfers + */ +struct tftp_context { + /** + * Open file for read/write. + * @param fname Filename + * @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail) + * @param write Flag indicating read (0) or write (!= 0) access + * @returns File handle supplied to other functions + */ + void* (*open)(const char* fname, const char* mode, u8_t write); + /** + * Close file handle + * @param handle File handle returned by open() + */ + void (*close)(void* handle); + /** + * Read from file + * @param handle File handle returned by open() + * @param buf Target buffer to copy read data to + * @param bytes Number of bytes to copy to buf + * @returns >= 0: Success; < 0: Error + */ + int (*read)(void* handle, void* buf, int bytes); + /** + * Write to file + * @param handle File handle returned by open() + * @param pbuf PBUF adjusted such that payload pointer points + * to the beginning of write data. In other words, + * TFTP headers are stripped off. + * @returns >= 0: Success; < 0: Error + */ + int (*write)(void* handle, struct pbuf* p); +}; + +err_t tftp_init(const struct tftp_context* ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_TFTP_SERVER_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/arch.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/arch.h new file mode 100644 index 0000000000..55714e1132 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/arch.h @@ -0,0 +1,319 @@ +/** + * @file + * Support for different processor and compiler architectures + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ARCH_H +#define LWIP_HDR_ARCH_H + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** + * @defgroup compiler_abstraction Compiler/platform abstraction + * @ingroup sys_layer + * All defines related to this section must not be placed in lwipopts.h, + * but in arch/cc.h! + * These options cannot be \#defined in lwipopts.h since they are not options + * of lwIP itself, but options of the lwIP port to your system. + * @{ + */ + +/** Define the byte order of the system. + * Needed for conversion of network data to host byte order. + * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN + */ +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +/** Define random number generator function of your system */ +#ifdef __DOXYGEN__ +#define LWIP_RAND() ((u32_t)rand()) +#endif + +/** Platform specific diagnostic output.\n + * Note the default implementation pulls in printf, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_DIAG +#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) +#include +#include +#endif + +/** Platform specific assertion handling.\n + * Note the default implementation pulls in printf, fflush and abort, which may + * in turn pull in a lot of standard libary code. In resource-constrained + * systems, this should be defined to something less resource-consuming. + */ +#ifndef LWIP_PLATFORM_ASSERT +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ + x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) +#include +#include +#endif + +/** Define this to 1 in arch/cc.h of your port if you do not want to + * include stddef.h header to get size_t. You need to typedef size_t + * by yourself in this case. + */ +#ifndef LWIP_NO_STDDEF_H +#define LWIP_NO_STDDEF_H 0 +#endif + +#if !LWIP_NO_STDDEF_H +#include /* for size_t */ +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the stdint.h header. You need to typedef the generic types listed in + * lwip/arch.h yourself in this case (u8_t, u16_t...). + */ +#ifndef LWIP_NO_STDINT_H +#define LWIP_NO_STDINT_H 0 +#endif + +/* Define generic types used in lwIP */ +#if !LWIP_NO_STDINT_H +#include +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef uintptr_t mem_ptr_t; +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the inttypes.h header. You need to define the format strings listed in + * lwip/arch.h yourself in this case (X8_F, U16_F...). + */ +#ifndef LWIP_NO_INTTYPES_H +#define LWIP_NO_INTTYPES_H 0 +#endif + +/* Define (sn)printf formatters for these lwIP types */ +#if !LWIP_NO_INTTYPES_H +#include +#ifndef X8_F +#define X8_F "02" PRIx8 +#endif +#ifndef U16_F +#define U16_F PRIu16 +#endif +#ifndef S16_F +#define S16_F PRId16 +#endif +#ifndef X16_F +#define X16_F PRIx16 +#endif +#ifndef U32_F +#define U32_F PRIu32 +#endif +#ifndef S32_F +#define S32_F PRId32 +#endif +#ifndef X32_F +#define X32_F PRIx32 +#endif +#ifndef SZT_F +#define SZT_F PRIuPTR +#endif +#endif + +/** Define this to 1 in arch/cc.h of your port if your compiler does not provide + * the limits.h header. You need to define the type limits yourself in this case + * (e.g. INT_MAX). + */ +#ifndef LWIP_NO_LIMITS_H +#define LWIP_NO_LIMITS_H 0 +#endif + +/* Include limits.h? */ +#if !LWIP_NO_LIMITS_H +#include +#endif + +/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ +#ifndef LWIP_CONST_CAST +#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) +#endif + +/** Get rid of alignment cast warnings (GCC -Wcast-align) */ +#ifndef LWIP_ALIGNMENT_CAST +#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, + * e.g. "conversion from 'u8_t' to 'void *' of greater size" + */ +#ifndef LWIP_PTR_NUMERIC_CAST +#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) +#endif + +/** Allocates a memory buffer of specified size that is of sufficient size to align + * its start address using LWIP_MEM_ALIGN. + * You can declare your own version here e.g. to enforce alignment without adding + * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement + * requirements.\n + * e.g. if you use gcc and need 32 bit alignment:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n + * or more portable:\n + * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] + */ +#ifndef LWIP_DECLARE_MEMORY_ALIGNED +#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] +#endif + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** Packed structs support. + * Placed BEFORE declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +/** Packed structs support. + * Placed AFTER declaration of a packed struct.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +/** Packed structs support. + * Placed between end of declaration of a packed struct and trailing semicolon.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_STRUCT +#if defined(__GNUC__) || defined(__clang__) +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#else +#define PACK_STRUCT_STRUCT +#endif +#endif /* PACK_STRUCT_STRUCT */ + +/** Packed structs support. + * Wraps u32_t and u16_t members.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + +/** Packed structs support. + * Wraps u8_t members, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_8 +#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_8 */ + +/** Packed structs support. + * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifndef PACK_STRUCT_FLD_S +#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) +#endif /* PACK_STRUCT_FLD_S */ + +/** Packed structs support using \#include files before and after struct to be packed.\n + * The file included BEFORE the struct is "arch/bpstruct.h".\n + * The file included AFTER the struct is "arch/epstruct.h".\n + * This can be used to implement struct packing on MS Visual C compilers, see + * the Win32 port in the lwIP contrib repository for reference. + * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n + * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. + */ +#ifdef __DOXYGEN__ +#define PACK_STRUCT_USE_INCLUDES +#endif + +/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ARCH_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/autoip.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/autoip.h new file mode 100644 index 0000000000..1d85bccff8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/autoip.h @@ -0,0 +1,99 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_AUTOIP_H +#define LWIP_HDR_AUTOIP_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +/* #include "lwip/udp.h" */ +#include "lwip/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/** AutoIP state information per netif */ +struct autoip +{ + /** the currently selected, probed, announced or used LL IP-Address */ + ip4_addr_t llipaddr; + /** current AutoIP state machine state */ + u8_t state; + /** sent number of probes or announces, dependent on state */ + u8_t sent_num; + /** ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u16_t ttw; + /** ticks until a conflict can be solved by defending */ + u8_t lastconflict; + /** total number of probed/used Link Local IP-Addresses */ + u8_t tried_llipaddr; +}; + + +void autoip_set_struct(struct netif *netif, struct autoip *autoip); +/** Remove a struct autoip previously set to the netif using autoip_set_struct() */ +#define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) +err_t autoip_start(struct netif *netif); +err_t autoip_stop(struct netif *netif); +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); +void autoip_tmr(void); +void autoip_network_changed(struct netif *netif); +u8_t autoip_supplied_address(const struct netif *netif); + +/* for lwIP internal use by ip4.c */ +u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr); + +#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_AUTOIP */ + +#endif /* LWIP_HDR_AUTOIP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/debug.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/debug.h new file mode 100644 index 0000000000..a142f1cff3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/debug.h @@ -0,0 +1,167 @@ +/** + * @file + * Debug messages infrastructure + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_DEBUG_H +#define LWIP_HDR_DEBUG_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +/** + * @defgroup debugging_levels LWIP_DBG_MIN_LEVEL and LWIP_DBG_TYPES_ON values + * @ingroup lwip_opts_debugmsg + * @{ + */ + +/** @name Debug level (LWIP_DBG_MIN_LEVEL) + * @{ + */ +/** Debug level: ALL messages*/ +#define LWIP_DBG_LEVEL_ALL 0x00 +/** Debug level: Warnings. bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_WARNING 0x01 +/** Debug level: Serious. memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 +/** Debug level: Severe */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +/** + * @} + */ + +#define LWIP_DBG_MASK_LEVEL 0x03 +/* compatibility define only */ +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL + +/** @name Enable/disable debug messages completely (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U +/** + * @} + */ + +/** @name Debug message types (LWIP_DBG_TYPES_ON) + * @{ + */ +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup lwip_assertions Assertion handling + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_NOASSERT: Disable LWIP_ASSERT checks: + * To disable assertions define LWIP_NOASSERT in arch/cc.h. + */ +#ifdef __DOXYGEN__ +#define LWIP_NOASSERT +#undef LWIP_NOASSERT +#endif +/** + * @} + */ + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \ + LWIP_PLATFORM_ASSERT(message); }} while(0) +#ifndef LWIP_PLATFORM_ASSERT +#error "If you want to use LWIP_ASSERT, LWIP_PLATFORM_ASSERT(message) needs to be defined in your arch/cc.h" +#endif +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +#ifndef LWIP_ERROR +#ifndef LWIP_NOASSERT +#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_ASSERT(message) +#elif defined LWIP_DEBUG +#define LWIP_PLATFORM_ERROR(message) LWIP_PLATFORM_DIAG((message)) +#else +#define LWIP_PLATFORM_ERROR(message) +#endif + +/* if "expression" isn't true, then print "message" and execute "handler" expression */ +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ERROR(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +/** Enable debug message printing, but only if debug message type is enabled + * AND is of correct type AND is at least LWIP_DBG_LEVEL. + */ +#ifdef __DOXYGEN__ +#define LWIP_DEBUG +#undef LWIP_DEBUG +#endif + +#ifdef LWIP_DEBUG +#ifndef LWIP_PLATFORM_DIAG +#error "If you want to use LWIP_DEBUG, LWIP_PLATFORM_DIAG(message) needs to be defined in your arch/cc.h" +#endif +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* LWIP_HDR_DEBUG_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/def.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/def.h new file mode 100644 index 0000000000..aaa64c77ab --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/def.h @@ -0,0 +1,142 @@ +/** + * @file + * various utility macros + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_DEF_H +#define LWIP_HDR_DEF_H + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" +#if LWIP_PERF +#include "arch/perf.h" +#else /* LWIP_PERF */ +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ +#endif /* LWIP_PERF */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +/* Get the number of entries in an array ('x' must NOT be a pointer!) */ +#define LWIP_ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) + +/** Create u32_t value from bytes */ +#define LWIP_MAKEU32(a,b,c,d) (((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff)) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#ifndef lwip_htons +u16_t lwip_htons(u16_t x); +#endif +#define lwip_ntohs(x) lwip_htons(x) + +#ifndef lwip_htonl +u32_t lwip_htonl(u32_t x); +#endif +#define lwip_ntohl(x) lwip_htonl(x) + +/* Provide usual function names as macros for users, but this can be turned off */ +#ifndef LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0x00ffUL) << 8) | (((x) & 0xff00UL) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0x000000ffUL) << 24) | \ + (((x) & 0x0000ff00UL) << 8) | \ + (((x) & 0x00ff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +/* Functions that are not available as standard implementations. + * In cc.h, you can #define these to implementations available on + * your platform to save some code bytes if you use these functions + * in your application, too. + */ + +#ifndef lwip_itoa +/* This can be #defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform */ +void lwip_itoa(char* result, size_t bufsize, int number); +#endif +#ifndef lwip_strnicmp +/* This can be #defined to strnicmp() or strncasecmp() depending on your platform */ +int lwip_strnicmp(const char* str1, const char* str2, size_t len); +#endif +#ifndef lwip_stricmp +/* This can be #defined to stricmp() or strcasecmp() depending on your platform */ +int lwip_stricmp(const char* str1, const char* str2); +#endif +#ifndef lwip_strnstr +/* This can be #defined to strnstr() depending on your platform */ +char* lwip_strnstr(const char* buffer, const char* token, size_t n); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_DEF_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp.h new file mode 100644 index 0000000000..ac1b18e9f1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp.h @@ -0,0 +1,143 @@ +/** + * @file + * DHCP client API + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_DHCP_H +#define LWIP_HDR_DHCP_H + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_BOOT_FILE_LEN 128U + +/* AutoIP cooperation flags (struct dhcp.autoip_coop_state) */ +typedef enum { + DHCP_AUTOIP_COOP_STATE_OFF = 0, + DHCP_AUTOIP_COOP_STATE_ON = 1 +} dhcp_autoip_coop_state_enum_t; + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** track PCB allocation state */ + u8_t pcb_allocated; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + u16_t t1_renew_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next renew try */ + u16_t t2_rebind_time; /* #ticks with period DHCP_COARSE_TIMER_SECS until next rebind try */ + u16_t lease_used; /* #ticks with period DHCP_COARSE_TIMER_SECS since last received DHCP ack */ + u16_t t0_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for lease time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease (ip_addr_t because passed to UDP) */ + ip4_addr_t offered_ip_addr; + ip4_addr_t offered_sn_mask; + ip4_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 87.5 of lease period) */ +#if LWIP_DHCP_BOOTP_FILE + ip4_addr_t offered_si_addr; + char boot_file_name[DHCP_BOOT_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); +err_t dhcp_start(struct netif *netif); +err_t dhcp_renew(struct netif *netif); +err_t dhcp_release(struct netif *netif); +void dhcp_stop(struct netif *netif); +void dhcp_inform(struct netif *netif); +void dhcp_network_changed(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, const ip4_addr_t *addr); +#endif +u8_t dhcp_supplied_address(const struct netif *netif); +/* to be called every minute */ +void dhcp_coarse_tmr(void); +/* to be called every half second */ +void dhcp_fine_tmr(void); + +#if LWIP_DHCP_GET_NTP_SRV +/** This function must exist, in other to add offered NTP servers to + * the NTP (or SNTP) engine. + * See LWIP_DHCP_MAX_NTP_SERVERS */ +extern void dhcp_set_ntp_servers(u8_t num_ntp_servers, const ip4_addr_t* ntp_server_addrs); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#define netif_dhcp_data(netif) ((struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*LWIP_HDR_DHCP_H*/ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp6.h new file mode 100644 index 0000000000..455336d37d --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dhcp6.h @@ -0,0 +1,58 @@ +/** + * @file + * + * IPv6 address autoconfiguration as per RFC 4862. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * IPv6 address autoconfiguration as per RFC 4862. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_IP6_DHCP6_H +#define LWIP_HDR_IP6_DHCP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + + +struct dhcp6 +{ + /*@todo: implement DHCP6*/ +}; + +#endif /* LWIP_IPV6_DHCP6 */ + +#endif /* LWIP_HDR_IP6_DHCP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dns.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dns.h new file mode 100644 index 0000000000..1453d72341 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/dns.h @@ -0,0 +1,130 @@ +/** + * @file + * DNS API + */ + +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_DNS_H +#define LWIP_HDR_DNS_H + +#include "lwip/opt.h" + +#if LWIP_DNS + +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/* DNS resolve types: */ +#define LWIP_DNS_ADDRTYPE_IPV4 0 +#define LWIP_DNS_ADDRTYPE_IPV6 1 +#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#if LWIP_IPV4 && LWIP_IPV6 +#ifndef LWIP_DNS_ADDRTYPE_DEFAULT +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4_IPV6 +#endif +#elif LWIP_IPV4 +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV4 +#else +#define LWIP_DNS_ADDRTYPE_DEFAULT LWIP_DNS_ADDRTYPE_IPV6 +#endif + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#define DNS_LOCAL_HOSTLIST_ELEM(name, addr_init) {name, addr_init, NULL} +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#if LWIP_IPV4 +extern const ip_addr_t dns_mquery_v4group; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 +extern const ip_addr_t dns_mquery_v6group; +#endif /* LWIP_IPV6 */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, const ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver); +const ip_addr_t* dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); +err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg, + u8_t dns_addrtype); + + +#if DNS_LOCAL_HOSTLIST +size_t dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg); +err_t dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype); +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* LWIP_HDR_DNS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/err.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/err.h new file mode 100644 index 0000000000..84e528d1ed --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/err.h @@ -0,0 +1,119 @@ +/** + * @file + * lwIP Error codes + */ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERR_H +#define LWIP_HDR_ERR_H + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup infrastructure_errors Error codes + * @ingroup infrastructure + * @{ + */ + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/** Definitions for error constants. */ +typedef enum { +/** No error, everything OK. */ + ERR_OK = 0, +/** Out of memory error. */ + ERR_MEM = -1, +/** Buffer error. */ + ERR_BUF = -2, +/** Timeout. */ + ERR_TIMEOUT = -3, +/** Routing problem. */ + ERR_RTE = -4, +/** Operation in progress */ + ERR_INPROGRESS = -5, +/** Illegal value. */ + ERR_VAL = -6, +/** Operation would block. */ + ERR_WOULDBLOCK = -7, +/** Address in use. */ + ERR_USE = -8, +/** Already connecting. */ + ERR_ALREADY = -9, +/** Conn already established.*/ + ERR_ISCONN = -10, +/** Not connected. */ + ERR_CONN = -11, +/** Low-level netif error */ + ERR_IF = -12, + +/** Connection aborted. */ + ERR_ABRT = -13, +/** Connection reset. */ + ERR_RST = -14, +/** Connection closed. */ + ERR_CLSD = -15, +/** Illegal argument. */ + ERR_ARG = -16 +} err_enum_t; + +#define ERR_IS_FATAL(e) ((e) <= ERR_ABRT) + +/** + * @} + */ + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#if !NO_SYS +int err_to_errno(err_t err); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERR_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/errno.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/errno.h new file mode 100644 index 0000000000..641cffb09c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/errno.h @@ -0,0 +1,193 @@ +/** + * @file + * Posix Errno defines + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ERRNO_H +#define LWIP_HDR_ERRNO_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +#ifndef errno +extern int errno; +#endif + +#else /* LWIP_PROVIDE_ERRNO */ + +/* Define LWIP_ERRNO_INCLUDE to to include the error defines here */ +#ifdef LWIP_ERRNO_INCLUDE +#include LWIP_ERRNO_INCLUDE +#endif /* LWIP_ERRNO_INCLUDE */ + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ERRNO_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/etharp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/etharp.h new file mode 100644 index 0000000000..7080a19d05 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/etharp.h @@ -0,0 +1,106 @@ +/** + * @file + * Ethernet output function - handles OUTGOING ethernet level traffic, implements + * ARP resolving. + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHARP_H +#define LWIP_HDR_NETIF_ETHARP_H + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/prot/etharp.h" + +/** 1 seconds period */ +#define ARP_TMR_INTERVAL 1000 + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct etharp_q_entry { + struct etharp_q_entry *next; + struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, no init needed. */ +void etharp_tmr(void); +s8_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, + struct eth_addr **eth_ret, const ip4_addr_t **ip_ret); +u8_t etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret); +err_t etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +err_t etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, const ip4_addr_t *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + * this is an ARP packet sent by a node in order to spontaneously cause other + * nodes to update an entry in their ARP cache. + * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), netif_ip4_addr(netif)) +void etharp_cleanup_netif(struct netif *netif); + +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr); +err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + +#endif /* LWIP_IPV4 && LWIP_ARP */ + +void etharp_input(struct pbuf *p, struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#endif /* LWIP_HDR_NETIF_ETHARP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ethip6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ethip6.h new file mode 100644 index 0000000000..5e88dffd05 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ethip6.h @@ -0,0 +1,68 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ETHIP6_H +#define LWIP_HDR_ETHIP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +err_t ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + +#endif /* LWIP_HDR_ETHIP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp.h new file mode 100644 index 0000000000..f5a31fd4c0 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp.h @@ -0,0 +1,110 @@ +/** + * @file + * ICMP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_ICMP_H +#define LWIP_HDR_ICMP_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp.h" + +#if LWIP_IPV6 && LWIP_ICMP6 +#include "lwip/icmp6.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP destination unreachable codes */ +enum icmp_dur_type { + /** net unreachable */ + ICMP_DUR_NET = 0, + /** host unreachable */ + ICMP_DUR_HOST = 1, + /** protocol unreachable */ + ICMP_DUR_PROTO = 2, + /** port unreachable */ + ICMP_DUR_PORT = 3, + /** fragmentation needed and DF set */ + ICMP_DUR_FRAG = 4, + /** source route failed */ + ICMP_DUR_SR = 5 +}; + +/** ICMP time exceeded codes */ +enum icmp_te_type { + /** time to live exceeded in transit */ + ICMP_TE_TTL = 0, + /** fragment reassembly time exceeded */ + ICMP_TE_FRAG = 1 +}; + +#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp); +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#endif /* LWIP_IPV4 && LWIP_ICMP */ + +#if LWIP_IPV4 && LWIP_IPV6 +#if LWIP_ICMP && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ + icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ + icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) +#elif LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) do{ if(!(isipv6)) { icmp_dest_unreach(pbuf, ICMP_DUR_PORT);}}while(0) +#elif LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) do{ if(isipv6) { icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT);}}while(0) +#else +#define icmp_port_unreach(isipv6, pbuf) +#endif +#elif LWIP_IPV6 && LWIP_ICMP6 +#define icmp_port_unreach(isipv6, pbuf) icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) +#elif LWIP_IPV4 && LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) +#else /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) */ +#define icmp_port_unreach(isipv6, pbuf) +#endif /* (LWIP_IPV6 && LWIP_ICMP6) || (LWIP_IPV4 && LWIP_ICMP) LWIP_IPV4*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ICMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp6.h new file mode 100644 index 0000000000..a29dc8c1c2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/icmp6.h @@ -0,0 +1,70 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_ICMP6_H +#define LWIP_HDR_ICMP6_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" +#include "lwip/prot/icmp6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +void icmp6_input(struct pbuf *p, struct netif *inp); +void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); +void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); +void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); +void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* LWIP_HDR_ICMP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/igmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/igmp.h new file mode 100644 index 0000000000..ffd80e680c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/igmp.h @@ -0,0 +1,115 @@ +/** + * @file + * IGMP API + */ + +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef LWIP_HDR_IGMP_H +#define LWIP_HDR_IGMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IPV4 && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* Compatibility defines (don't use for new code) */ +#define IGMP_DEL_MAC_FILTER NETIF_DEL_MAC_FILTER +#define IGMP_ADD_MAC_FILTER NETIF_ADD_MAC_FILTER + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** multicast address */ + ip4_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void); +err_t igmp_start(struct netif *netif); +err_t igmp_stop(struct netif *netif); +void igmp_report_groups(struct netif *netif); +struct igmp_group *igmp_lookfor_group(struct netif *ifp, const ip4_addr_t *addr); +void igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest); +err_t igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_joingroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr); +err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr); +void igmp_tmr(void); + +/** @ingroup igmp + * Get list head of IGMP groups for netif. + * Note: The allsystems group IP is contained in the list as first entry. + * @see @ref netif_set_igmp_mac_filter() + */ +#define netif_igmp_data(netif) ((struct igmp_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 && LWIP_IGMP */ + +#endif /* LWIP_HDR_IGMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet.h new file mode 100644 index 0000000000..4a34f02653 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet.h @@ -0,0 +1,172 @@ +/** + * @file + * This file (together with sockets.h) aims to provide structs and functions from + * - arpa/inet.h + * - netinet/in.h + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_H +#define LWIP_HDR_INET_H + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) +typedef u32_t in_addr_t; +#endif + +struct in_addr { + in_addr_t s_addr; +}; + +struct in6_addr { + union { + u32_t u32_addr[4]; + u8_t u8_addr[16]; + } un; +#define s6_addr un.u8_addr +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 wildcard address. */ +#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} +/** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 loopback address. */ +#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} +/** This variable is initialized by the system to contain the wildcard IPv6 address. */ +extern const struct in6_addr in6addr_any; + +/* Definitions of the bits in an (IPv4) Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX +#endif +#if LWIP_IPV6 +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX +#endif +#endif + +#if LWIP_IPV4 + +#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip4_addr_t are an u32_t effectively! */ +#define inet_addr_to_ip4addr_p(target_ip4addr_p, source_inaddr) ((target_ip4addr_p) = (ip4_addr_t*)&((source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) +#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ + (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3];} +/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ +#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) + +/* directly map this to the lwip internal functions */ +#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) +#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) +#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) + +#endif /* LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet_chksum.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet_chksum.h new file mode 100644 index 0000000000..4e23d7f194 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/inet_chksum.h @@ -0,0 +1,105 @@ +/** + * @file + * IP checksum calculation functions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INET_CHKSUM_H +#define LWIP_HDR_INET_CHKSUM_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like lwip_htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +# ifndef LWIP_CHKSUM_COPY +# define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +# ifndef LWIP_CHKSUM_COPY_ALGORITHM +# define LWIP_CHKSUM_COPY_ALGORITHM 1 +# endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +# else /* LWIP_CHKSUM_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +# endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +# define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(const void *dataptr, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#if LWIP_IPV4 +u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip4_addr_t *src, const ip4_addr_t *dest); +u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, + u16_t proto_len, u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest); +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip6_addr_t *src, const ip6_addr_t *dest); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest); +#endif /* LWIP_IPV6 */ + + +u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + const ip_addr_t *src, const ip_addr_t *dest); +u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INET_H */ + diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/init.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/init.h new file mode 100644 index 0000000000..940fa21aff --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/init.h @@ -0,0 +1,100 @@ +/** + * @file + * lwIP initialization API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_INIT_H +#define LWIP_HDR_INIT_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup lwip_version Version + * @ingroup lwip + * @{ + */ + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 2 +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 0 +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 2 +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (Git), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC LWIP_RC_RELEASE + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255 +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for Git versions */ +#define LWIP_RC_DEVELOPMENT 0 + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/* Some helper defines to get a version string */ +#define LWIP_VERSTR2(x) #x +#define LWIP_VERSTR(x) LWIP_VERSTR2(x) +#if LWIP_VERSION_IS_RELEASE +#define LWIP_VERSION_STRING_SUFFIX "" +#elif LWIP_VERSION_IS_DEVELOPMENT +#define LWIP_VERSION_STRING_SUFFIX "d" +#else +#define LWIP_VERSION_STRING_SUFFIX "rc" LWIP_VERSTR(LWIP_VERSION_RC) +#endif + +/** Provides the version of the stack */ +#define LWIP_VERSION (((u32_t)LWIP_VERSION_MAJOR) << 24 | ((u32_t)LWIP_VERSION_MINOR) << 16 | \ + ((u32_t)LWIP_VERSION_REVISION) << 8 | ((u32_t)LWIP_VERSION_RC)) +/** Provides the version of the stack as string */ +#define LWIP_VERSION_STRING LWIP_VERSTR(LWIP_VERSION_MAJOR) "." LWIP_VERSTR(LWIP_VERSION_MINOR) "." LWIP_VERSTR(LWIP_VERSION_REVISION) LWIP_VERSION_STRING_SUFFIX + +/** + * @} + */ + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_INIT_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip.h new file mode 100644 index 0000000000..0673be9b4a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip.h @@ -0,0 +1,319 @@ +/** + * @file + * IP API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_H +#define LWIP_HDR_IP_H + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/ip6.h" +#include "lwip/prot/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#define LWIP_IP_HDRINCL NULL + +/** pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ +#ifndef LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX +#define LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p) LWIP_ASSERT("p->ref == 1", (p)->ref == 1) +#endif + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/** This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX in sockets.h + */ +#define SOF_REUSEADDR 0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE 0x08U /* keep connections alive */ +#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE) + +/** Global variables of this module, kept in a struct for efficient access using base+index. */ +struct ip_globals +{ + /** The interface that accepted the packet for the current callback invocation. */ + struct netif *current_netif; + /** The interface that received the packet for the current callback invocation. */ + struct netif *current_input_netif; +#if LWIP_IPV4 + /** Header of the input packet currently being processed. */ + struct ip_hdr *current_ip4_header; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Header of the input IPv6 packet currently being processed. */ + struct ip6_hdr *current_ip6_header; +#endif /* LWIP_IPV6 */ + /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ + u16_t current_ip_header_tot_len; + /** Source IP address of current_header */ + ip_addr_t current_iphdr_src; + /** Destination IP address of current_header */ + ip_addr_t current_iphdr_dest; +}; +extern struct ip_globals ip_data; + + +/** Get the interface that accepted the current packet. + * This may or may not be the receiving netif, depending on your netif/network setup. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (ip_data.current_netif) +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_input_netif() (ip_data.current_input_netif) +/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ +#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) +/** Source IP address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if LWIP_IPV4 && LWIP_IPV6 +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ((const struct ip_hdr*)(ip_data.current_ip4_header)) +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ +#define ip_current_is_v6() (ip6_current_header() != NULL) +/** Source IPv6 address of current_header */ +#define ip6_current_src_addr() (ip_2_ip6(&ip_data.current_iphdr_src)) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (ip_2_ip6(&ip_data.current_iphdr_dest)) +/** Get the transport layer protocol */ +#define ip_current_header_proto() (ip_current_is_v6() ? \ + IP6H_NEXTH(ip6_current_header()) :\ + IPH_PROTO(ip4_current_header())) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((ip_current_is_v6() ? \ + (const u8_t*)ip6_current_header() : (const u8_t*)ip4_current_header()) + ip_current_header_tot_len())) + +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (ip_2_ip4(&ip_data.current_iphdr_src)) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (ip_2_ip4(&ip_data.current_iphdr_dest)) + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv4 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip4_current_header() ((const struct ip_hdr*)(ip_data.current_ip4_header)) +/** Always returns FALSE when only supporting IPv4 only */ +#define ip_current_is_v6() 0 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IPH_PROTO(ip4_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((const u8_t*)ip4_current_header() + ip_current_header_tot_len())) +/** Source IP4 address of current_header */ +#define ip4_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP4 address of current_header */ +#define ip4_current_dest_addr() (&ip_data.current_iphdr_dest) + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() ((const struct ip6_hdr*)(ip_data.current_ip6_header)) +/** Always returns TRUE when only supporting IPv6 only */ +#define ip_current_is_v6() 1 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IP6H_NEXTH(ip6_current_header()) +/** Get the transport layer header */ +#define ip_next_header_ptr() ((const void*)((const u8_t*)ip6_current_header())) +/** Source IP6 address of current_header */ +#define ip6_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP6 address of current_header */ +#define ip6_current_dest_addr() (&ip_data.current_iphdr_dest) + +#endif /* LWIP_IPV6 */ + +/** Union source address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Union destination address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +/** Gets an IP pcb option (SOF_* flags) */ +#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt)) +/** Sets an IP pcb option (SOF_* flags) */ +#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt)) +/** Resets an IP pcb option (SOF_* flags) */ +#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ip + * Output IP packet, netif is selected by source address + */ +#define ip_output(p, src, dest, ttl, tos, proto) \ + (IP_IS_V6(dest) ? \ + ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ + ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto)) +/** + * @ingroup ip + * Output IP packet to specified interface + */ +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** + * @ingroup ip + * Output IP packet to interface specifying source address + */ +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip4_output_if_src(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** Output IP packet with addr_hint */ +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + (IP_IS_V6(dest) ? \ + ip6_output_hinted(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, addr_hint) : \ + ip4_output_hinted(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, addr_hint)) +/** + * @ingroup ip + * Get netif for address combination. See \ref ip6_route and \ref ip4_route + */ +#define ip_route(src, dest) \ + (IP_IS_V6(dest) ? \ + ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \ + ip4_route_src(ip_2_ip4(dest), ip_2_ip4(src))) +/** + * @ingroup ip + * Get netif for IP. + */ +#define ip_netif_get_local_ip(netif, dest) (IP_IS_V6(dest) ? \ + ip6_netif_get_local_ip(netif, ip_2_ip6(dest)) : \ + ip4_netif_get_local_ip(netif)) +#define ip_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip4_debug_print(p)) + +err_t ip_input(struct pbuf *p, struct netif *inp); + +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip4_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip4_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + ip4_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_route(src, dest) \ + ip4_route_src(dest, src) +#define ip_netif_get_local_ip(netif, dest) \ + ip4_netif_get_local_ip(netif) +#define ip_debug_print(is_ipv6, p) ip4_debug_print(p) + +#define ip_input ip4_input + +#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ + +#define ip_output(p, src, dest, ttl, tos, proto) \ + ip6_output(p, src, dest, ttl, tos, proto) +#define ip_output_if(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if(p, src, dest, ttl, tos, proto, netif) +#define ip_output_if_src(p, src, dest, ttl, tos, proto, netif) \ + ip6_output_if_src(p, src, dest, ttl, tos, proto, netif) +#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ + ip6_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_route(src, dest) \ + ip6_route(src, dest) +#define ip_netif_get_local_ip(netif, dest) \ + ip6_netif_get_local_ip(netif, dest) +#define ip_debug_print(is_ipv6, p) ip6_debug_print(p) + +#define ip_input ip6_input + +#endif /* LWIP_IPV6 */ + +#define ip_route_get_local_ip(src, dest, netif, ipaddr) do { \ + (netif) = ip_route(src, dest); \ + (ipaddr) = ip_netif_get_local_ip(netif, dest); \ +}while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4.h new file mode 100644 index 0000000000..48246ecc25 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4.h @@ -0,0 +1,111 @@ +/** + * @file + * IPv4 API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_H +#define LWIP_HDR_IP4_H + +#include "lwip/opt.h" + +#if LWIP_IPV4 + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip4_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/prot/ip4.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +#define LWIP_IPV4_SRC_ROUTING 1 +#else +#define LWIP_IPV4_SRC_ROUTING 0 +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP) + +#define ip_init() /* Compatibility define, no init needed. */ +struct netif *ip4_route(const ip4_addr_t *dest); +#if LWIP_IPV4_SRC_ROUTING +struct netif *ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src); +#else /* LWIP_IPV4_SRC_ROUTING */ +#define ip4_route_src(dest, src) ip4_route(dest) +#endif /* LWIP_IPV4_SRC_ROUTING */ +err_t ip4_input(struct pbuf *p, struct netif *inp); +err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto); +err_t ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); +#endif /* IP_OPTIONS_SEND */ + +#if LWIP_MULTICAST_TX_OPTIONS +void ip4_set_default_multicast_netif(struct netif* default_multicast_netif); +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#define ip4_netif_get_local_ip(netif) (((netif) != NULL) ? netif_ip_addr4(netif) : NULL) + +#if IP_DEBUG +void ip4_debug_print(struct pbuf *p); +#else +#define ip4_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_H */ + + diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_addr.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_addr.h new file mode 100644 index 0000000000..51b46b8d4c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_addr.h @@ -0,0 +1,227 @@ +/** + * @file + * IPv4 address API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP4_ADDR_H +#define LWIP_HDR_IP4_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the aligned version of ip4_addr_t, + used as local variable, on the stack, etc. */ +struct ip4_addr { + u32_t addr; +}; + +/** ip4_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip4_addr_t as well as on ip4_addr_p_t. */ +typedef struct ip4_addr ip4_addr_t; + +/** + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Forward declaration to not include netif.h */ +struct netif; + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) (ipaddr)->addr = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t)) +#endif + +/** Copy IP address - faster than ip4_addr_set: no NULL check */ +#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip4_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for lwip_htonl()) */ +#define ip4_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip4_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Check if an address is in the loopback region */ +#define ip4_addr_isloopback(ipaddr) (((ipaddr)->addr & PP_HTONL(IP_CLASSA_NET)) == PP_HTONL(((u32_t)IP_LOOPBACKNET) << 24)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip4_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + lwip_htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip4_addr_get_network(target, host, netmask) do { ((target)->addr = ((host)->addr) & ((netmask)->addr)); } while(0) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip4_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY) +#define ip4_addr_isany(addr1) ((addr1) == NULL || ip4_addr_isany_val(*(addr1))) + +#define ip4_addr_isbroadcast(addr1, netif) ip4_addr_isbroadcast_u32((addr1)->addr, netif) +u8_t ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif); + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask); + +#define ip4_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip4_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip4_addr_debug_print_parts(debug, a, b, c, d) \ + LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d)) +#define ip4_addr_debug_print(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0)) +#define ip4_addr_debug_print_val(debug, ipaddr) \ + ip4_addr_debug_print_parts(debug, \ + ip4_addr1_16(&(ipaddr)), \ + ip4_addr2_16(&(ipaddr)), \ + ip4_addr3_16(&(ipaddr)), \ + ip4_addr4_16(&(ipaddr))) + +/* Get one byte from the 4-byte address */ +#define ip4_addr1(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[0]) +#define ip4_addr2(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[1]) +#define ip4_addr3(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[2]) +#define ip4_addr4(ipaddr) (((const u8_t*)(&(ipaddr)->addr))[3]) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) + +#define IP4ADDR_STRLEN_MAX 16 + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp); +int ip4addr_aton(const char *cp, ip4_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip4addr_ntoa(const ip4_addr_t *addr); +char *ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_frag.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_frag.h new file mode 100644 index 0000000000..ed5bf14a31 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip4_frag.h @@ -0,0 +1,100 @@ +/** + * @file + * IP fragmentation/reassembly + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef LWIP_HDR_IP4_FRAG_H +#define LWIP_HDR_IP4_FRAG_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#if LWIP_IPV4 + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/** IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void); +void ip_reass_tmr(void); +struct pbuf * ip4_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !LWIP_NETIF_TX_SINGLE_PBUF +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV4 */ + +#endif /* LWIP_HDR_IP4_FRAG_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6.h new file mode 100644 index 0000000000..099b94fb74 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6.h @@ -0,0 +1,93 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_H +#define LWIP_HDR_IP6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); +const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest); +err_t ip6_input(struct pbuf *p, struct netif *inp); +err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth); +err_t ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip6_output_hinted(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if LWIP_IPV6_MLD +err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); +#endif /* LWIP_IPV6_MLD */ + +#define ip6_netif_get_local_ip(netif, dest) (((netif) != NULL) ? \ + ip6_select_source_address(netif, dest) : NULL) + +#if IP6_DEBUG +void ip6_debug_print(struct pbuf *p); +#else +#define ip6_debug_print(p) +#endif /* IP6_DEBUG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_addr.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_addr.h new file mode 100644 index 0000000000..ee381aeb23 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_addr.h @@ -0,0 +1,285 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Structs and macros for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_ADDR_H +#define LWIP_HDR_IP6_ADDR_H + +#include "lwip/opt.h" +#include "def.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** This is the aligned version of ip6_addr_t, + used as local variable, on the stack, etc. */ +struct ip6_addr { + u32_t addr[4]; +}; + +/** IPv6 address */ +typedef struct ip6_addr ip6_addr_t; + +/** Set an IPv6 partial address given by byte-parts */ +#define IP6_ADDR_PART(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = PP_HTONL(LWIP_MAKEU32(a,b,c,d)) + +/** Set a full IPv6 address by passing the 4 u32_t indices in network byte order + (use PP_HTONL() for constants) */ +#define IP6_ADDR(ip6addr, idx0, idx1, idx2, idx3) do { \ + (ip6addr)->addr[0] = idx0; \ + (ip6addr)->addr[1] = idx1; \ + (ip6addr)->addr[2] = idx2; \ + (ip6addr)->addr[3] = idx3; } while(0) + +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[0])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[1])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[2])) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3]) >> 16) & 0xffff)) +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)((lwip_htonl((ip6addr)->addr[3])) & 0xffff)) + +/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) +/** Safely copy one IPv6 address to another (src may be NULL) */ +#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) + +/** Set complete address to zero */ +#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = 0;}while(0) + +/** Set address to ipv6 'any' (no need for lwip_htonl()) */ +#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) +/** Set address to ipv6 loopback address */ +#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) +/** Safely copy one IPv6 address to another and change byte order + * from host- to network-order. */ +#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : lwip_htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : lwip_htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : lwip_htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : lwip_htonl((src)->addr[3]);}while(0) + + +/** + * Determine if two IPv6 address are on the same network. + * + * @arg addr1 IPv6 address 1 + * @arg addr2 IPv6 address 2 + * @return !0 if the network identifiers of both address match + */ +#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1])) + +#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) + +#define ip6_get_subnet_id(ip6addr) (lwip_htonl((ip6addr)->addr[2]) & 0x0000ffffUL) + +#define ip6_addr_isany_val(ip6addr) (((ip6addr).addr[0] == 0) && \ + ((ip6addr).addr[1] == 0) && \ + ((ip6addr).addr[2] == 0) && \ + ((ip6addr).addr[3] == 0)) +#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || ip6_addr_isany_val(*(ip6addr))) + +#define ip6_addr_isloopback(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) + +#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) + +#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) + +#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) + +#define ip6_addr_isipv4mappedipv6(ip6addr) (((ip6addr)->addr[0] == 0) && ((ip6addr)->addr[1] == 0) && (((ip6addr)->addr[2]) == PP_HTONL(0x0000FFFFUL))) + +#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) +#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) +#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) +#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) +#define ip6_addr_multicast_scope(ip6addr) ((lwip_htonl((ip6addr)->addr[0]) >> 16) & 0xf) +#define IP6_MULTICAST_SCOPE_RESERVED 0x0 +#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 +#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 +#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 +#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 +#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 +#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 +#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IP6_MULTICAST_SCOPE_GLOBAL 0xe +#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf +#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff010000UL)) +#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff020000UL)) +#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff040000UL)) +#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff050000UL)) +#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff080000UL)) +#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff8f0000UL)) == PP_HTONL(0xff0e0000UL)) + +/* @todo define get/set for well-know multicast addresses, e.g. ff02::1 */ +#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) +#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) + +#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) +#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0) + +#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) + +#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ + (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id));}while(0) + +#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) + +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */ +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */ + +#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */ + +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) + +#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \ + LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \ + a, b, c, d, e, f, g, h)) +#define ip6_addr_debug_print(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0), \ + (u16_t)((ipaddr) != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) +#define ip6_addr_debug_print_val(debug, ipaddr) \ + ip6_addr_debug_print_parts(debug, \ + IP6_ADDR_BLOCK1(&(ipaddr)), \ + IP6_ADDR_BLOCK2(&(ipaddr)), \ + IP6_ADDR_BLOCK3(&(ipaddr)), \ + IP6_ADDR_BLOCK4(&(ipaddr)), \ + IP6_ADDR_BLOCK5(&(ipaddr)), \ + IP6_ADDR_BLOCK6(&(ipaddr)), \ + IP6_ADDR_BLOCK7(&(ipaddr)), \ + IP6_ADDR_BLOCK8(&(ipaddr))) + +#define IP6ADDR_STRLEN_MAX 46 + +int ip6addr_aton(const char *cp, ip6_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip6addr_ntoa(const ip6_addr_t *addr); +char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); + + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_IP6_ADDR_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_frag.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_frag.h new file mode 100644 index 0000000000..6be274734b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip6_frag.h @@ -0,0 +1,120 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef LWIP_HDR_IP6_FRAG_H +#define LWIP_HDR_IP6_FRAG_H + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + +/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, this needs to + * be enabled (to not overwrite part of the data). When enabled, the IPv6 header + * is copied instead of referencing it, which gives more room for struct ip6_reass_helper */ +#ifndef IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_COPYHEADER 0 +#endif + +/** The IPv6 reassembly timer interval in milliseconds. */ +#define IP6_REASS_TMR_INTERVAL 1000 + +/* Copy the complete header of the first fragment to struct ip6_reassdata + or just point to its original location in the first pbuf? */ +#if IPV6_FRAG_COPYHEADER +#define IPV6_FRAG_HDRPTR +#define IPV6_FRAG_HDRREF(hdr) (&(hdr)) +#else /* IPV6_FRAG_COPYHEADER */ +#define IPV6_FRAG_HDRPTR * +#define IPV6_FRAG_HDRREF(hdr) (hdr) +#endif /* IPV6_FRAG_COPYHEADER */ + +/** IPv6 reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip6_reassdata { + struct ip6_reassdata *next; + struct pbuf *p; + struct ip6_hdr IPV6_FRAG_HDRPTR iphdr; + u32_t identification; + u16_t datagram_len; + u8_t nexth; + u8_t timer; +}; + +#define ip6_reass_init() /* Compatibility define */ +void ip6_reass_tmr(void); +struct pbuf *ip6_reass(struct pbuf *p); + +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ + +#ifndef LWIP_PBUF_CUSTOM_REF_DEFINED +#define LWIP_PBUF_CUSTOM_REF_DEFINED +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ + +err_t ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest); + +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP6_FRAG_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip_addr.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip_addr.h new file mode 100644 index 0000000000..11f65d25bd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/ip_addr.h @@ -0,0 +1,407 @@ +/** + * @file + * IP address API (common IPv4 and IPv6) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_IP_ADDR_H +#define LWIP_HDR_IP_ADDR_H + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include "lwip/ip4_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup ipaddr + * IP address types for use in ip_addr_t.type member. + * @see tcp_new_ip_type(), udp_new_ip_type(), raw_new_ip_type(). + */ +enum lwip_ip_addr_type { + /** IPv4 */ + IPADDR_TYPE_V4 = 0U, + /** IPv6 */ + IPADDR_TYPE_V6 = 6U, + /** IPv4+IPv6 ("dual-stack") */ + IPADDR_TYPE_ANY = 46U +}; + +#if LWIP_IPV4 && LWIP_IPV6 +/** + * @ingroup ipaddr + * A union struct for both IP version's addresses. + * ATTENTION: watch out for its size when adding IPv6 address scope! + */ +typedef struct ip_addr { + union { + ip6_addr_t ip6; + ip4_addr_t ip4; + } u_addr; + /** @ref lwip_ip_addr_type */ + u8_t type; +} ip_addr_t; + +extern const ip_addr_t ip_addr_any_type; + +/** @ingroup ip4addr */ +#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_V4 } +/** @ingroup ip4addr */ +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) +/** @ingroup ip6addr */ +#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 } +/** @ingroup ip6addr */ +#define IPADDR6_INIT_HOST(a, b, c, d) { { { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } } }, IPADDR_TYPE_V6 } + +/** @ingroup ipaddr */ +#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY) +/** @ingroup ipaddr */ +#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_ANY } + +/** @ingroup ip4addr */ +#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4) +/** @ingroup ip6addr */ +#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6) +/** @ingroup ip4addr */ +#define IP_IS_V4(ipaddr) (((ipaddr) == NULL) || IP_IS_V4_VAL(*(ipaddr))) +/** @ingroup ip6addr */ +#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr))) + +#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0) +#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0) +#define IP_GET_TYPE(ipaddr) ((ipaddr)->type) + +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr)) +#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) + +/** @ingroup ip6addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6)) +/** @ingroup ip4addr + * Convert generic ip address to specific protocol version + */ +#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4)) + +/** @ingroup ip4addr */ +#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \ + IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0) +/** @ingroup ip6addr */ +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +/** @ingroup ipaddr */ +#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); }}while(0) +/** @ingroup ip6addr */ +#define ip_addr_copy_from_ip6(dest, src) do{ \ + ip6_addr_copy(*ip_2_ip6(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V6); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_copy_from_ip4(dest, src) do{ \ + ip4_addr_copy(*ip_2_ip4(&(dest)), src); IP_SET_TYPE_VAL(dest, IPADDR_TYPE_V4); }while(0) +/** @ingroup ip4addr */ +#define ip_addr_set_ip4_u32(ipaddr, val) do{if(ipaddr){ip4_addr_set_u32(ip_2_ip4(ipaddr), val); \ + IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ip4addr */ +#define ip_addr_get_ip4_u32(ipaddr) (((ipaddr) && IP_IS_V4(ipaddr)) ? \ + ip4_addr_get_u32(ip_2_ip4(ipaddr)) : 0) +/** @ingroup ipaddr */ +#define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, IP_GET_TYPE(src)); if(IP_IS_V6(src)){ \ + ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); }else{ \ + ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_ipaddr(dest, src) ip_addr_set(dest, src) +/** @ingroup ipaddr */ +#define ip_addr_set_zero(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, 0); }while(0) +/** @ingroup ip5addr */ +#define ip_addr_set_zero_ip4(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }while(0) +/** @ingroup ip6addr */ +#define ip_addr_set_zero_ip6(ipaddr) do{ \ + ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_any(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_loopback(ip_2_ip4(ipaddr)); IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_set_hton(dest, src) do{if(IP_IS_V6(src)){ \ + ip6_addr_set_hton(ip_2_ip6(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \ + ip4_addr_set_hton(ip_2_ip4(ipaddr), (src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_get_network(target, host, netmask) do{if(IP_IS_V6(host)){ \ + ip4_addr_set_zero(ip_2_ip4(target)); IP_SET_TYPE(target, IPADDR_TYPE_V6); } else { \ + ip4_addr_get_network(ip_2_ip4(target), ip_2_ip4(host), ip_2_ip4(netmask)); IP_SET_TYPE(target, IPADDR_TYPE_V4); }}while(0) +/** @ingroup ipaddr */ +#define ip_addr_netcmp(addr1, addr2, mask) ((IP_IS_V6(addr1) && IP_IS_V6(addr2)) ? \ + 0 : \ + ip4_addr_netcmp(ip_2_ip4(addr1), ip_2_ip4(addr2), mask)) +/** @ingroup ipaddr */ +#define ip_addr_cmp(addr1, addr2) ((IP_GET_TYPE(addr1) != IP_GET_TYPE(addr2)) ? 0 : (IP_IS_V6_VAL(*(addr1)) ? \ + ip6_addr_cmp(ip_2_ip6(addr1), ip_2_ip6(addr2)) : \ + ip4_addr_cmp(ip_2_ip4(addr1), ip_2_ip4(addr2)))) +/** @ingroup ipaddr */ +#define ip_addr_isany(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isany(ip_2_ip6(ipaddr)) : \ + ip4_addr_isany(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_isany_val(ipaddr) ((IP_IS_V6_VAL(ipaddr)) ? \ + ip6_addr_isany_val(*ip_2_ip6(&(ipaddr))) : \ + ip4_addr_isany_val(*ip_2_ip4(&(ipaddr)))) +/** @ingroup ipaddr */ +#define ip_addr_isbroadcast(ipaddr, netif) ((IP_IS_V6(ipaddr)) ? \ + 0 : \ + ip4_addr_isbroadcast(ip_2_ip4(ipaddr), netif)) +/** @ingroup ipaddr */ +#define ip_addr_ismulticast(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_ismulticast(ip_2_ip6(ipaddr)) : \ + ip4_addr_ismulticast(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_isloopback(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_isloopback(ip_2_ip6(ipaddr)) : \ + ip4_addr_isloopback(ip_2_ip4(ipaddr))) +/** @ingroup ipaddr */ +#define ip_addr_islinklocal(ipaddr) ((IP_IS_V6(ipaddr)) ? \ + ip6_addr_islinklocal(ip_2_ip6(ipaddr)) : \ + ip4_addr_islinklocal(ip_2_ip4(ipaddr))) +#define ip_addr_debug_print(debug, ipaddr) do { if(IP_IS_V6(ipaddr)) { \ + ip6_addr_debug_print(debug, ip_2_ip6(ipaddr)); } else { \ + ip4_addr_debug_print(debug, ip_2_ip4(ipaddr)); }}while(0) +#define ip_addr_debug_print_val(debug, ipaddr) do { if(IP_IS_V6_VAL(ipaddr)) { \ + ip6_addr_debug_print_val(debug, *ip_2_ip6(&(ipaddr))); } else { \ + ip4_addr_debug_print_val(debug, *ip_2_ip4(&(ipaddr))); }}while(0) +/** @ingroup ipaddr */ +#define ipaddr_ntoa(addr) (((addr) == NULL) ? "NULL" : \ + ((IP_IS_V6(addr)) ? ip6addr_ntoa(ip_2_ip6(addr)) : ip4addr_ntoa(ip_2_ip4(addr)))) +/** @ingroup ipaddr */ +#define ipaddr_ntoa_r(addr, buf, buflen) (((addr) == NULL) ? "NULL" : \ + ((IP_IS_V6(addr)) ? ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen) : ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen))) +int ipaddr_aton(const char *cp, ip_addr_t *addr); + +/** @ingroup ipaddr */ +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +/** @ingroup ipaddr */ +#define ip4_2_ipv4_mapped_ipv6(ip6addr, ip4addr) do { \ + (ip6addr)->addr[3] = (ip4addr)->addr; \ + (ip6addr)->addr[2] = PP_HTONL(0x0000FFFFUL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[0] = 0; } while(0); + +/** @ingroup ipaddr */ +#define unmap_ipv4_mapped_ipv6(ip4addr, ip6addr) \ + (ip4addr)->addr = (ip6addr)->addr[3]; + +#define IP46_ADDR_ANY(type) (((type) == IPADDR_TYPE_V6)? IP6_ADDR_ANY : IP4_ADDR_ANY) + +#else /* LWIP_IPV4 && LWIP_IPV6 */ + +#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1 +#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1 + +#if LWIP_IPV4 + +typedef ip4_addr_t ip_addr_t; +#define IPADDR4_INIT(u32val) { u32val } +#define IPADDR4_INIT_BYTES(a,b,c,d) IPADDR4_INIT(PP_HTONL(LWIP_MAKEU32(a,b,c,d))) +#define IP_IS_V4_VAL(ipaddr) 1 +#define IP_IS_V6_VAL(ipaddr) 0 +#define IP_IS_V4(ipaddr) 1 +#define IP_IS_V6(ipaddr) 0 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V4 +#define ip_2_ip4(ipaddr) (ipaddr) +#define IP_ADDR4(ipaddr,a,b,c,d) IP4_ADDR(ipaddr,a,b,c,d) + +#define ip_addr_copy(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_copy_from_ip4(dest, src) ip4_addr_copy(dest, src) +#define ip_addr_set_ip4_u32(ipaddr, val) ip4_addr_set_u32(ip_2_ip4(ipaddr), val) +#define ip_addr_get_ip4_u32(ipaddr) ip4_addr_get_u32(ip_2_ip4(ipaddr)) +#define ip_addr_set(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip4_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip4(ipaddr) ip4_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip4_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip4_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip4_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip4_addr_get_network(target, host, mask) +#define ip_addr_netcmp(addr1, addr2, mask) ip4_addr_netcmp(addr1, addr2, mask) +#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2) +#define ip_addr_isany(ipaddr) ip4_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip4_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip4_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip4_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) ip4_addr_isbroadcast(addr, netif) +#define ip_addr_ismulticast(ipaddr) ip4_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip4_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip4_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip4addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip4addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip4addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP4_ADDR_ANY) + +#else /* LWIP_IPV4 */ + +typedef ip6_addr_t ip_addr_t; +#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } } +#define IPADDR6_INIT_HOST(a, b, c, d) { { PP_HTONL(a), PP_HTONL(b), PP_HTONL(c), PP_HTONL(d) } } +#define IP_IS_V4_VAL(ipaddr) 0 +#define IP_IS_V6_VAL(ipaddr) 1 +#define IP_IS_V4(ipaddr) 0 +#define IP_IS_V6(ipaddr) 1 +#define IP_IS_ANY_TYPE_VAL(ipaddr) 0 +#define IP_SET_TYPE_VAL(ipaddr, iptype) +#define IP_SET_TYPE(ipaddr, iptype) +#define IP_GET_TYPE(ipaddr) IPADDR_TYPE_V6 +#define ip_2_ip6(ipaddr) (ipaddr) +#define IP_ADDR6(ipaddr,i0,i1,i2,i3) IP6_ADDR(ipaddr,i0,i1,i2,i3) +#define IP_ADDR6_HOST(ipaddr,i0,i1,i2,i3) IP_ADDR6(ipaddr,PP_HTONL(i0),PP_HTONL(i1),PP_HTONL(i2),PP_HTONL(i3)) + +#define ip_addr_copy(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_copy_from_ip6(dest, src) ip6_addr_copy(dest, src) +#define ip_addr_set(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_ipaddr(dest, src) ip6_addr_set(dest, src) +#define ip_addr_set_zero(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_zero_ip6(ipaddr) ip6_addr_set_zero(ipaddr) +#define ip_addr_set_any(is_ipv6, ipaddr) ip6_addr_set_any(ipaddr) +#define ip_addr_set_loopback(is_ipv6, ipaddr) ip6_addr_set_loopback(ipaddr) +#define ip_addr_set_hton(dest, src) ip6_addr_set_hton(dest, src) +#define ip_addr_get_network(target, host, mask) ip6_addr_set_zero(target) +#define ip_addr_netcmp(addr1, addr2, mask) 0 +#define ip_addr_cmp(addr1, addr2) ip6_addr_cmp(addr1, addr2) +#define ip_addr_isany(ipaddr) ip6_addr_isany(ipaddr) +#define ip_addr_isany_val(ipaddr) ip6_addr_isany_val(ipaddr) +#define ip_addr_isloopback(ipaddr) ip6_addr_isloopback(ipaddr) +#define ip_addr_islinklocal(ipaddr) ip6_addr_islinklocal(ipaddr) +#define ip_addr_isbroadcast(addr, netif) 0 +#define ip_addr_ismulticast(ipaddr) ip6_addr_ismulticast(ipaddr) +#define ip_addr_debug_print(debug, ipaddr) ip6_addr_debug_print(debug, ipaddr) +#define ip_addr_debug_print_val(debug, ipaddr) ip6_addr_debug_print_val(debug, ipaddr) +#define ipaddr_ntoa(ipaddr) ip6addr_ntoa(ipaddr) +#define ipaddr_ntoa_r(ipaddr, buf, buflen) ip6addr_ntoa_r(ipaddr, buf, buflen) +#define ipaddr_aton(cp, addr) ip6addr_aton(cp, addr) + +#define IPADDR_STRLEN_MAX IP6ADDR_STRLEN_MAX + +#define IP46_ADDR_ANY(type) (IP6_ADDR_ANY) + +#endif /* LWIP_IPV4 */ +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#if LWIP_IPV4 + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IP wildcard. + * Defined to @ref IP4_ADDR_ANY when IPv4 is enabled. + * Defined to @ref IP6_ADDR_ANY in IPv6 only systems. + * Use this if you can handle IPv4 _AND_ IPv6 addresses. + * Use @ref IP4_ADDR_ANY or @ref IP6_ADDR_ANY when the IP + * type matters. + */ +#define IP_ADDR_ANY IP4_ADDR_ANY +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip_addr_t + * for the IPv4 wildcard and the broadcast address + */ +#define IP4_ADDR_ANY (&ip_addr_any) +/** + * @ingroup ip4addr + * Can be used as a fixed/const ip4_addr_t + * for the wildcard and the broadcast address + */ +#define IP4_ADDR_ANY4 (ip_2_ip4(&ip_addr_any)) + +/** @ingroup ip4addr */ +#define IP_ADDR_BROADCAST (&ip_addr_broadcast) +/** @ingroup ip4addr */ +#define IP4_ADDR_BROADCAST (ip_2_ip4(&ip_addr_broadcast)) + +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 + +extern const ip_addr_t ip6_addr_any; + +/** + * @ingroup ip6addr + * IP6_ADDR_ANY can be used as a fixed ip_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY (&ip6_addr_any) +/** + * @ingroup ip6addr + * IP6_ADDR_ANY6 can be used as a fixed ip6_addr_t + * for the IPv6 wildcard address + */ +#define IP6_ADDR_ANY6 (ip_2_ip6(&ip6_addr_any)) + +#if !LWIP_IPV4 +/** IPv6-only configurations */ +#define IP_ADDR_ANY IP6_ADDR_ANY +#endif /* !LWIP_IPV4 */ + +#endif + +#if LWIP_IPV4 && LWIP_IPV6 +/** @ingroup ipaddr */ +#define IP_ANY_TYPE (&ip_addr_any_type) +#else +#define IP_ANY_TYPE IP_ADDR_ANY +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_IP_ADDR_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mem.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mem.h new file mode 100644 index 0000000000..ff208d25c3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mem.h @@ -0,0 +1,82 @@ +/** + * @file + * Heap API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_MEM_H +#define LWIP_HDR_MEM_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include "lwip/arch.h" + +typedef size_t mem_size_t; +#define MEM_SIZE_F SZT_F + +#elif MEM_USE_POOLS + +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F + +#else + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000L +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ +#endif + +void mem_init(void); +void *mem_trim(void *mem, mem_size_t size); +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void mem_free(void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEM_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/memp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/memp.h new file mode 100644 index 0000000000..68fcd99145 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/memp.h @@ -0,0 +1,153 @@ +/** + * @file + * Memory pool API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_H +#define LWIP_HDR_MEMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* run once with empty definition to handle all custom includes in lwippools.h */ +#define LWIP_MEMPOOL(name,num,size,desc) +#include "lwip/priv/memp_std.h" + +/** Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, +#include "lwip/priv/memp_std.h" + MEMP_MAX +} memp_t; + +#include "lwip/priv/memp_priv.h" +#include "lwip/stats.h" + +extern const struct memp_desc* const memp_pools[MEMP_MAX]; + +/** + * @ingroup mempool + * Declare prototype for private memory pool if it is used in multiple files + */ +#define LWIP_MEMPOOL_PROTOTYPE(name) extern const struct memp_desc memp_ ## name + +#if MEMP_MEM_MALLOC + +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size) \ + }; + +#else /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Declare a private memory pool + * Private mempools example: + * .h: only when pool is used in multiple .c files: LWIP_MEMPOOL_PROTOTYPE(my_private_pool); + * .c: + * - in global variables section: LWIP_MEMPOOL_DECLARE(my_private_pool, 10, sizeof(foo), "Some description") + * - call ONCE before using pool (e.g. in some init() function): LWIP_MEMPOOL_INIT(my_private_pool); + * - allocate: void* my_new_mem = LWIP_MEMPOOL_ALLOC(my_private_pool); + * - free: LWIP_MEMPOOL_FREE(my_private_pool, my_new_mem); + * + * To relocate a pool, declare it as extern in cc.h. Example for GCC: + * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_my_private_pool[]; + */ +#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ + LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ + \ + LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ + \ + static struct memp *memp_tab_ ## name; \ + \ + const struct memp_desc memp_ ## name = { \ + DECLARE_LWIP_MEMPOOL_DESC(desc) \ + LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ + LWIP_MEM_ALIGN_SIZE(size), \ + (num), \ + memp_memory_ ## name ## _base, \ + &memp_tab_ ## name \ + }; + +#endif /* MEMP_MEM_MALLOC */ + +/** + * @ingroup mempool + * Initialize a private memory pool + */ +#define LWIP_MEMPOOL_INIT(name) memp_init_pool(&memp_ ## name) +/** + * @ingroup mempool + * Allocate from a private memory pool + */ +#define LWIP_MEMPOOL_ALLOC(name) memp_malloc_pool(&memp_ ## name) +/** + * @ingroup mempool + * Free element from a private memory pool + */ +#define LWIP_MEMPOOL_FREE(name, x) memp_free_pool(&memp_ ## name, (x)) + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. + * This has to be defined here as it is required for pool size calculation. */ +struct memp_malloc_helper +{ + memp_t poolnr; +#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) + u16_t size; +#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */ +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type); +#endif +void memp_free(memp_t type, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mld6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mld6.h new file mode 100644 index 0000000000..7fa0797f27 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/mld6.h @@ -0,0 +1,99 @@ +/** + * @file + * + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_MLD6_H +#define LWIP_HDR_MLD6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** MLD group */ +struct mld_group { + /** next link */ + struct mld_group *next; + /** multicast address */ + ip6_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ + +err_t mld6_stop(struct netif *netif); +void mld6_report_groups(struct netif *netif); +void mld6_tmr(void); +struct mld_group *mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr); +void mld6_input(struct pbuf *p, struct netif *inp); +err_t mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr); +err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr); + +/** @ingroup mld6 + * Get list head of MLD6 groups for netif. + * Note: The allnodes group IP is NOT in the list, since it must always + * be received for correct IPv6 operation. + * @see @ref netif_set_mld_mac_filter() + */ +#define netif_mld6_data(netif) ((struct mld_group *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ + +#endif /* LWIP_HDR_MLD6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/nd6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/nd6.h new file mode 100644 index 0000000000..8204fa4cce --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/nd6.h @@ -0,0 +1,84 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_H +#define LWIP_HDR_ND6_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period */ +#define ND6_TMR_INTERVAL 1000 + +struct pbuf; +struct netif; + +void nd6_tmr(void); +void nd6_input(struct pbuf *p, struct netif *inp); +void nd6_clear_destination_cache(void); +struct netif *nd6_find_route(const ip6_addr_t *ip6addr); +err_t nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp); +u16_t nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif); +#if LWIP_ND6_TCP_REACHABILITY_HINTS +void nd6_reachability_hint(const ip6_addr_t *ip6addr); +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ +void nd6_cleanup_netif(struct netif *netif); +#if LWIP_IPV6_MLD +void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state); +#endif /* LWIP_IPV6_MLD */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netbuf.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netbuf.h new file mode 100644 index 0000000000..e6865f80f9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netbuf.h @@ -0,0 +1,118 @@ +/** + * @file + * netbuf API (for netconn API) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETBUF_H +#define LWIP_HDR_NETBUF_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +/** "Network buffer" - contains data and addressing info */ +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void); +void netbuf_delete (struct netbuf *buf); +void * netbuf_alloc (struct netbuf *buf, u16_t size); +void netbuf_free (struct netbuf *buf); +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size); +void netbuf_chain (struct netbuf *head, struct netbuf *tail); + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len); +s8_t netbuf_next (struct netbuf *buf); +void netbuf_first (struct netbuf *buf); + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(&((buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(&((buf)->toaddr), destaddr) +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#else /* LWIP_CHECKSUM_ON_COPY */ +#define netbuf_destport(buf) ((buf)->toport_chksum) +#endif /* LWIP_CHECKSUM_ON_COPY */ +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETBUF_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netdb.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netdb.h new file mode 100644 index 0000000000..d3d15dfac5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netdb.h @@ -0,0 +1,150 @@ +/** + * @file + * NETDB API (sockets) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_NETDB_H +#define LWIP_HDR_NETDB_H + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/arch.h" +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_FLAGS +#define LWIP_DNS_API_DEFINE_FLAGS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 +#define EAI_FAMILY 204 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DEFINE_FLAGS +/* input flags for struct addrinfo */ +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_NUMERICSERV 0x08 +#define AI_V4MAPPED 0x10 +#define AI_ALL 0x20 +#define AI_ADDRCONFIG 0x40 +#endif /* LWIP_DNS_API_DEFINE_FLAGS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessible error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +/** @ingroup netdbapi */ +#define gethostbyname(name) lwip_gethostbyname(name) +/** @ingroup netdbapi */ +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +/** @ingroup netdbapi */ +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +/** @ingroup netdbapi */ +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* LWIP_HDR_NETDB_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netif.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netif.h new file mode 100644 index 0000000000..67a2d24de8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netif.h @@ -0,0 +1,474 @@ +/** + * @file + * netif API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_H +#define LWIP_HDR_NETIF_H + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** Must be the maximum of all used hardware address lengths + across all types of interfaces in use. + This does not have to be changed, normally. */ +#ifndef NETIF_MAX_HWADDR_LEN +#define NETIF_MAX_HWADDR_LEN 6U +#endif + +/** + * @defgroup netif_flags Flags + * @ingroup netif + * @{ + */ + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It must be set by the startup code before this netif can be used + * (also for dhcp/autoip). + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x04U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x08U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x10U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x20U +/** If set, the netif has MLD6 capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_MLD6 0x40U + +/** + * @} + */ + +enum lwip_internal_netif_client_data_index +{ +#if LWIP_DHCP + LWIP_NETIF_CLIENT_DATA_INDEX_DHCP, +#endif +#if LWIP_AUTOIP + LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, +#endif +#if LWIP_IGMP + LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, +#endif +#if LWIP_IPV6_MLD + LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, +#endif + LWIP_NETIF_CLIENT_DATA_INDEX_MAX +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_CHECKSUM_GEN_IP 0x0001 +#define NETIF_CHECKSUM_GEN_UDP 0x0002 +#define NETIF_CHECKSUM_GEN_TCP 0x0004 +#define NETIF_CHECKSUM_GEN_ICMP 0x0008 +#define NETIF_CHECKSUM_GEN_ICMP6 0x0010 +#define NETIF_CHECKSUM_CHECK_IP 0x0100 +#define NETIF_CHECKSUM_CHECK_UDP 0x0200 +#define NETIF_CHECKSUM_CHECK_TCP 0x0400 +#define NETIF_CHECKSUM_CHECK_ICMP 0x0800 +#define NETIF_CHECKSUM_CHECK_ICMP6 0x1000 +#define NETIF_CHECKSUM_ENABLE_ALL 0xFFFF +#define NETIF_CHECKSUM_DISABLE_ALL 0x0000 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +struct netif; + +/** MAC Filter Actions, these are passed to a netif's igmp_mac_filter or + * mld_mac_filter callback function. */ +enum netif_mac_filter_action { + /** Delete a filter entry */ + NETIF_DEL_MAC_FILTER = 0, + /** Add a filter entry */ + NETIF_ADD_MAC_FILTER = 1 +}; + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV4 +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4*/ + +#if LWIP_IPV6 +/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'ethip6_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IPv6 address to which the packet shall be sent + */ +typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, + const ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ + +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +#if LWIP_IPV4 && LWIP_IGMP +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + const ip4_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** Function prototype for netif mld_mac_filter functions */ +typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, + const ip6_addr_t *group, enum netif_mac_filter_action action); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if LWIP_DHCP || LWIP_AUTOIP || LWIP_IGMP || LWIP_IPV6_MLD || (LWIP_NUM_NETIF_CLIENT_DATA > 0) +u8_t netif_alloc_client_data_id(void); +/** @ingroup netif_cd + * Set client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_set_client_data(netif, id, data) netif_get_client_data(netif, id) = (data) +/** @ingroup netif_cd + * Get client data. Obtain ID from netif_alloc_client_data_id(). + */ +#define netif_get_client_data(netif, id) (netif)->client_data[(id)] +#endif /* LWIP_DHCP || LWIP_AUTOIP || (LWIP_NUM_NETIF_CLIENT_DATA > 0) */ + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { + /** pointer to next in linked list */ + struct netif *next; + +#if LWIP_IPV4 + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + /** Array of IPv6 addresses for this netif. */ + ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; + /** The state of each IPv6 address (Tentative, Preferred, etc). + * @see ip6_addr.h */ + u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; +#endif /* LWIP_IPV6 */ + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. */ + netif_input_fn input; +#if LWIP_IPV4 + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually etharp_output() */ + netif_output_fn output; +#endif /* LWIP_IPV4 */ + /** This function is called by ethernet_output() when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. */ + netif_linkoutput_fn linkoutput; +#if LWIP_IPV6 + /** This function is called by the IPv6 module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. + * For ethernet physical layer, this is usually ethip6_output() */ + netif_output_ip6_fn output_ip6; +#endif /* LWIP_IPV6 */ +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK + /** This function is called when the netif has been removed */ + netif_status_callback_fn remove_callback; +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. */ + void *state; +#ifdef netif_get_client_data + void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA]; +#endif +#if LWIP_IPV6_AUTOCONFIG + /** is this netif enabled for IPv6 autoconfiguration */ + u8_t ip6_autoconfig_enabled; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /** Number of Router Solicitation messages that remain to be sent. */ + u8_t rs_count; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + const char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ +#if LWIP_CHECKSUM_CTRL_PER_NETIF + u16_t chksum_flags; +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ + /** maximum transfer unit (in bytes) */ + u16_t mtu; + /** number of bytes used in hwaddr */ + u8_t hwaddr_len; + /** link level hardware address of this interface */ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** flags (@see @ref netif_flags) */ + u8_t flags; + /** descriptive abbreviation */ + char name[2]; + /** number of this interface */ + u8_t num; +#if MIB2_STATS + /** link type (from "snmp_ifType" enum from snmp_mib2.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + struct stats_mib2_netif_ctrs mib2_counters; +#endif /* MIB2_STATS */ +#if LWIP_IPV4 && LWIP_IGMP + /** This function could be called to add or delete an entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IPV4 && LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /** This function could be called to add or delete an entry in the IPv6 multicast + filter table of the ethernet MAC. */ + netif_mld_mac_filter_fn mld_mac_filter; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. */ + struct pbuf *loop_first; + struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ + (netif)->chksum_flags = chksumflags; } while(0) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void); + +struct netif *netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input); +#if LWIP_IPV4 +void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, + const ip4_addr_t *gw); +#endif /* LWIP_IPV4 */ +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(const char *name); + +void netif_set_default(struct netif *netif); + +#if LWIP_IPV4 +void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr); +void netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask); +void netif_set_gw(struct netif *netif, const ip4_addr_t *gw); +/** @ingroup netif_ip4 */ +#define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) +/** @ingroup netif_ip4 */ +#define netif_ip4_netmask(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->netmask))) +/** @ingroup netif_ip4 */ +#define netif_ip4_gw(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->gw))) +/** @ingroup netif_ip4 */ +#define netif_ip_addr4(netif) ((const ip_addr_t*)&((netif)->ip_addr)) +/** @ingroup netif_ip4 */ +#define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask)) +/** @ingroup netif_ip4 */ +#define netif_ip_gw4(netif) ((const ip_addr_t*)&((netif)->gw)) +#endif /* LWIP_IPV4 */ + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +/** @ingroup netif + * Ask if an interface is up + */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +/** @ingroup netif */ +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +/** @ingroup netif */ +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +/** @ingroup netif */ +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** @ingroup netif */ +#define netif_set_mld_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->mld_mac_filter = function; }}while(0) +#define netif_get_mld_mac_filter(netif) (((netif) != NULL) ? ((netif)->mld_mac_filter) : NULL) +#define netif_mld_mac_filter(netif, addr, action) do { if((netif) && (netif)->mld_mac_filter) { (netif)->mld_mac_filter((netif), (addr), (action)); }}while(0) +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +err_t netif_input(struct pbuf *p, struct netif *inp); + +#if LWIP_IPV6 +/** @ingroup netif_ip6 */ +#define netif_ip_addr6(netif, i) ((const ip_addr_t*)(&((netif)->ip6_addr[i]))) +/** @ingroup netif_ip6 */ +#define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) +void netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6); +void netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3); +#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) +void netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state); +s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr); +void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit); +err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx); +#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0) +#endif /* LWIP_IPV6 */ + +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint)) +#else /* LWIP_NETIF_HWADDRHINT */ +#define NETIF_SET_HWADDRHINT(netif, hint) +#endif /* LWIP_NETIF_HWADDRHINT */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netifapi.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netifapi.h new file mode 100644 index 0000000000..8bd2b4f76f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/netifapi.h @@ -0,0 +1,140 @@ +/** + * @file + * netif API (to be used from non-TCPIP threads) + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +#ifndef LWIP_HDR_NETIFAPI_H +#define LWIP_HDR_NETIFAPI_H + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MPU_COMPATIBLE +#define NETIFAPI_IPADDR_DEF(type, m) type m +#else /* LWIP_MPU_COMPATIBLE */ +#define NETIFAPI_IPADDR_DEF(type, m) const type * m +#endif /* LWIP_MPU_COMPATIBLE */ + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg { + struct tcpip_api_call_data call; + struct netif *netif; + union { + struct { +#if LWIP_IPV4 + NETIFAPI_IPADDR_DEF(ip4_addr_t, ipaddr); + NETIFAPI_IPADDR_DEF(ip4_addr_t, netmask); + NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); +#endif /* LWIP_IPV4 */ + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + } msg; +}; + + +/* API for application */ +err_t netifapi_netif_add(struct netif *netif, +#if LWIP_IPV4 + const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, +#endif /* LWIP_IPV4 */ + void *state, netif_init_fn init, netif_input_fn input); + +#if LWIP_IPV4 +err_t netifapi_netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, const ip4_addr_t *gw); +#endif /* LWIP_IPV4*/ + +err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +/** @ingroup netifapi_netif */ +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL) +/** @ingroup netifapi_netif */ +#define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL) + +/** + * @defgroup netifapi_dhcp4 DHCPv4 + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) +/** @ingroup netifapi_dhcp4 */ +#define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) + +/** + * @defgroup netifapi_autoip AUTOIP + * @ingroup netifapi + * To be called from non-TCPIP threads + */ +/** @ingroup netifapi_autoip */ +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +/** @ingroup netifapi_autoip */ +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* LWIP_HDR_NETIFAPI_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/opt.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/opt.h new file mode 100644 index 0000000000..fd459af144 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/opt.h @@ -0,0 +1,2876 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * NOTE: || defined __DOXYGEN__ is a workaround for doxygen bug - + * without this, doxygen does not see the actual #define + */ + +#if !defined LWIP_HDR_OPT_H +#define LWIP_HDR_OPT_H + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you don't like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/** + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts + */ + + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ +#define NO_SYS 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif + +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 1 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 0 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 + */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 16 +#endif + +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#if !defined LWIP_ARP || defined __DOXYGEN__ +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 10 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 0 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 3 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF 0 +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#if !defined IP_FORWARD || defined __DOXYGEN__ +#define IP_FORWARD 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ +#define IP_REASSEMBLY 1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#if !defined IP_FRAG || defined __DOXYGEN__ +#define IP_FRAG 1 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL (IP_DEFAULT_TTL) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ +#define LWIP_DHCP 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/** + * LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has + * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and + * netif drivers might not set this flag, the default is off. If enabled, + * netif_set_link_up() must be called to continue dhcp starting. + */ +#if !defined LWIP_DHCP_CHECK_LINK_UP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#endif + +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 0 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DHCP servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ +#define LWIP_AUTOIP 0 +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ----- Multicast/IGMP options ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ +#define LWIP_IGMP 0 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS (LWIP_IGMP && LWIP_UDP) +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#if !defined LWIP_DNS || defined __DOXYGEN__ +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#if !defined LWIP_UDP || defined __DOXYGEN__ +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF (2 * TCP_MSS) +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 0u +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif. + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF LWIP_NETIF_LOOPBACK +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 1 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 1 +#endif + +/* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete + * successfully, as required by POSIX. Default is POSIX-compliant. + */ +#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ +#define LWIP_SOCKET_SET_ERRNO 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ +#define LWIP_SO_SNDTIMEO 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} + */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#endif + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 1 +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to #include in files that provide hooks. + * Declare your hook function prototypes in there, you may also #include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(dest, src): + * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * - called from etharp_output() (IPv4) + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Returns the IPv4 address of the gateway to handle the specified destination + * IPv4 address. If NULL is returned, the netif's default gateway is used. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * - called from ip6_input() (IPv6) + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * - called from ip6_route() (IPv6) + * - src: sourc IPv6 address + * - dest: destination IPv6 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * - called from nd6_get_next_hop_entry() (IPv6) + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Returns the IPv6 address of the next hop to handle the specified destination + * IPv6 address. If NULL is returned, a NDP-discovered router is used instead. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * - called from ethernet_input() if VLAN support is enabled + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature: s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * - called from memp_free() when a memp pool was empty and an item is now available + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Return ERR_OK if packet is accepted, any error code otherwise. + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_OFF +#endif +/** + * @} + */ + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + +#endif /* LWIP_HDR_OPT_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/pbuf.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/pbuf.h new file mode 100644 index 0000000000..90610461ea --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/pbuf.h @@ -0,0 +1,263 @@ +/** + * @file + * pbuf API + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_PBUF_H +#define LWIP_HDR_PBUF_H + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** LWIP_SUPPORT_CUSTOM_PBUF==1: Custom pbufs behave much like their pbuf type + * but they are allocated by external code (initialised by calling + * pbuf_alloced_custom()) and when pbuf_free gives up their last reference, they + * are freed by calling pbuf_custom->custom_free_function(). + * Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG, unless required by external driver/application code. */ +#ifndef LWIP_SUPPORT_CUSTOM_PBUF +#define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)) +#endif + +/* @todo: We need a mechanism to prevent wasting memory in every pbuf + (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ + +#define PBUF_TRANSPORT_HLEN 20 +#if LWIP_IPV6 +#define PBUF_IP_HLEN 40 +#else +#define PBUF_IP_HLEN 20 +#endif + +/** + * @ingroup pbuf + * Enumeration of pbuf layers + */ +typedef enum { + /** Includes spare room for transport layer header, e.g. UDP header. + * Use this if you intend to pass the pbuf to functions like udp_send(). + */ + PBUF_TRANSPORT, + /** Includes spare room for IP header. + * Use this if you intend to pass the pbuf to functions like raw_send(). + */ + PBUF_IP, + /** Includes spare room for link layer header (ethernet header). + * Use this if you intend to pass the pbuf to functions like ethernet_output(). + * @see PBUF_LINK_HLEN + */ + PBUF_LINK, + /** Includes spare room for additional encapsulation header before ethernet + * headers (e.g. 802.11). + * Use this if you intend to pass the pbuf to functions like netif->linkoutput(). + * @see PBUF_LINK_ENCAPSULATION_HLEN + */ + PBUF_RAW_TX, + /** Use this for input packets in a netif driver when calling netif->input() + * in the most common case - ethernet-layer netif driver. */ + PBUF_RAW +} pbuf_layer; + +/** + * @ingroup pbuf + * Enumeration of pbuf types + */ +typedef enum { + /** pbuf data is stored in RAM, used for TX mostly, struct pbuf and its payload + are allocated in one piece of contiguous memory (so the first payload byte + can be calculated from struct pbuf). + pbuf_alloc() allocates PBUF_RAM pbufs as unchained pbufs (although that might + change in future versions). + This should be used for all OUTGOING packets (TX).*/ + PBUF_RAM, + /** pbuf data is stored in ROM, i.e. struct pbuf and its payload are located in + totally different memory areas. Since it points to ROM, payload does not + have to be copied when queued for transmission. */ + PBUF_ROM, + /** pbuf comes from the pbuf pool. Much like PBUF_ROM but payload might change + so it has to be duplicated when queued before transmitting, depending on + who has a 'ref' to it. */ + PBUF_REF, + /** pbuf payload refers to RAM. This one comes from a pool and should be used + for RX. Payload can be chained (scatter-gather RX) but like PBUF_RAM, struct + pbuf and its payload are allocated in one piece of contiguous memory (so + the first payload byte can be calculated from struct pbuf). + Don't use this for TX, if the pool becomes empty e.g. because of TCP queuing, + you are unable to receive TCP acks! */ + PBUF_POOL +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free calls pbuf_custom->custom_free_function() + when the last reference is released (plus custom PBUF_RAM cannot be trimmed) */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U +/** indicates this pbuf was received as link-level broadcast */ +#define PBUF_FLAG_LLBCAST 0x08U +/** indicates this pbuf was received as link-level multicast */ +#define PBUF_FLAG_LLMCAST 0x10U +/** indicates this pbuf includes a TCP FIN flag */ +#define PBUF_FLAG_TCP_FIN 0x20U + +/** Main packet buffer struct */ +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** pbuf_type as u8_t instead of enum to save space */ + u8_t /*pbuf_type*/ type; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; +}; + + +/** Helper struct for const-correctness only. + * The only meaning of this one is to provide a const payload pointer + * for PBUF_ROM type. + */ +struct pbuf_rom { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + const void *payload; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ +#ifndef PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_FREE_OOSEQ 1 +#endif /* PBUF_POOL_FREE_OOSEQ */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ +extern volatile u8_t pbuf_free_ooseq_pending; +void pbuf_free_ooseq(void); +/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level to check if ooseq pbufs need to be + freed! */ +#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ + /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ + ooseq queued pbufs now */ \ + pbuf_free_ooseq(); }}while(0) +#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */ + /* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */ + #define PBUF_CHECK_FREE_OOSEQ() +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len); +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size); +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +u8_t pbuf_header_force(struct pbuf *p, s16_t header_size); +void pbuf_ref(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u16_t pbuf_clen(const struct pbuf *p); +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from); +u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset); +struct pbuf *pbuf_skip(struct pbuf* in, u16_t in_offset, u16_t* out_offset); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE +void pbuf_split_64k(struct pbuf *p, struct pbuf **rest); +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ + +u8_t pbuf_get_at(const struct pbuf* p, u16_t offset); +int pbuf_try_get_at(const struct pbuf* p, u16_t offset); +void pbuf_put_at(struct pbuf* p, u16_t offset, u8_t data); +u16_t pbuf_memcmp(const struct pbuf* p, u16_t offset, const void* s2, u16_t n); +u16_t pbuf_memfind(const struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); +u16_t pbuf_strstr(const struct pbuf* p, const char* substr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PBUF_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/api_msg.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/api_msg.h new file mode 100644 index 0000000000..f12b8b7d4f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/api_msg.h @@ -0,0 +1,216 @@ +/** + * @file + * netconn API lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_API_MSG_H +#define LWIP_HDR_API_MSG_H + +#include "lwip/opt.h" + +#if LWIP_NETCONN || LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ +/* Note: Netconn API is always available when sockets are enabled - + * sockets are implemented on top of them */ + +#include "lwip/arch.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/priv/tcpip_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_MPU_COMPATIBLE +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_MSG_M_DEF_SEM(m) *m +#else +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif +#else /* LWIP_MPU_COMPATIBLE */ +#define API_MSG_M_DEF_SEM(m) API_MSG_M_DEF(m) +#endif /* LWIP_MPU_COMPATIBLE */ + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for lwip_netconn_do_send */ + struct netbuf *b; + /** used for lwip_netconn_do_newconn */ + struct { + u8_t proto; + } n; + /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ + struct { + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; + } bc; + /** used for lwip_netconn_do_getaddr */ + struct { + ip_addr_t API_MSG_M_DEF(ipaddr); + u16_t API_MSG_M_DEF(port); + u8_t local; + } ad; + /** used for lwip_netconn_do_write */ + struct { + const void *dataptr; + size_t len; + u8_t apiflags; +#if LWIP_SO_SNDTIMEO + u32_t time_started; +#endif /* LWIP_SO_SNDTIMEO */ + } w; + /** used for lwip_netconn_do_recv */ + struct { + u32_t len; + } r; +#if LWIP_TCP + /** used for lwip_netconn_do_close (/shutdown) */ + struct { + u8_t shut; +#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER + u32_t time_started; +#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + u8_t polls_left; +#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ + } sd; +#endif /* LWIP_TCP */ +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) + /** used for lwip_netconn_do_join_leave_group */ + struct { + API_MSG_M_DEF_C(ip_addr_t, multiaddr); + API_MSG_M_DEF_C(ip_addr_t, netif_addr); + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +#if LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t* op_completed_sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +}; + +#if LWIP_NETCONN_SEM_PER_THREAD +#define LWIP_API_MSG_SEM(msg) ((msg)->op_completed_sem) +#else /* LWIP_NETCONN_SEM_PER_THREAD */ +#define LWIP_API_MSG_SEM(msg) (&(msg)->conn->op_completed) +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ + + +#if LWIP_DNS +/** As lwip_netconn_do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ +#if LWIP_MPU_COMPATIBLE + char name[DNS_MAX_NAME_LENGTH]; +#else /* LWIP_MPU_COMPATIBLE */ + const char *name; +#endif /* LWIP_MPU_COMPATIBLE */ + /** The resolved address is stored here */ + ip_addr_t API_MSG_M_DEF(addr); +#if LWIP_IPV4 && LWIP_IPV6 + /** Type of resolve call */ + u8_t dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t API_MSG_M_DEF_SEM(sem); + /** Errors are given back here */ + err_t API_MSG_M_DEF(err); +}; +#endif /* LWIP_DNS */ + +#if LWIP_TCP +extern u8_t netconn_aborted; +#endif /* LWIP_TCP */ + +void lwip_netconn_do_newconn (void *m); +void lwip_netconn_do_delconn (void *m); +void lwip_netconn_do_bind (void *m); +void lwip_netconn_do_connect (void *m); +void lwip_netconn_do_disconnect (void *m); +void lwip_netconn_do_listen (void *m); +void lwip_netconn_do_send (void *m); +void lwip_netconn_do_recv (void *m); +#if TCP_LISTEN_BACKLOG +void lwip_netconn_do_accepted (void *m); +#endif /* TCP_LISTEN_BACKLOG */ +void lwip_netconn_do_write (void *m); +void lwip_netconn_do_getaddr (void *m); +void lwip_netconn_do_close (void *m); +void lwip_netconn_do_shutdown (void *m); +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +void lwip_netconn_do_join_leave_group(void *m); +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ + +#if LWIP_DNS +void lwip_netconn_do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#endif /* LWIP_HDR_API_MSG_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_priv.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_priv.h new file mode 100644 index 0000000000..f246061dad --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_priv.h @@ -0,0 +1,183 @@ +/** + * @file + * memory pools lwIP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_MEMP_PRIV_H +#define LWIP_HDR_MEMP_PRIV_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/mem.h" + +#if MEMP_OVERFLOW_CHECK +/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning + * and at the end of each element, initialize them as 0xcd and check + * them later. */ +/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, + * every single element in each pool is checked! + * This is VERY SLOW but also very helpful. */ +/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in + * lwipopts.h to change the amount reserved for checking. */ +#ifndef MEMP_SANITY_REGION_BEFORE +#define MEMP_SANITY_REGION_BEFORE 16 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#if MEMP_SANITY_REGION_BEFORE > 0 +#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) +#else +#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#ifndef MEMP_SANITY_REGION_AFTER +#define MEMP_SANITY_REGION_AFTER 16 +#endif /* MEMP_SANITY_REGION_AFTER*/ +#if MEMP_SANITY_REGION_AFTER > 0 +#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) +#else +#define MEMP_SANITY_REGION_AFTER_ALIGNED 0 +#endif /* MEMP_SANITY_REGION_AFTER*/ + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE 0 +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + +#if !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK +struct memp { + struct memp *next; +#if MEMP_OVERFLOW_CHECK + const char *file; + int line; +#endif /* MEMP_OVERFLOW_CHECK */ +}; +#endif /* !MEMP_MEM_MALLOC || MEMP_OVERFLOW_CHECK */ + +#if MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/priv/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/priv/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS && MEMP_USE_CUSTOM_POOLS */ + +/** Memory pool descriptor */ +struct memp_desc { +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY + /** Textual description */ + const char *desc; +#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */ +#if MEMP_STATS + /** Statistics */ + struct stats_mem *stats; +#endif + + /** Element size */ + u16_t size; + +#if !MEMP_MEM_MALLOC + /** Number of elements */ + u16_t num; + + /** Base address */ + u8_t *base; + + /** First free element of each pool. Elements form a linked list. */ + struct memp **tab; +#endif /* MEMP_MEM_MALLOC */ +}; + +#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY +#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc), +#else +#define DECLARE_LWIP_MEMPOOL_DESC(desc) +#endif + +#if MEMP_STATS +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) static struct stats_mem name; +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) &name, +#else +#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name) +#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name) +#endif + +void memp_init_pool(const struct memp_desc *desc); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_pool_fn(const struct memp_desc* desc, const char* file, const int line); +#define memp_malloc_pool(d) memp_malloc_pool_fn((d), __FILE__, __LINE__) +#else +void *memp_malloc_pool(const struct memp_desc *desc); +#endif +void memp_free_pool(const struct memp_desc* desc, void *mem); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_MEMP_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_std.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_std.h new file mode 100644 index 0000000000..ce9fd50031 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/memp_std.h @@ -0,0 +1,146 @@ +/** + * @file + * lwIP internal memory pools (do not use in application code) + * This file is deliberately included multiple times: once with empty + * definition of LWIP_MEMPOOL() to handle all includes and multiple times + * to build up various lists of mem pools. + */ + +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))), "MALLOC_"#size) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB") +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB") +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB") +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG") +#endif /* LWIP_TCP */ + +#if LWIP_IPV4 && IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") +#endif /* LWIP_IPV4 && IP_REASSEMBLY */ +#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG) +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") +#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */ + +#if LWIP_NETCONN || LWIP_SOCKET +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN || LWIP_SOCKET */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL(API_MSG, MEMP_NUM_API_MSG, sizeof(struct api_msg), "API_MSG") +#if LWIP_DNS +LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg), "DNS_API_MSG") +#endif +#if LWIP_SOCKET && !LWIP_TCPIP_CORE_LOCKING +LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") +#endif +#if LWIP_NETIF_API +LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") +#endif +#endif /* LWIP_MPU_COMPATIBLE */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* LWIP_IPV4 && LWIP_ARP && ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") +#endif /* LWIP_IGMP */ + +#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") +#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ + +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#if LWIP_IPV6 && LWIP_ND6_QUEUEING +LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") +#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ + +#if LWIP_IPV6 && LWIP_IPV6_REASS +LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM") +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL") + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/nd6_priv.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/nd6_priv.h new file mode 100644 index 0000000000..4bda0b793a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/nd6_priv.h @@ -0,0 +1,144 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_ND6_PRIV_H +#define LWIP_HDR_ND6_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ND6_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct nd6_q_entry { + struct nd6_q_entry *next; + struct pbuf *p; +}; +#endif /* LWIP_ND6_QUEUEING */ + +/** Struct for tables. */ +struct nd6_neighbor_cache_entry { + ip6_addr_t next_hop_address; + struct netif *netif; + u8_t lladdr[NETIF_MAX_HWADDR_LEN]; + /*u32_t pmtu;*/ +#if LWIP_ND6_QUEUEING + /** Pointer to queue of pending outgoing packets on this entry. */ + struct nd6_q_entry *q; +#else /* LWIP_ND6_QUEUEING */ + /** Pointer to a single pending outgoing packet on this entry. */ + struct pbuf *q; +#endif /* LWIP_ND6_QUEUEING */ + u8_t state; + u8_t isrouter; + union { + u32_t reachable_time; /* in ms since value may originate from network packet */ + u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */ + u32_t probes_sent; + u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */ + } counter; +}; + +struct nd6_destination_cache_entry { + ip6_addr_t destination_addr; + ip6_addr_t next_hop_addr; + u16_t pmtu; + u32_t age; +}; + +struct nd6_prefix_list_entry { + ip6_addr_t prefix; + struct netif *netif; + u32_t invalidation_timer; /* in ms since value may originate from network packet */ +#if LWIP_IPV6_AUTOCONFIG + u8_t flags; +#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 +#endif /* LWIP_IPV6_AUTOCONFIG */ +}; + +struct nd6_router_list_entry { + struct nd6_neighbor_cache_entry *neighbor_entry; + u32_t invalidation_timer; /* in ms since value may originate from network packet */ + u8_t flags; +}; + +enum nd6_neighbor_cache_entry_state { + ND6_NO_ENTRY = 0, + ND6_INCOMPLETE, + ND6_REACHABLE, + ND6_STALE, + ND6_DELAY, + ND6_PROBE +}; + +/* Router tables. */ +/* @todo make these static? and entries accessible through API? */ +extern struct nd6_neighbor_cache_entry neighbor_cache[]; +extern struct nd6_destination_cache_entry destination_cache[]; +extern struct nd6_prefix_list_entry prefix_list[]; +extern struct nd6_router_list_entry default_router_list[]; + +/* Default values, can be updated by a RA message. */ +extern u32_t reachable_time; +extern u32_t retrans_timer; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* LWIP_HDR_ND6_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcp_priv.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcp_priv.h new file mode 100644 index 0000000000..73e8967e47 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcp_priv.h @@ -0,0 +1,507 @@ +/** + * @file + * TCP internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_PRIV_H +#define LWIP_HDR_TCP_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/tcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +void tcp_init (void); /* Initialize this module. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + +/* Call this from a netif driver (watch out for threading issues!) that has + returned a memory error on transmit and now has free buffers to send more. + This iterates all active pcbs that had an error and tries to call + tcp_output, so use this with care as it might slow down the system. */ +void tcp_txnow (void); + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +err_t tcp_send_empty_ack(struct tcp_pcb *pcb); +void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); +void tcp_rexmit_fast (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); +err_t tcp_process_refused_data(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) || \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +#define TCP_TCPLEN(seg) ((seg)->len + (((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0) ? 1U : 0U)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was successfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) ret = lwip_tcp_event(arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) do { if ((pcb)->state != SYN_RCVD) { \ + ret = lwip_tcp_event((pcb)->callback_arg, (pcb), LWIP_EVENT_POLL, NULL, 0, ERR_OK); \ + } else { \ + ret = ERR_ARG; } } while(0) +#define TCP_EVENT_ERR(last_state,errf,arg,err) do { if (last_state != SYN_RCVD) { \ + lwip_tcp_event((arg), NULL, LWIP_EVENT_ERR, NULL, 0, (err)); } } while(0) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(lpcb,pcb,arg,err,ret) \ + do { \ + if((lpcb)->accept != NULL) \ + (ret) = (lpcb)->accept((arg),(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(last_state,errf,arg,err) \ + do { \ + LWIP_UNUSED_ARG(last_state); \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segments on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversize only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ +#define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_EOL 0 +#define LWIP_TCP_OPT_NOP 1 +#define LWIP_TCP_OPT_MSS 2 +#define LWIP_TCP_OPT_WS 3 +#define LWIP_TCP_OPT_TS 8 + +#define LWIP_TCP_OPT_LEN_MSS 4 +#if LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_OPT_LEN_TS 10 +#define LWIP_TCP_OPT_LEN_TS_OUT 12 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_TS_OUT 0 +#endif +#if LWIP_WND_SCALE +#define LWIP_TCP_OPT_LEN_WS 3 +#define LWIP_TCP_OPT_LEN_WS_OUT 4 /* aligned for output (includes NOP padding) */ +#else +#define LWIP_TCP_OPT_LEN_WS_OUT 0 +#endif + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? LWIP_TCP_OPT_LEN_MSS : 0) + \ + (flags & TF_SEG_OPTS_TS ? LWIP_TCP_OPT_LEN_TS_OUT : 0) + \ + (flags & TF_SEG_OPTS_WND_SCALE ? LWIP_TCP_OPT_LEN_WS_OUT : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(mss) lwip_htonl(0x02040000 | ((mss) & 0xFFFF)) + +#if LWIP_WND_SCALE +#define TCPWNDSIZE_F U32_F +#define TCPWND_MAX 0xFFFFFFFFU +#define TCPWND_CHECK16(x) LWIP_ASSERT("window size > 0xFFFF", (x) <= 0xFFFF) +#define TCPWND_MIN16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#else /* LWIP_WND_SCALE */ +#define TCPWNDSIZE_F U16_F +#define TCPWND_MAX 0xFFFFU +#define TCPWND_CHECK16(x) +#define TCPWND_MIN16(x) x +#endif /* LWIP_WND_SCALE */ + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; +extern u8_t tcp_active_pcbs_changed; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 +#define NUM_TCP_PCB_LISTS 4 +extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for (tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + struct tcp_pcb *tcp_tmp_pcb; \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for (tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + struct tcp_pcb *tcp_tmp_pcb; \ + for (tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + +#define TCP_REG_ACTIVE(npcb) \ + do { \ + TCP_REG(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_RMV_ACTIVE(npcb) \ + do { \ + TCP_RMV(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_PCB_REMOVE_ACTIVE(pcb) \ + do { \ + tcp_pcb_remove(&tcp_active_pcbs, pcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +void tcp_segs_free(struct tcp_seg *seg); +void tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb); +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, + const ip_addr_t *local_ip, const ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(struct tcp_pcb *pcb); + +err_t tcp_keepalive(struct tcp_pcb *pcb); +err_t tcp_zero_window_probe(struct tcp_pcb *pcb); +void tcp_trigger_input_pcb_close(void); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest +#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING + , const ip_addr_t *src +#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ + ); +#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING +#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest, src) +#else /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ +#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest) +#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */ +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void); + +void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcpip_priv.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcpip_priv.h new file mode 100644 index 0000000000..630efb1402 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/priv/tcpip_priv.h @@ -0,0 +1,160 @@ +/** + * @file + * TCPIP API internal implementations (do not use in application code) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_PRIV_H +#define LWIP_HDR_TCPIP_PRIV_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pbuf; +struct netif; + +#if LWIP_MPU_COMPATIBLE +#define API_VAR_REF(name) (*(name)) +#define API_VAR_DECLARE(type, name) type * name +#define API_VAR_ALLOC(type, pool, name, errorval) do { \ + name = (type *)memp_malloc(pool); \ + if (name == NULL) { \ + return errorval; \ + } \ + } while(0) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) do { \ + name = (type *)LWIP_MEMPOOL_ALLOC(pool); \ + if (name == NULL) { \ + return errorval; \ + } \ + } while(0) +#define API_VAR_FREE(pool, name) memp_free(pool, name) +#define API_VAR_FREE_POOL(pool, name) LWIP_MEMPOOL_FREE(pool, name) +#define API_EXPR_REF(expr) (&(expr)) +#if LWIP_NETCONN_SEM_PER_THREAD +#define API_EXPR_REF_SEM(expr) (expr) +#else +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#endif +#define API_EXPR_DEREF(expr) expr +#define API_MSG_M_DEF(m) m +#define API_MSG_M_DEF_C(t, m) t m +#else /* LWIP_MPU_COMPATIBLE */ +#define API_VAR_REF(name) name +#define API_VAR_DECLARE(type, name) type name +#define API_VAR_ALLOC(type, pool, name, errorval) +#define API_VAR_ALLOC_POOL(type, pool, name, errorval) +#define API_VAR_FREE(pool, name) +#define API_VAR_FREE_POOL(pool, name) +#define API_EXPR_REF(expr) expr +#define API_EXPR_REF_SEM(expr) API_EXPR_REF(expr) +#define API_EXPR_DEREF(expr) (*(expr)) +#define API_MSG_M_DEF(m) *m +#define API_MSG_M_DEF_C(t, m) const t * m +#endif /* LWIP_MPU_COMPATIBLE */ + +err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem); + +struct tcpip_api_call_data +{ +#if !LWIP_TCPIP_CORE_LOCKING + err_t err; +#if !LWIP_NETCONN_SEM_PER_THREAD + sys_sem_t sem; +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ +#else /* !LWIP_TCPIP_CORE_LOCKING */ + u8_t dummy; /* avoid empty struct :-( */ +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +}; +typedef err_t (*tcpip_api_call_fn)(struct tcpip_api_call_data* call); +err_t tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call); + +enum tcpip_msg_type { + TCPIP_MSG_API, + TCPIP_MSG_API_CALL, + TCPIP_MSG_INPKT, +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + TCPIP_MSG_CALLBACK, + TCPIP_MSG_CALLBACK_STATIC +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + union { + struct { + tcpip_callback_fn function; + void* msg; + } api_msg; + struct { + tcpip_api_call_fn function; + struct tcpip_api_call_data *arg; + sys_sem_t *sem; + } api_call; + struct { + struct pbuf *p; + struct netif *netif; + netif_input_fn input_fn; + } inp; + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_PRIV_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/autoip.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/autoip.h new file mode 100644 index 0000000000..fd3af8a9fc --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/autoip.h @@ -0,0 +1,78 @@ +/** + * @file + * AutoIP protocol definitions + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + */ + +#ifndef LWIP_HDR_PROT_AUTOIP_H +#define LWIP_HDR_PROT_AUTOIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* 169.254.0.0 */ +#define AUTOIP_NET 0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +typedef enum { + AUTOIP_STATE_OFF = 0, + AUTOIP_STATE_PROBING = 1, + AUTOIP_STATE_ANNOUNCING = 2, + AUTOIP_STATE_BOUND = 3 +} autoip_state_enum_t; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_AUTOIP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dhcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dhcp.h new file mode 100644 index 0000000000..112953cb8b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dhcp.h @@ -0,0 +1,183 @@ +/** + * @file + * DHCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Leon Woestenberg + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef LWIP_HDR_PROT_DHCP_H +#define LWIP_HDR_PROT_DHCP_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + + + /* DHCP message item offsets and length */ +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_OFS 44U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_OFS 108U +#define DHCP_FILE_LEN 128U +#define DHCP_MSG_LEN 236U +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4U) /* 4 byte: cookie */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FLD_8(u8_t op); + PACK_STRUCT_FLD_8(u8_t htype); + PACK_STRUCT_FLD_8(u8_t hlen); + PACK_STRUCT_FLD_8(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FLD_S(ip4_addr_p_t ciaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t yiaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t siaddr); + PACK_STRUCT_FLD_S(ip4_addr_p_t giaddr); + PACK_STRUCT_FLD_8(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FLD_8(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FLD_8(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FLD_8(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +/* DHCP client states */ +typedef enum { + DHCP_STATE_OFF = 0, + DHCP_STATE_REQUESTING = 1, + DHCP_STATE_INIT = 2, + DHCP_STATE_REBOOTING = 3, + DHCP_STATE_REBINDING = 4, + DHCP_STATE_RENEWING = 5, + DHCP_STATE_SELECTING = 6, + DHCP_STATE_INFORMING = 7, + DHCP_STATE_CHECKING = 8, + DHCP_STATE_PERMANENT = 9, /* not yet implemented */ + DHCP_STATE_BOUND = 10, + DHCP_STATE_RELEASING = 11, /* not yet implemented */ + DHCP_STATE_BACKING_OFF = 12 +} dhcp_state_enum_t; + +/* DHCP op codes */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ +#define DHCP_HTYPE_ETH 1 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/* BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_NTP 42 +#define DHCP_OPTION_END 255 + +/* DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/* possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + + +#ifdef __cplusplus +} +#endif + +#endif /*LWIP_HDR_PROT_DHCP_H*/ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dns.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dns.h new file mode 100644 index 0000000000..94782d6e9c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/dns.h @@ -0,0 +1,140 @@ +/** + * @file + * DNS - host name to IP address resolver. + */ + +/* + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + * + * security fixes and more by Simon Goldschmidt + * + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LWIP_HDR_PROT_DNS_H +#define LWIP_HDR_PROT_DNS_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS server port address */ +#ifndef DNS_SERVER_PORT +#define DNS_SERVER_PORT 53 +#endif + +/* DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_AAAA 28 /* IPv6 address */ +#define DNS_RRTYPE_SRV 33 /* service location */ +#define DNS_RRTYPE_ANY 255 /* any type */ + +/* DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_ANY 255 /* any class */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +#define DNS_HDR_GET_OPCODE(hdr) ((((hdr)->flags1) >> 3) & 0xF) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS message header */ +struct dns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FLD_8(u8_t flags1); + PACK_STRUCT_FLD_8(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_HDR 12 + + +/* Multicast DNS definitions */ + +/** UDP port for multicast DNS queries */ +#ifndef DNS_MQUERY_PORT +#define DNS_MQUERY_PORT 5353 +#endif + +/* IPv4 group for multicast DNS queries: 224.0.0.251 */ +#ifndef DNS_MQUERY_IPV4_GROUP_INIT +#define DNS_MQUERY_IPV4_GROUP_INIT IPADDR4_INIT_BYTES(224,0,0,251) +#endif + +/* IPv6 group for multicast DNS queries: FF02::FB */ +#ifndef DNS_MQUERY_IPV6_GROUP_INIT +#define DNS_MQUERY_IPV6_GROUP_INIT IPADDR6_INIT_HOST(0xFF020000,0,0,0xFB) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_DNS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/etharp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/etharp.h new file mode 100644 index 0000000000..ec78305b82 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/etharp.h @@ -0,0 +1,91 @@ +/** + * @file + * ARP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHARP_H +#define LWIP_HDR_PROT_ETHARP_H + +#include "lwip/arch.h" +#include "lwip/prot/ethernet.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN ETH_HWADDR_LEN +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message, see RFC 826 ("Packet format") */ +struct etharp_hdr { + PACK_STRUCT_FIELD(u16_t hwtype); + PACK_STRUCT_FIELD(u16_t proto); + PACK_STRUCT_FLD_8(u8_t hwlen); + PACK_STRUCT_FLD_8(u8_t protolen); + PACK_STRUCT_FIELD(u16_t opcode); + PACK_STRUCT_FLD_S(struct eth_addr shwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr2 sipaddr); + PACK_STRUCT_FLD_S(struct eth_addr dhwaddr); + PACK_STRUCT_FLD_S(struct ip4_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETHARP_HDR 28 + +/* ARP hwtype values */ +enum etharp_hwtype { + HWTYPE_ETHERNET = 1 + /* others not used */ +}; + +/* ARP message types (opcodes) */ +enum etharp_opcode { + ARP_REQUEST = 1, + ARP_REPLY = 2 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHARP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ethernet.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ethernet.h new file mode 100644 index 0000000000..e4baa29dc4 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ethernet.h @@ -0,0 +1,170 @@ +/** + * @file + * Ethernet protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ETHERNET_H +#define LWIP_HDR_PROT_ETHERNET_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETH_HWADDR_LEN +#ifdef ETHARP_HWADDR_LEN +#define ETH_HWADDR_LEN ETHARP_HWADDR_LEN /* compatibility mode */ +#else +#define ETH_HWADDR_LEN 6 +#endif +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FLD_8(u8_t addr[ETH_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** Ethernet header */ +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FLD_8(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FLD_S(struct eth_addr dest); + PACK_STRUCT_FLD_S(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ +struct eth_vlan_hdr { + PACK_STRUCT_FIELD(u16_t prio_vid); + PACK_STRUCT_FIELD(u16_t tpid); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_VLAN_HDR 4 +#define VLAN_ID(vlan_hdr) (lwip_htons((vlan_hdr)->prio_vid) & 0xFFF) + +/** + * @ingroup ethernet + * A list of often ethtypes (although lwIP does not use all of them): */ +enum eth_type { + /** Internet protocol v4 */ + ETHTYPE_IP = 0x0800U, + /** Address resolution protocol */ + ETHTYPE_ARP = 0x0806U, + /** Wake on lan */ + ETHTYPE_WOL = 0x0842U, + /** RARP */ + ETHTYPE_RARP = 0x8035U, + /** Virtual local area network */ + ETHTYPE_VLAN = 0x8100U, + /** Internet protocol v6 */ + ETHTYPE_IPV6 = 0x86DDU, + /** PPP Over Ethernet Discovery Stage */ + ETHTYPE_PPPOEDISC = 0x8863U, + /** PPP Over Ethernet Session Stage */ + ETHTYPE_PPPOE = 0x8864U, + /** Jumbo Frames */ + ETHTYPE_JUMBO = 0x8870U, + /** Process field network */ + ETHTYPE_PROFINET = 0x8892U, + /** Ethernet for control automation technology */ + ETHTYPE_ETHERCAT = 0x88A4U, + /** Link layer discovery protocol */ + ETHTYPE_LLDP = 0x88CCU, + /** Serial real-time communication system */ + ETHTYPE_SERCOS = 0x88CDU, + /** Media redundancy protocol */ + ETHTYPE_MRP = 0x88E3U, + /** Precision time protocol */ + ETHTYPE_PTP = 0x88F7U, + /** Q-in-Q, 802.1ad */ + ETHTYPE_QINQ = 0x9100U +}; + +/** The 24-bit IANA IPv4-multicast OUI is 01-00-5e: */ +#define LL_IP4_MULTICAST_ADDR_0 0x01 +#define LL_IP4_MULTICAST_ADDR_1 0x00 +#define LL_IP4_MULTICAST_ADDR_2 0x5e + +/** IPv6 multicast uses this prefix */ +#define LL_IP6_MULTICAST_ADDR_0 0x33 +#define LL_IP6_MULTICAST_ADDR_1 0x33 + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables + * or known to be 32-bit aligned within the protocol header. */ +#ifndef ETHADDR32_COPY +#define ETHADDR32_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) +#endif + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local + * variables and known to be 16-bit aligned within the protocol header. */ +#ifndef ETHADDR16_COPY +#define ETHADDR16_COPY(dst, src) SMEMCPY(dst, src, ETH_HWADDR_LEN) +#endif + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETH_HWADDR_LEN) == 0) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ETHERNET_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp.h new file mode 100644 index 0000000000..7d19385c72 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp.h @@ -0,0 +1,91 @@ +/** + * @file + * ICMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP_H +#define LWIP_HDR_PROT_ICMP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ +#define ICMP_AM 17 /* address mask request */ +#define ICMP_AMR 18 /* address mask reply */ + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is split to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Compatibility defines, old versions used to combine type and code to an u16_t */ +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp6.h new file mode 100644 index 0000000000..3461120421 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/icmp6.h @@ -0,0 +1,170 @@ +/** + * @file + * ICMP6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ICMP6_H +#define LWIP_HDR_PROT_ICMP6_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** ICMP type */ +enum icmp6_type { + /** Destination unreachable */ + ICMP6_TYPE_DUR = 1, + /** Packet too big */ + ICMP6_TYPE_PTB = 2, + /** Time exceeded */ + ICMP6_TYPE_TE = 3, + /** Parameter problem */ + ICMP6_TYPE_PP = 4, + /** Private experimentation */ + ICMP6_TYPE_PE1 = 100, + /** Private experimentation */ + ICMP6_TYPE_PE2 = 101, + /** Reserved for expansion of error messages */ + ICMP6_TYPE_RSV_ERR = 127, + + /** Echo request */ + ICMP6_TYPE_EREQ = 128, + /** Echo reply */ + ICMP6_TYPE_EREP = 129, + /** Multicast listener query */ + ICMP6_TYPE_MLQ = 130, + /** Multicast listener report */ + ICMP6_TYPE_MLR = 131, + /** Multicast listener done */ + ICMP6_TYPE_MLD = 132, + /** Router solicitation */ + ICMP6_TYPE_RS = 133, + /** Router advertisement */ + ICMP6_TYPE_RA = 134, + /** Neighbor solicitation */ + ICMP6_TYPE_NS = 135, + /** Neighbor advertisement */ + ICMP6_TYPE_NA = 136, + /** Redirect */ + ICMP6_TYPE_RD = 137, + /** Multicast router advertisement */ + ICMP6_TYPE_MRA = 151, + /** Multicast router solicitation */ + ICMP6_TYPE_MRS = 152, + /** Multicast router termination */ + ICMP6_TYPE_MRT = 153, + /** Private experimentation */ + ICMP6_TYPE_PE3 = 200, + /** Private experimentation */ + ICMP6_TYPE_PE4 = 201, + /** Reserved for expansion of informational messages */ + ICMP6_TYPE_RSV_INF = 255 +}; + +/** ICMP destination unreachable codes */ +enum icmp6_dur_code { + /** No route to destination */ + ICMP6_DUR_NO_ROUTE = 0, + /** Communication with destination administratively prohibited */ + ICMP6_DUR_PROHIBITED = 1, + /** Beyond scope of source address */ + ICMP6_DUR_SCOPE = 2, + /** Address unreachable */ + ICMP6_DUR_ADDRESS = 3, + /** Port unreachable */ + ICMP6_DUR_PORT = 4, + /** Source address failed ingress/egress policy */ + ICMP6_DUR_POLICY = 5, + /** Reject route to destination */ + ICMP6_DUR_REJECT_ROUTE = 6 +}; + +/** ICMP time exceeded codes */ +enum icmp6_te_code { + /** Hop limit exceeded in transit */ + ICMP6_TE_HL = 0, + /** Fragment reassembly time exceeded */ + ICMP6_TE_FRAG = 1 +}; + +/** ICMP parameter code */ +enum icmp6_pp_code { + /** Erroneous header field encountered */ + ICMP6_PP_FIELD = 0, + /** Unrecognized next header type encountered */ + ICMP6_PP_HEADER = 1, + /** Unrecognized IPv6 option encountered */ + ICMP6_PP_OPTION = 2 +}; + +/** This is the standard ICMP6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t data); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** This is the ICMP6 header adapted for echo req/resp. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_echo_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ICMP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/igmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/igmp.h new file mode 100644 index 0000000000..d60cb31ee7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/igmp.h @@ -0,0 +1,90 @@ +/** + * @file + * IGMP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IGMP_H +#define LWIP_HDR_PROT_IGMP_H + +#include "lwip/arch.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * IGMP constants + */ +#define IGMP_TTL 1 +#define IGMP_MINLEN 8 +#define ROUTER_ALERT 0x9404U +#define ROUTER_ALERTLEN 4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY 0x11 /* Membership query */ +#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ + +/* Group membership states */ +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 + +/** + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FLD_8(u8_t igmp_msgtype); + PACK_STRUCT_FLD_8(u8_t igmp_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_checksum); + PACK_STRUCT_FLD_S(ip4_addr_p_t igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IGMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip.h new file mode 100644 index 0000000000..bbfae36752 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip.h @@ -0,0 +1,51 @@ +/** + * @file + * IP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP_H +#define LWIP_HDR_PROT_IP_H + +#include "lwip/arch.h" + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/** This operates on a void* by loading the first byte */ +#define IP_HDR_GET_VERSION(ptr) ((*(u8_t*)(ptr)) >> 4) + +#endif /* LWIP_HDR_PROT_IP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip4.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip4.h new file mode 100644 index 0000000000..bd442c6892 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip4.h @@ -0,0 +1,127 @@ +/** + * @file + * IPv4 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP4_H +#define LWIP_HDR_PROT_IP4_H + +#include "lwip/arch.h" +#include "lwip/ip4_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the packed version of ip4_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip4_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +typedef struct ip4_addr_packed ip4_addr_p_t; + +/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ +#define IP_HLEN 20 + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/* The IPv4 header */ +struct ip_hdr { + /* version / header length */ + PACK_STRUCT_FLD_8(u8_t _v_hl); + /* type of service */ + PACK_STRUCT_FLD_8(u8_t _tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000U /* reserved fragment flag */ +#define IP_DF 0x4000U /* don't fragment flag */ +#define IP_MF 0x2000U /* more fragments flag */ +#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FLD_8(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FLD_8(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip4_addr_p_t src); + PACK_STRUCT_FLD_S(ip4_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Macros to get struct ip_hdr fields: */ +#define IPH_V(hdr) ((hdr)->_v_hl >> 4) +#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) +#define IPH_TOS(hdr) ((hdr)->_tos) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +/* Macros to set struct ip_hdr fields: */ +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) +#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP4_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip6.h new file mode 100644 index 0000000000..6e1e2632bf --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/ip6.h @@ -0,0 +1,169 @@ +/** + * @file + * IPv6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_IP6_H +#define LWIP_HDR_PROT_IP6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This is the packed version of ip6_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_addr_packed { + PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +typedef struct ip6_addr_packed ip6_addr_p_t; + +#define IP6_HLEN 40 + +#define IP6_NEXTH_HOPBYHOP 0 +#define IP6_NEXTH_TCP 6 +#define IP6_NEXTH_UDP 17 +#define IP6_NEXTH_ENCAPS 41 +#define IP6_NEXTH_ROUTING 43 +#define IP6_NEXTH_FRAGMENT 44 +#define IP6_NEXTH_ICMP6 58 +#define IP6_NEXTH_NONE 59 +#define IP6_NEXTH_DESTOPTS 60 +#define IP6_NEXTH_UDPLITE 136 + +/** The IPv6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hdr { + /** version / traffic class / flow label */ + PACK_STRUCT_FIELD(u32_t _v_tc_fl); + /** payload length */ + PACK_STRUCT_FIELD(u16_t _plen); + /** next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /** hop limit */ + PACK_STRUCT_FLD_8(u8_t _hoplim); + /** source and destination IP addresses */ + PACK_STRUCT_FLD_S(ip6_addr_p_t src); + PACK_STRUCT_FLD_S(ip6_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Hop-by-hop router alert option. */ +#define IP6_HBH_HLEN 8 +#define IP6_PAD1_OPTION 0 +#define IP6_PADN_ALERT_OPTION 1 +#define IP6_ROUTER_ALERT_OPTION 5 +#define IP6_ROUTER_ALERT_VALUE_MLD 0 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hbh_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* header length */ + PACK_STRUCT_FLD_8(u8_t _hlen); + /* router alert option type */ + PACK_STRUCT_FLD_8(u8_t _ra_opt_type); + /* router alert option data len */ + PACK_STRUCT_FLD_8(u8_t _ra_opt_dlen); + /* router alert option data */ + PACK_STRUCT_FIELD(u16_t _ra_opt_data); + /* PadN option type */ + PACK_STRUCT_FLD_8(u8_t _padn_opt_type); + /* PadN option data len */ + PACK_STRUCT_FLD_8(u8_t _padn_opt_dlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Fragment header. */ +#define IP6_FRAG_HLEN 8 +#define IP6_FRAG_OFFSET_MASK 0xfff8 +#define IP6_FRAG_MORE_FLAG 0x0001 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_frag_hdr { + /* next header */ + PACK_STRUCT_FLD_8(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FLD_8(u8_t reserved); + /* fragment offset */ + PACK_STRUCT_FIELD(u16_t _fragment_offset); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u32_t _identification); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP6H_V(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((lwip_ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (lwip_ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (lwip_ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) + +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (lwip_htonl((((u32_t)(v)) << 28) | (((u32_t)(tc)) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = lwip_htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_IP6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/mld6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/mld6.h new file mode 100644 index 0000000000..be3a006af2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/mld6.h @@ -0,0 +1,70 @@ +/** + * @file + * MLD6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_MLD6_H +#define LWIP_HDR_PROT_MLD6_H + +#include "lwip/arch.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Multicast listener report/query/done message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mld_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t max_resp_delay); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t multicast_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_MLD6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/nd6.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/nd6.h new file mode 100644 index 0000000000..2d4903d15b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/nd6.h @@ -0,0 +1,277 @@ +/** + * @file + * ND6 protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_ND6_H +#define LWIP_HDR_PROT_ND6_H + +#include "lwip/arch.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Neighbor solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ns_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Neighbor advertisement message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct na_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FLD_8(u8_t reserved[3]); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define ND6_FLAG_ROUTER (0x80) +#define ND6_FLAG_SOLICITED (0x40) +#define ND6_FLAG_OVERRIDE (0x20) + +/** Router solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rs_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Router advertisement message header. */ +#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) +#define ND6_RA_FLAG_OTHER_CONFIG (0x40) +#define ND6_RA_FLAG_HOME_AGENT (0x20) +#define ND6_RA_PREFERENCE_MASK (0x18) +#define ND6_RA_PREFERENCE_HIGH (0x08) +#define ND6_RA_PREFERENCE_MEDIUM (0x00) +#define ND6_RA_PREFERENCE_LOW (0x18) +#define ND6_RA_PREFERENCE_DISABLED (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ra_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FLD_8(u8_t current_hop_limit); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u16_t router_lifetime); + PACK_STRUCT_FIELD(u32_t reachable_time); + PACK_STRUCT_FIELD(u32_t retrans_timer); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirect message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirect_header { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FLD_S(ip6_addr_p_t target_address); + PACK_STRUCT_FLD_S(ip6_addr_p_t destination_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Link-layer address option. */ +#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) +#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct lladdr_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t addr[NETIF_MAX_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Prefix information option. */ +#define ND6_OPTION_TYPE_PREFIX_INFO (0x03) +#define ND6_PREFIX_FLAG_ON_LINK (0x80) +#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) +#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) +#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct prefix_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t flags); + PACK_STRUCT_FIELD(u32_t valid_lifetime); + PACK_STRUCT_FIELD(u32_t preferred_lifetime); + PACK_STRUCT_FLD_8(u8_t reserved2[3]); + PACK_STRUCT_FLD_8(u8_t site_prefix_length); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirected header option. */ +#define ND6_OPTION_TYPE_REDIR_HDR (0x04) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirected_header_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t reserved[6]); + /* Portion of redirected packet follows. */ + /* PACK_STRUCT_FLD_8(u8_t redirected[8]); */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** MTU option. */ +#define ND6_OPTION_TYPE_MTU (0x05) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mtu_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t mtu); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Route information option. */ +#define ND6_OPTION_TYPE_ROUTE_INFO (24) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct route_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FLD_8(u8_t prefix_length); + PACK_STRUCT_FLD_8(u8_t preference); + PACK_STRUCT_FIELD(u32_t route_lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Recursive DNS Server Option. */ +#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS +#define LWIP_RDNSS_OPTION_MAX_SERVERS LWIP_ND6_RDNSS_MAX_DNS_SERVERS +#else +#define LWIP_RDNSS_OPTION_MAX_SERVERS 1 +#endif +#define ND6_OPTION_TYPE_RDNSS (25) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rdnss_option { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t lifetime); + PACK_STRUCT_FLD_S(ip6_addr_p_t rdnss_address[LWIP_RDNSS_OPTION_MAX_SERVERS]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_ND6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/tcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/tcp.h new file mode 100644 index 0000000000..67fe7b9e5f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/tcp.h @@ -0,0 +1,97 @@ +/** + * @file + * TCP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_TCP_H +#define LWIP_HDR_PROT_TCP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* TCP header flags bits */ +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U +/* Valid TCP header flags */ +#define TCP_FLAGS 0x3fU + +#define TCPH_HDRLEN(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)) +#define TCPH_FLAGS(phdr) ((u16_t)(lwip_ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)) + +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = lwip_htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS(~TCP_FLAGS)) | lwip_htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = (u16_t)(lwip_htons((u16_t)((len) << 12) | (flags))) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | lwip_htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags & ~lwip_htons(flags)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_TCP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/udp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/udp.h new file mode 100644 index 0000000000..664f19a3e7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/prot/udp.h @@ -0,0 +1,68 @@ +/** + * @file + * UDP protocol definitions + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_PROT_UDP_H +#define LWIP_HDR_PROT_UDP_H + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_PROT_UDP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/raw.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/raw.h new file mode 100644 index 0000000000..30aa147109 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/raw.h @@ -0,0 +1,118 @@ +/** + * @file + * raw API (to be used from TCPIP thread)\n + * See also @ref raw_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_RAW_H +#define LWIP_HDR_RAW_H + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr); + +/** the RAW protocol control block */ +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +#if LWIP_IPV6 + /* fields for handling checksum computations as per RFC3542. */ + u16_t chksum_offset; + u8_t chksum_reqd; +#endif +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto); +struct raw_pcb * raw_new_ip_type(u8_t type, u8_t proto); +void raw_remove (struct raw_pcb *pcb); +err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr); + +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp); +#define raw_init() /* Compatibility define, no init needed. */ + +void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +/* for compatibility with older implementation */ +#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* LWIP_HDR_RAW_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sio.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sio.h new file mode 100644 index 0000000000..7643e19569 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sio.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef SIO_H +#define SIO_H + +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum); +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd); +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd); +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SIO_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/snmp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/snmp.h new file mode 100644 index 0000000000..8704d0b4d2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/snmp.h @@ -0,0 +1,213 @@ +/** + * @file + * SNMP support API for implementing netifs and statitics for MIB2 + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Dirk Ziegelmeier + * + */ +#ifndef LWIP_HDR_SNMP_H +#define LWIP_HDR_SNMP_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct udp_pcb; +struct netif; + +/** + * @defgroup netif_mib2 MIB2 statistics + * @ingroup netif + */ + +/* MIB2 statistics functions */ +#if MIB2_STATS /* don't build if not configured for use in lwipopts.h */ +/** + * @ingroup netif_mib2 + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +/** This macro has a precision of ~49 days because sys_now returns u32_t. \#define your own if you want ~490 days. */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) (*(ptrToVal) = (sys_now() / 10)) +#endif + +/** + * @ingroup netif_mib2 + * Increment stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_INC(n, x) do { ++(n)->mib2_counters.x; } while(0) +/** + * @ingroup netif_mib2 + * Add value to stats member for SNMP MIB2 stats (struct stats_mib2_netif_ctrs) + */ +#define MIB2_STATS_NETIF_ADD(n, x, val) do { (n)->mib2_counters.x += (val); } while(0) + +/** + * @ingroup netif_mib2 + * Init MIB2 statistic counters in netif + * @param netif Netif to init + * @param type one of enum @ref snmp_ifType + * @param speed your link speed here (units: bits per second) + */ +#define MIB2_INIT_NETIF(netif, type, speed) do { \ + (netif)->link_type = (type); \ + (netif)->link_speed = (speed);\ + (netif)->ts = 0; \ + (netif)->mib2_counters.ifinoctets = 0; \ + (netif)->mib2_counters.ifinucastpkts = 0; \ + (netif)->mib2_counters.ifinnucastpkts = 0; \ + (netif)->mib2_counters.ifindiscards = 0; \ + (netif)->mib2_counters.ifinerrors = 0; \ + (netif)->mib2_counters.ifinunknownprotos = 0; \ + (netif)->mib2_counters.ifoutoctets = 0; \ + (netif)->mib2_counters.ifoutucastpkts = 0; \ + (netif)->mib2_counters.ifoutnucastpkts = 0; \ + (netif)->mib2_counters.ifoutdiscards = 0; \ + (netif)->mib2_counters.ifouterrors = 0; } while(0) +#else /* MIB2_STATS */ +#ifndef MIB2_COPY_SYSUPTIME_TO +#define MIB2_COPY_SYSUPTIME_TO(ptrToVal) +#endif +#define MIB2_INIT_NETIF(netif, type, speed) +#define MIB2_STATS_NETIF_INC(n, x) +#define MIB2_STATS_NETIF_ADD(n, x, val) +#endif /* MIB2_STATS */ + +/* LWIP MIB2 callbacks */ +#if LWIP_MIB2_CALLBACKS /* don't build if not configured for use in lwipopts.h */ +/* network interface */ +void mib2_netif_added(struct netif *ni); +void mib2_netif_removed(struct netif *ni); + +#if LWIP_IPV4 && LWIP_ARP +/* ARP (for atTable and ipNetToMediaTable) */ +void mib2_add_arp_entry(struct netif *ni, ip4_addr_t *ip); +void mib2_remove_arp_entry(struct netif *ni, ip4_addr_t *ip); +#else /* LWIP_IPV4 && LWIP_ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) +#endif /* LWIP_IPV4 && LWIP_ARP */ + +/* IP */ +#if LWIP_IPV4 +void mib2_add_ip4(struct netif *ni); +void mib2_remove_ip4(struct netif *ni); +void mib2_add_route_ip4(u8_t dflt, struct netif *ni); +void mib2_remove_route_ip4(u8_t dflt, struct netif *ni); +#endif /* LWIP_IPV4 */ + +/* UDP */ +#if LWIP_UDP +void mib2_udp_bind(struct udp_pcb *pcb); +void mib2_udp_unbind(struct udp_pcb *pcb); +#endif /* LWIP_UDP */ + +#else /* LWIP_MIB2_CALLBACKS */ +/* LWIP_MIB2_CALLBACKS support not available */ +/* define everything to be empty */ + +/* network interface */ +#define mib2_netif_added(ni) +#define mib2_netif_removed(ni) + +/* ARP */ +#define mib2_add_arp_entry(ni,ip) +#define mib2_remove_arp_entry(ni,ip) + +/* IP */ +#define mib2_add_ip4(ni) +#define mib2_remove_ip4(ni) +#define mib2_add_route_ip4(dflt, ni) +#define mib2_remove_route_ip4(dflt, ni) + +/* UDP */ +#define mib2_udp_bind(pcb) +#define mib2_udp_unbind(pcb) +#endif /* LWIP_MIB2_CALLBACKS */ + +/* for source-code compatibility reasons only, can be removed (not used internally) */ +#define NETIF_INIT_SNMP MIB2_INIT_NETIF +#define snmp_add_ifinoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifinoctets, value) +#define snmp_inc_ifinucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinucastpkts) +#define snmp_inc_ifinnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifinnucastpkts) +#define snmp_inc_ifindiscards(ni) MIB2_STATS_NETIF_INC(ni, ifindiscards) +#define snmp_inc_ifinerrors(ni) MIB2_STATS_NETIF_INC(ni, ifinerrors) +#define snmp_inc_ifinunknownprotos(ni) MIB2_STATS_NETIF_INC(ni, ifinunknownprotos) +#define snmp_add_ifoutoctets(ni,value) MIB2_STATS_NETIF_ADD(ni, ifoutoctets, value) +#define snmp_inc_ifoutucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutucastpkts) +#define snmp_inc_ifoutnucastpkts(ni) MIB2_STATS_NETIF_INC(ni, ifoutnucastpkts) +#define snmp_inc_ifoutdiscards(ni) MIB2_STATS_NETIF_INC(ni, ifoutdiscards) +#define snmp_inc_ifouterrors(ni) MIB2_STATS_NETIF_INC(ni, ifouterrors) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SNMP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sockets.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sockets.h new file mode 100644 index 0000000000..2522056dba --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sockets.h @@ -0,0 +1,593 @@ +/** + * @file + * Socket API (to be used from non-TCPIP threads) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef LWIP_HDR_SOCKETS_H +#define LWIP_HDR_SOCKETS_H + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) +typedef u8_t sa_family_t; +#endif +/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) +typedef u16_t in_port_t; +#endif + +#if LWIP_IPV4 +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; +#define SIN_ZERO_LEN 8 + char sin_zero[SIN_ZERO_LEN]; +}; +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +struct sockaddr_in6 { + u8_t sin6_len; /* length of this structure */ + sa_family_t sin6_family; /* AF_INET6 */ + in_port_t sin6_port; /* Transport layer port # */ + u32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + u32_t sin6_scope_id; /* Set of interfaces for scope */ +}; +#endif /* LWIP_IPV6 */ + +struct sockaddr { + u8_t sa_len; + sa_family_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_storage { + u8_t s2_len; + sa_family_t ss_family; + char s2_data1[2]; + u32_t s2_data2[3]; +#if LWIP_IPV6 + u32_t s2_data3[3]; +#endif /* LWIP_IPV6 */ +}; + +/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) +typedef u32_t socklen_t; +#endif + +struct lwip_sock; + +#if !LWIP_TCPIP_CORE_LOCKING +/** Maximum optlen used by setsockopt/getsockopt */ +#define LWIP_SETGETSOCKOPT_MAXOPTLEN 16 + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { + /** socket index for which to change options */ + int s; + /** level of the option to process */ + int level; + /** name of the option to process */ + int optname; + /** set: value to set the option to + * get: value of the option is stored here */ +#if LWIP_MPU_COMPATIBLE + u8_t optval[LWIP_SETGETSOCKOPT_MAXOPTLEN]; +#else + union { + void *p; + const void *pc; + } optval; +#endif + /** size of *optval */ + socklen_t optlen; + /** if an error occurs, it is temporarily stored here */ + err_t err; + /** semaphore to wake up the calling task */ + void* completed_sem; +}; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + +#if !defined(iovec) +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ + + +/* + * Additional options, not kept in so_options. + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_DONTLINGER ((int)(~SO_LINGER)) +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time in seconds */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#if LWIP_IPV6 +#define AF_INET6 10 +#else /* LWIP_IPV6 */ +#define AF_INET6 AF_UNSPEC +#endif /* LWIP_IPV6 */ +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#if LWIP_IPV6 +#define IPPROTO_IPV6 41 +#define IPPROTO_ICMPV6 58 +#endif /* LWIP_IPV6 */ +#define IPPROTO_UDPLITE 136 +#define IPPROTO_RAW 255 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_IPV6 +/* + * Options for level IPPROTO_IPV6 + */ +#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ +#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ +#endif /* LWIP_IPV6 */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_MULTICAST_TX_OPTIONS +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_IGMP +/* + * Options and types related to multicast membership + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +#undef FD_SETSIZE +/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +#define FD_SETSIZE MEMP_NUM_NETCONN +#define FDSETSAFESET(n, code) do { \ + if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ + code; }} while(0) +#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ + (code) : 0) +#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] |= (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] &= ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) +#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) + +typedef struct fd_set +{ + unsigned char fd_bits [(FD_SETSIZE+7)/8]; +} fd_set; + +#elif LWIP_SOCKET_OFFSET +#error LWIP_SOCKET_OFFSET does not work with external FD_SET! +#elif FD_SETSIZE < MEMP_NUM_NETCONN +#error "external FD_SETSIZE too small for number of sockets" +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +#define lwip_socket_init() /* Compatibility define, no init needed. */ +void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ +void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ + +#if LWIP_COMPAT_SOCKETS == 2 +/* This helps code parsers/code completion by not having the COMPAT functions as defines */ +#define lwip_accept accept +#define lwip_bind bind +#define lwip_shutdown shutdown +#define lwip_getpeername getpeername +#define lwip_getsockname getsockname +#define lwip_setsockopt setsockopt +#define lwip_getsockopt getsockopt +#define lwip_close closesocket +#define lwip_connect connect +#define lwip_listen listen +#define lwip_recv recv +#define lwip_recvfrom recvfrom +#define lwip_send send +#define lwip_sendmsg sendmsg +#define lwip_sendto sendto +#define lwip_socket socket +#define lwip_select select +#define lwip_ioctlsocket ioctl + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define lwip_read read +#define lwip_write write +#define lwip_writev writev +#undef lwip_close +#define lwip_close close +#define closesocket(s) close(s) +#define lwip_fcntl fcntl +#define lwip_ioctl ioctl +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS == 2 */ + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendmsg(int s, const struct msghdr *message, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_writev(int s, const struct iovec *iov, int iovcnt); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); + +#if LWIP_COMPAT_SOCKETS +#if LWIP_COMPAT_SOCKETS != 2 +/** @ingroup socket */ +#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) +/** @ingroup socket */ +#define bind(s,name,namelen) lwip_bind(s,name,namelen) +/** @ingroup socket */ +#define shutdown(s,how) lwip_shutdown(s,how) +/** @ingroup socket */ +#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) +/** @ingroup socket */ +#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) +/** @ingroup socket */ +#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) +/** @ingroup socket */ +#define closesocket(s) lwip_close(s) +/** @ingroup socket */ +#define connect(s,name,namelen) lwip_connect(s,name,namelen) +/** @ingroup socket */ +#define listen(s,backlog) lwip_listen(s,backlog) +/** @ingroup socket */ +#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) +/** @ingroup socket */ +#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) +/** @ingroup socket */ +#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) +/** @ingroup socket */ +#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) +/** @ingroup socket */ +#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) +/** @ingroup socket */ +#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) +/** @ingroup socket */ +#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) +/** @ingroup socket */ +#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +/** @ingroup socket */ +#define read(s,mem,len) lwip_read(s,mem,len) +/** @ingroup socket */ +#define write(s,dataptr,len) lwip_write(s,dataptr,len) +/** @ingroup socket */ +#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) +/** @ingroup socket */ +#define close(s) lwip_close(s) +/** @ingroup socket */ +#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) +/** @ingroup socket */ +#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ +#endif /* LWIP_COMPAT_SOCKETS != 2 */ + +#if LWIP_IPV4 && LWIP_IPV6 +/** @ingroup socket */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) \ + : (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL)) +/** @ingroup socket */ +#define inet_pton(af,src,dst) \ + (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) \ + : (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0)) +#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0) +#else /* LWIP_IPV4 && LWIP_IPV6 */ +#define inet_ntop(af,src,dst,size) \ + (((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) : NULL) +#define inet_pton(af,src,dst) \ + (((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) : 0) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* LWIP_HDR_SOCKETS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/stats.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/stats.h new file mode 100644 index 0000000000..bcda2ace6e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/stats.h @@ -0,0 +1,491 @@ +/** + * @file + * Statistics API (to be used from TCPIP thread) + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_STATS_H +#define LWIP_HDR_STATS_H + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +/** Protocol related stats */ +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +/** IGMP stats */ +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +/** Memory stats */ +struct stats_mem { +#if defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY + const char *name; +#endif /* defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY */ + STAT_COUNTER err; + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER illegal; +}; + +/** System element stats */ +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +/** System stats */ +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +/** SNMP MIB2 stats */ +struct stats_mib2 { + /* IP */ + u32_t ipinhdrerrors; + u32_t ipinaddrerrors; + u32_t ipinunknownprotos; + u32_t ipindiscards; + u32_t ipindelivers; + u32_t ipoutrequests; + u32_t ipoutdiscards; + u32_t ipoutnoroutes; + u32_t ipreasmoks; + u32_t ipreasmfails; + u32_t ipfragoks; + u32_t ipfragfails; + u32_t ipfragcreates; + u32_t ipreasmreqds; + u32_t ipforwdatagrams; + u32_t ipinreceives; + + /* TCP */ + u32_t tcpactiveopens; + u32_t tcppassiveopens; + u32_t tcpattemptfails; + u32_t tcpestabresets; + u32_t tcpoutsegs; + u32_t tcpretranssegs; + u32_t tcpinsegs; + u32_t tcpinerrs; + u32_t tcpoutrsts; + + /* UDP */ + u32_t udpindatagrams; + u32_t udpnoports; + u32_t udpinerrors; + u32_t udpoutdatagrams; + + /* ICMP */ + u32_t icmpinmsgs; + u32_t icmpinerrors; + u32_t icmpindestunreachs; + u32_t icmpintimeexcds; + u32_t icmpinparmprobs; + u32_t icmpinsrcquenchs; + u32_t icmpinredirects; + u32_t icmpinechos; + u32_t icmpinechoreps; + u32_t icmpintimestamps; + u32_t icmpintimestampreps; + u32_t icmpinaddrmasks; + u32_t icmpinaddrmaskreps; + u32_t icmpoutmsgs; + u32_t icmpouterrors; + u32_t icmpoutdestunreachs; + u32_t icmpouttimeexcds; + u32_t icmpoutechos; /* can be incremented by user application ('ping') */ + u32_t icmpoutechoreps; +}; + +/** + * @ingroup netif_mib2 + * SNMP MIB2 interface stats + */ +struct stats_mib2_netif_ctrs { + /** The total number of octets received on the interface, including framing characters */ + u32_t ifinoctets; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * not addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinucastpkts; + /** The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were + * addressed to a multicast or broadcast address at this sub-layer */ + u32_t ifinnucastpkts; + /** The number of inbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being deliverable to a higher-layer protocol. One possible + * reason for discarding such a packet could be to free up buffer space */ + u32_t ifindiscards; + /** For packet-oriented interfaces, the number of inbound packets that contained errors + * preventing them from being deliverable to a higher-layer protocol. For character- + * oriented or fixed-length interfaces, the number of inbound transmission units that + * contained errors preventing them from being deliverable to a higher-layer protocol. */ + u32_t ifinerrors; + /** For packet-oriented interfaces, the number of packets received via the interface which + * were discarded because of an unknown or unsupported protocol. For character-oriented + * or fixed-length interfaces that support protocol multiplexing the number of transmission + * units received via the interface which were discarded because of an unknown or unsupported + * protocol. For any interface that does not support protocol multiplexing, this counter will + * always be 0 */ + u32_t ifinunknownprotos; + /** The total number of octets transmitted out of the interface, including framing characters. */ + u32_t ifoutoctets; + /** The total number of packets that higher-level protocols requested be transmitted, and + * which were not addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutucastpkts; + /** The total number of packets that higher-level protocols requested be transmitted, and which + * were addressed to a multicast or broadcast address at this sub-layer, including + * those that were discarded or not sent. */ + u32_t ifoutnucastpkts; + /** The number of outbound packets which were chosen to be discarded even though no errors had + * been detected to prevent their being transmitted. One possible reason for discarding + * such a packet could be to free up buffer space. */ + u32_t ifoutdiscards; + /** For packet-oriented interfaces, the number of outbound packets that could not be transmitted + * because of errors. For character-oriented or fixed-length interfaces, the number of outbound + * transmission units that could not be transmitted because of errors. */ + u32_t ifouterrors; +}; + +/** lwIP stats container */ +struct stats_ { +#if LINK_STATS + /** Link level */ + struct stats_proto link; +#endif +#if ETHARP_STATS + /** ARP */ + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + /** Fragmentation */ + struct stats_proto ip_frag; +#endif +#if IP_STATS + /** IP */ + struct stats_proto ip; +#endif +#if ICMP_STATS + /** ICMP */ + struct stats_proto icmp; +#endif +#if IGMP_STATS + /** IGMP */ + struct stats_igmp igmp; +#endif +#if UDP_STATS + /** UDP */ + struct stats_proto udp; +#endif +#if TCP_STATS + /** TCP */ + struct stats_proto tcp; +#endif +#if MEM_STATS + /** Heap */ + struct stats_mem mem; +#endif +#if MEMP_STATS + /** Internal memory pools */ + struct stats_mem *memp[MEMP_MAX]; +#endif +#if SYS_STATS + /** System */ + struct stats_sys sys; +#endif +#if IP6_STATS + /** IPv6 */ + struct stats_proto ip6; +#endif +#if ICMP6_STATS + /** ICMP6 */ + struct stats_proto icmp6; +#endif +#if IP6_FRAG_STATS + /** IPv6 fragmentation */ + struct stats_proto ip6_frag; +#endif +#if MLD6_STATS + /** Multicast listener discovery */ + struct stats_igmp mld6; +#endif +#if ND6_STATS + /** Neighbor discovery */ + struct stats_proto nd6; +#endif +#if MIB2_STATS + /** SNMP MIB2 */ + struct stats_mib2 mib2; +#endif +}; + +/** Global variable containing lwIP internal statistics. Add this to your debugger's watchlist. */ +extern struct stats_ lwip_stats; + +/** Init statistics */ +void stats_init(void); + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#define STATS_GET(x) lwip_stats.x +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP") +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + + #if MEMP_STATS +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i]->x) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(lwip_stats.memp[i], i) +#define MEMP_STATS_GET(x, i) STATS_GET(memp[i]->x) + #else +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_DISPLAY(i) +#define MEMP_STATS_GET(x, i) 0 +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +#if IP6_STATS +#define IP6_STATS_INC(x) STATS_INC(x) +#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") +#else +#define IP6_STATS_INC(x) +#define IP6_STATS_DISPLAY() +#endif + +#if ICMP6_STATS +#define ICMP6_STATS_INC(x) STATS_INC(x) +#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") +#else +#define ICMP6_STATS_INC(x) +#define ICMP6_STATS_DISPLAY() +#endif + +#if IP6_FRAG_STATS +#define IP6_FRAG_STATS_INC(x) STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") +#else +#define IP6_FRAG_STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() +#endif + +#if MLD6_STATS +#define MLD6_STATS_INC(x) STATS_INC(x) +#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") +#else +#define MLD6_STATS_INC(x) +#define MLD6_STATS_DISPLAY() +#endif + +#if ND6_STATS +#define ND6_STATS_INC(x) STATS_INC(x) +#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") +#else +#define ND6_STATS_INC(x) +#define ND6_STATS_DISPLAY() +#endif + +#if MIB2_STATS +#define MIB2_STATS_INC(x) STATS_INC(x) +#else +#define MIB2_STATS_INC(x) +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +void stats_display_proto(struct stats_proto *proto, const char *name); +void stats_display_igmp(struct stats_igmp *igmp, const char *name); +void stats_display_mem(struct stats_mem *mem, const char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp, name) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_STATS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sys.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sys.h new file mode 100644 index 0000000000..d12bae0f96 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/sys.h @@ -0,0 +1,455 @@ +/** + * @file + * OS abstraction layer + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + */ + +#ifndef LWIP_HDR_SYS_H +#define LWIP_HDR_SYS_H + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_sem_valid(s) 0 +#define sys_sem_valid_val(s) 0 +#define sys_sem_set_invalid(s) +#define sys_sem_set_invalid_val(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mutex_valid(mu) 0 +#define sys_mutex_set_invalid(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) +#define sys_mbox_valid(m) +#define sys_mbox_valid_val(m) +#define sys_mbox_set_invalid(m) +#define sys_mbox_set_invalid_val(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#ifndef LWIP_COMPAT_MUTEX +#define LWIP_COMPAT_MUTEX 0 +#endif + +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** + * @ingroup sys_mutex + * Create a new mutex. + * Note that mutexes are expected to not be taken recursively by the lwIP code, + * so both implementation types (recursive or non-recursive) should work. + * @param mutex pointer to the mutex to create + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Lock a mutex + * @param mutex the mutex to lock + */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Unlock a mutex + * @param mutex the mutex to unlock + */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** + * @ingroup sys_mutex + * Delete a semaphore + * @param mutex the mutex to delete + */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** + * @ingroup sys_mutex + * Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** + * @ingroup sys_mutex + * Set a mutex invalid so that sys_mutex_valid returns 0 + */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** + * @ingroup sys_sem + * Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** + * @ingroup sys_sem + * Signals a semaphore + * @param sem the semaphore to signal + */ +void sys_sem_signal(sys_sem_t *sem); +/** + * @ingroup sys_sem + * Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout + */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** + * @ingroup sys_sem + * Delete a semaphore + * @param sem semaphore to delete + */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** + * @ingroup sys_sem + * Check if a semaphore is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** + * @ingroup sys_sem + * Set a semaphore invalid so that sys_sem_valid returns 0 + */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif +#ifndef sys_sem_valid_val +/** + * Same as sys_sem_valid() but taking a value, not a pointer + */ +#define sys_sem_valid_val(sem) sys_sem_valid(&(sem)) +#endif +#ifndef sys_sem_set_invalid_val +/** + * Same as sys_sem_set_invalid() but taking a value, not a pointer + */ +#define sys_sem_set_invalid_val(sem) sys_sem_set_invalid(&(sem)) +#endif + +#ifndef sys_msleep +/** + * @ingroup sys_misc + * Sleep for specified number of ms + */ +void sys_msleep(u32_t ms); /* only has a (close to) 1 ms resolution. */ +#endif + +/* Mailbox functions. */ + +/** + * @ingroup sys_mbox + * Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (minimum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise + */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** + * @ingroup sys_mbox + * Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) + */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** + * @ingroup sys_mbox + * Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! + */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timeout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** + * @ingroup sys_mbox + * Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty + */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** + * For now, we map straight to sys_arch implementation. + */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** + * @ingroup sys_mbox + * Delete an mbox + * @param mbox mbox to delete + */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** + * @ingroup sys_mbox + * Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid + */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** + * @ingroup sys_mbox + * Set an mbox invalid so that sys_mbox_valid returns 0 + */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_valid_val +/** + * Same as sys_mbox_valid() but taking a value, not a pointer + */ +#define sys_mbox_valid_val(mbox) sys_mbox_valid(&(mbox)) +#endif +#ifndef sys_mbox_set_invalid_val +/** + * Same as sys_mbox_set_invalid() but taking a value, not a pointer + */ +#define sys_mbox_set_invalid_val(mbox) sys_mbox_set_invalid(&(mbox)) +#endif + + +/** + * @ingroup sys_misc + * The only thread function: + * Creates a new thread + * ATTENTION: although this function returns a value, it MUST NOT FAIL (ports have to assert this!) + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/* sys_init() must be called before anything else. */ +void sys_init(void); + +#ifndef sys_jiffies +/** + * Ticks/jiffies since power up. + */ +u32_t sys_jiffies(void); +#endif + +/** + * @ingroup sys_time + * Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. + */ +u32_t sys_now(void); + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** + * @ingroup sys_prot + * SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** + * @ingroup sys_prot + * SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** + * @ingroup sys_prot + * SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_SYS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcp.h new file mode 100644 index 0000000000..34d1c10158 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcp.h @@ -0,0 +1,433 @@ +/** + * @file + * TCP API (to be used from TCPIP thread)\n + * See also @ref tcp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCP_H +#define LWIP_HDR_TCP_H + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) @todo! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +#if LWIP_WND_SCALE +#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) +#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) +#define TCPWND16(x) ((u16_t)LWIP_MIN((x), 0xFFFF)) +#define TCP_WND_MAX(pcb) ((tcpwnd_size_t)(((pcb)->flags & TF_WND_SCALE) ? TCP_WND : TCPWND16(TCP_WND))) +typedef u32_t tcpwnd_size_t; +#else +#define RCV_WND_SCALE(pcb, wnd) (wnd) +#define SND_WND_SCALE(pcb, wnd) (wnd) +#define TCPWND16(x) (x) +#define TCP_WND_MAX(pcb) TCP_WND +typedef u16_t tcpwnd_size_t; +#endif + +#if LWIP_WND_SCALE || TCP_LISTEN_BACKLOG || LWIP_TCP_TIMESTAMPS +typedef u16_t tcpflags_t; +#else +typedef u8_t tcpflags_t; +#endif + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + void *callback_arg; \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + /* ports are in host byte order */ \ + u16_t local_port + + +/** the TCP protocol control block for listening pcbs */ +struct tcp_pcb_listen { +/** Common members of all PCB types */ + IP_PCB; +/** Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. */ + tcp_accept_fn accept; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + + +/** the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + tcpflags_t flags; +#define TF_ACK_DELAY 0x01U /* Delayed ACK. */ +#define TF_ACK_NOW 0x02U /* Immediate ACK. */ +#define TF_INFR 0x04U /* In fast recovery. */ +#define TF_CLOSEPEND 0x08U /* If this is set, tcp_close failed to enqueue the FIN (retried in tcp_tmr) */ +#define TF_RXCLOSED 0x10U /* rx closed by tcp_shutdown */ +#define TF_FIN 0x20U /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY 0x40U /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ +#if LWIP_WND_SCALE +#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */ +#endif +#if TCP_LISTEN_BACKLOG +#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */ +#endif +#if LWIP_TCP_TIMESTAMPS +#define TF_TIMESTAMP 0x0400U /* Timestamp option enabled */ +#endif + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + + /* Timers */ + u8_t polltmr, pollinterval; + u8_t last_timer; + u32_t tmr; + + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + tcpwnd_size_t rcv_wnd; /* receiver window available */ + tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + s16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u8_t dupacks; + u32_t lastack; /* Highest acknowledged seqno. */ + + /* congestion avoidance/control variables */ + tcpwnd_size_t cwnd; + tcpwnd_size_t ssthresh; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + tcpwnd_size_t snd_wnd; /* sender window */ + tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ + + tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) + u16_t snd_queuelen; /* Number of pbufs currently in the send buffer. */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG + struct tcp_pcb_listen* listener; +#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u8_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; + +#if LWIP_WND_SCALE + u8_t snd_scale; + u8_t rcv_scale; +#endif +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void); +struct tcp_pcb * tcp_new_ip_type (u8_t type); + +void tcp_arg (struct tcp_pcb *pcb, void *arg); +#if LWIP_CALLBACK_API +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); +#endif /* LWIP_CALLBACK_API */ +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); + +#if LWIP_TCP_TIMESTAMPS +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#else /* LWIP_TCP_TIMESTAMPS */ +#define tcp_mss(pcb) ((pcb)->mss) +#endif /* LWIP_TCP_TIMESTAMPS */ +#define tcp_sndbuf(pcb) (TCPWND16((pcb)->snd_buf)) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +/** @ingroup tcp_raw */ +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +/** @ingroup tcp_raw */ +#define tcp_nagle_enable(pcb) ((pcb)->flags = (tcpflags_t)((pcb)->flags & ~TF_NODELAY)) +/** @ingroup tcp_raw */ +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) + +#if TCP_LISTEN_BACKLOG +#define tcp_backlog_set(pcb, new_backlog) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \ + ((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0) +void tcp_backlog_delayed(struct tcp_pcb* pcb); +void tcp_backlog_accepted(struct tcp_pcb* pcb); +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_backlog_set(pcb, new_backlog) +#define tcp_backlog_delayed(pcb) +#define tcp_backlog_accepted(pcb) +#endif /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) /* compatibility define, not needed any more */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len); +err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected); + +struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +/** @ingroup tcp_raw */ +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb); +err_t tcp_close (struct tcp_pcb *pcb); +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags); + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +err_t tcp_output (struct tcp_pcb *pcb); + + +const char* tcp_debug_state_str(enum tcp_state s); + +/* for compatibility with older implementation */ +#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* LWIP_HDR_TCP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcpip.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcpip.h new file mode 100644 index 0000000000..f2f6b469f1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/tcpip.h @@ -0,0 +1,106 @@ +/** + * @file + * Functions to sync with TCPIP thread + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_TCPIP_H +#define LWIP_HDR_TCPIP_H + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/timeouts.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +/** Lock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +/** Unlock lwIP core mutex (needs @ref LWIP_TCPIP_CORE_LOCKING 1) */ +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +struct pbuf; +struct netif; + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +/* Forward declarations */ +struct tcpip_callback_msg; + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +err_t tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn); +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); +/** + * @ingroup lwip_os + * @see tcpip_callback_with_block + */ +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); +void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); +err_t tcpip_trycallback(struct tcpip_callback_msg* msg); + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* LWIP_HDR_TCPIP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/timeouts.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/timeouts.h new file mode 100644 index 0000000000..c9b93aa02a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/timeouts.h @@ -0,0 +1,121 @@ +/** + * @file + * Timer implementations + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_TIMEOUTS_H +#define LWIP_HDR_TIMEOUTS_H + +#include "lwip/opt.h" +#include "lwip/err.h" +#if !NO_SYS +#include "lwip/sys.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a stack-internal timer function that has to be + * called at a defined interval */ +typedef void (* lwip_cyclic_timer_handler)(void); + +/** This struct contains information about a stack-internal timer function + that has to be called at a defined interval */ +struct lwip_cyclic_timer { + u32_t interval_ms; + lwip_cyclic_timer_handler handler; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +/** This array contains all stack-internal cyclic timers. To get the number of + * timers, use LWIP_ARRAYSIZE() */ +extern const struct lwip_cyclic_timer lwip_cyclic_timers[]; + +#if LWIP_TIMERS + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void); + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg); +void sys_restart_timeouts(void); +#if NO_SYS +void sys_check_timeouts(void); +u32_t sys_timeouts_sleeptime(void); +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ + + +#endif /* LWIP_TIMERS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_TIMEOUTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/lwip/udp.h b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/udp.h new file mode 100644 index 0000000000..b929907394 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/lwip/udp.h @@ -0,0 +1,182 @@ +/** + * @file + * UDP API (to be used from TCPIP thread)\n + * See also @ref udp_raw + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_UDP_H +#define LWIP_HDR_UDP_H + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" +#include "lwip/ip6_addr.h" +#include "lwip/prot/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' might point into the pbuf 'p' so freeing this pbuf + * can make 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port); + +/** the UDP protocol control block */ +struct udp_pcb { +/** Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_MULTICAST_TX_OPTIONS + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; + /** TTL for outgoing multicast packets */ + u8_t mcast_ttl; +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for external reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void); +struct udp_pcb * udp_new_ip_type(u8_t type); +void udp_remove (struct udp_pcb *pcb); +err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +err_t udp_connect (struct udp_pcb *pcb, const ip_addr_t *ipaddr, + u16_t port); +void udp_disconnect (struct udp_pcb *pcb); +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg); +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif); +err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, const ip_addr_t *src_ip); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port); +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); + +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum); +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum); +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum); +err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, + u8_t have_chksum, u16_t chksum, const ip_addr_t *src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp); + +void udp_init (void); + +/* for compatibility with older implementation */ +#define udp_new_ip6() udp_new_ip_type(IPADDR_TYPE_V6) + +#if LWIP_MULTICAST_TX_OPTIONS +#define udp_set_multicast_netif_addr(pcb, ip4addr) ip_addr_copy_from_ip4((pcb)->multicast_ip, *(ip4addr)) +#define udp_get_multicast_netif_addr(pcb) ip_2_ip4(&(pcb)->multicast_ip) +#define udp_set_multicast_ttl(pcb, value) do { (pcb)->mcast_ttl = value; } while(0) +#define udp_get_multicast_ttl(pcb) ((pcb)->mcast_ttl) +#endif /* LWIP_MULTICAST_TX_OPTIONS */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +void udp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* LWIP_HDR_UDP_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/etharp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/etharp.h new file mode 100644 index 0000000000..b536fd280f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/etharp.h @@ -0,0 +1,3 @@ +/* ARP has been moved to core/ipv4, provide this #include for compatibility only */ +#include "lwip/etharp.h" +#include "netif/ethernet.h" diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ethernet.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ethernet.h new file mode 100644 index 0000000000..49649cbf8b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ethernet.h @@ -0,0 +1,77 @@ +/** + * @file + * Ethernet input function - handles INCOMING ethernet level traffic + * To be used in most low-level netif implementations + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef LWIP_HDR_NETIF_ETHERNET_H +#define LWIP_HDR_NETIF_ETHERNET_H + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/prot/ethernet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_ARP || LWIP_ETHERNET + +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + +err_t ethernet_input(struct pbuf *p, struct netif *netif); +err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type); + +extern const struct eth_addr ethbroadcast, ethzero; + +#endif /* LWIP_ARP || LWIP_ETHERNET */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_ETHERNET_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6.h new file mode 100644 index 0000000000..4174644bb3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6.h @@ -0,0 +1,86 @@ +/** + * @file + * + * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + */ + +/* + * Copyright (c) 2015 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_H +#define LWIP_HDR_LOWPAN6_H + +#include "netif/lowpan6_opts.h" + +#if LWIP_IPV6 && LWIP_6LOWPAN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** 1 second period */ +#define LOWPAN6_TMR_INTERVAL 1000 + +void lowpan6_tmr(void); + +err_t lowpan6_set_context(u8_t index, const ip6_addr_t * context); +err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low); + +#if LWIP_IPV4 +err_t lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4 */ +err_t lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr); +err_t lowpan6_input(struct pbuf * p, struct netif *netif); +err_t lowpan6_if_init(struct netif *netif); + +/* pan_id in network byte order. */ +err_t lowpan6_set_pan_id(u16_t pan_id); + +#if !NO_SYS +err_t tcpip_6lowpan_input(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_6LOWPAN */ + +#endif /* LWIP_HDR_LOWPAN6_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6_opts.h new file mode 100644 index 0000000000..fb93ea05de --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/lowpan6_opts.h @@ -0,0 +1,70 @@ +/** + * @file + * 6LowPAN options list + */ + +/* + * Copyright (c) 2015 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef LWIP_HDR_LOWPAN6_OPTS_H +#define LWIP_HDR_LOWPAN6_OPTS_H + +#include "lwip/opt.h" + +#ifndef LWIP_6LOWPAN +#define LWIP_6LOWPAN 0 +#endif + +#ifndef LWIP_6LOWPAN_NUM_CONTEXTS +#define LWIP_6LOWPAN_NUM_CONTEXTS 10 +#endif + +#ifndef LWIP_6LOWPAN_INFER_SHORT_ADDRESS +#define LWIP_6LOWPAN_INFER_SHORT_ADDRESS 1 +#endif + +#ifndef LWIP_6LOWPAN_IPHC +#define LWIP_6LOWPAN_IPHC 1 +#endif + +#ifndef LWIP_6LOWPAN_HW_CRC +#define LWIP_6LOWPAN_HW_CRC 1 +#endif + +#ifndef LOWPAN6_DEBUG +#define LOWPAN6_DEBUG LWIP_DBG_OFF +#endif + +#endif /* LWIP_HDR_LOWPAN6_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ccp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ccp.h new file mode 100644 index 0000000000..14dd65962c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ccp.h @@ -0,0 +1,156 @@ +/* + * ccp.h - Definitions for PPP Compression Control Protocol. + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ccp.h,v 1.12 2004/11/04 10:02:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CCP_H +#define CCP_H + +/* + * CCP codes. + */ + +#define CCP_CONFREQ 1 +#define CCP_CONFACK 2 +#define CCP_TERMREQ 5 +#define CCP_TERMACK 6 +#define CCP_RESETREQ 14 +#define CCP_RESETACK 15 + +/* + * Max # bytes for a CCP option + */ + +#define CCP_MAX_OPTION_LENGTH 32 + +/* + * Parts of a CCP packet. + */ + +#define CCP_CODE(dp) ((dp)[0]) +#define CCP_ID(dp) ((dp)[1]) +#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3]) +#define CCP_HDRLEN 4 + +#define CCP_OPT_CODE(dp) ((dp)[0]) +#define CCP_OPT_LENGTH(dp) ((dp)[1]) +#define CCP_OPT_MINLEN 2 + +#if BSDCOMPRESS_SUPPORT +/* + * Definitions for BSD-Compress. + */ + +#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */ +#define CILEN_BSD_COMPRESS 3 /* length of config. option */ + +/* Macros for handling the 3rd byte of the BSD-Compress config option. */ +#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */ +#define BSD_VERSION(x) ((x) >> 5) /* version of option format */ +#define BSD_CURRENT_VERSION 1 /* current version number */ +#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n)) + +#define BSD_MIN_BITS 9 /* smallest code size supported */ +#define BSD_MAX_BITS 15 /* largest code size supported */ +#endif /* BSDCOMPRESS_SUPPORT */ + +#if DEFLATE_SUPPORT +/* + * Definitions for Deflate. + */ + +#define CI_DEFLATE 26 /* config option for Deflate */ +#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */ +#define CILEN_DEFLATE 4 /* length of its config option */ + +#define DEFLATE_MIN_SIZE 9 +#define DEFLATE_MAX_SIZE 15 +#define DEFLATE_METHOD_VAL 8 +#define DEFLATE_SIZE(x) (((x) >> 4) + 8) +#define DEFLATE_METHOD(x) ((x) & 0x0F) +#define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) +#define DEFLATE_CHK_SEQUENCE 0 +#endif /* DEFLATE_SUPPORT */ + +#if MPPE_SUPPORT +/* + * Definitions for MPPE. + */ + +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ +#endif /* MPPE_SUPPORT */ + +#if PREDICTOR_SUPPORT +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ +#endif /* PREDICTOR_SUPPORT */ + +typedef struct ccp_options { +#if DEFLATE_SUPPORT + unsigned int deflate :1; /* do Deflate? */ + unsigned int deflate_correct :1; /* use correct code for deflate? */ + unsigned int deflate_draft :1; /* use draft RFC code for deflate? */ +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + unsigned int bsd_compress :1; /* do BSD Compress? */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + unsigned int predictor_1 :1; /* do Predictor-1? */ + unsigned int predictor_2 :1; /* do Predictor-2? */ +#endif /* PREDICTOR_SUPPORT */ + +#if MPPE_SUPPORT + u8_t mppe; /* MPPE bitfield */ +#endif /* MPPE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + u_short bsd_bits; /* # bits/code for BSD Compress */ +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + u_short deflate_size; /* lg(window size) for Deflate */ +#endif /* DEFLATE_SUPPORT */ + u8_t method; /* code for chosen compression method */ +} ccp_options; + +extern const struct protent ccp_protent; + +void ccp_resetrequest(ppp_pcb *pcb); /* Issue a reset-request. */ + +#endif /* CCP_H */ +#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-md5.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-md5.h new file mode 100644 index 0000000000..eb0269fe50 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-md5.h @@ -0,0 +1,36 @@ +/* + * chap-md5.h - New CHAP/MD5 implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +extern const struct chap_digest_type md5_digest; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-new.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-new.h new file mode 100644 index 0000000000..64eae32202 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap-new.h @@ -0,0 +1,192 @@ +/* + * chap-new.c - New CHAP implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAP_H +#define CHAP_H + +#include "ppp.h" + +/* + * CHAP packets begin with a standard header with code, id, len (2 bytes). + */ +#define CHAP_HDRLEN 4 + +/* + * Values for the code field. + */ +#define CHAP_CHALLENGE 1 +#define CHAP_RESPONSE 2 +#define CHAP_SUCCESS 3 +#define CHAP_FAILURE 4 + +/* + * CHAP digest codes. + */ +#define CHAP_MD5 5 +#if MSCHAP_SUPPORT +#define CHAP_MICROSOFT 0x80 +#define CHAP_MICROSOFT_V2 0x81 +#endif /* MSCHAP_SUPPORT */ + +/* + * Semi-arbitrary limits on challenge and response fields. + */ +#define MAX_CHALLENGE_LEN 64 +#define MAX_RESPONSE_LEN 64 + +/* + * These limits apply to challenge and response packets we send. + * The +4 is the +1 that we actually need rounded up. + */ +#define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) +#define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) + +/* bitmask of supported algorithms */ +#if MSCHAP_SUPPORT +#define MDTYPE_MICROSOFT_V2 0x1 +#define MDTYPE_MICROSOFT 0x2 +#endif /* MSCHAP_SUPPORT */ +#define MDTYPE_MD5 0x4 +#define MDTYPE_NONE 0 + +#if MSCHAP_SUPPORT +/* Return the digest alg. ID for the most preferred digest type. */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + ((mdtype) & MDTYPE_MICROSOFT_V2)? CHAP_MICROSOFT_V2: \ + ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_DIGEST(mdtype) \ + ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Return the bit flag (lsb set) for our most preferred digest type. */ +#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype) + +/* Return the bit flag for a given digest algorithm ID. */ +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MICROSOFT_V2)? MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_D(digest) \ + ((digest) == CHAP_MD5)? MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* Can we do the requested digest? */ +#if MSCHAP_SUPPORT +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MICROSOFT_V2)? (mdtype) & MDTYPE_MICROSOFT_V2: \ + ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#else /* !MSCHAP_SUPPORT */ +#define CHAP_CANDIGEST(mdtype, digest) \ + ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ + 0 +#endif /* MSCHAP_SUPPORT */ + +/* + * The code for each digest type has to supply one of these. + */ +struct chap_digest_type { + int code; + +#if PPP_SERVER + /* + * Note: challenge and response arguments below are formatted as + * a length byte followed by the actual challenge/response data. + */ + void (*generate_challenge)(ppp_pcb *pcb, unsigned char *challenge); + int (*verify_response)(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space); +#endif /* PPP_SERVER */ + void (*make_response)(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *priv); + int (*check_success)(ppp_pcb *pcb, unsigned char *pkt, int len, unsigned char *priv); + void (*handle_failure)(ppp_pcb *pcb, unsigned char *pkt, int len); +}; + +/* + * Each interface is described by chap structure. + */ +#if CHAP_SUPPORT +typedef struct chap_client_state { + u8_t flags; + const char *name; + const struct chap_digest_type *digest; + unsigned char priv[64]; /* private area for digest's use */ +} chap_client_state; + +#if PPP_SERVER +typedef struct chap_server_state { + u8_t flags; + u8_t id; + const char *name; + const struct chap_digest_type *digest; + int challenge_xmits; + int challenge_pktlen; + unsigned char challenge[CHAL_MAX_PKTLEN]; +} chap_server_state; +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* Hook for a plugin to validate CHAP challenge */ +extern int (*chap_verify_hook)(char *name, char *ourname, int id, + const struct chap_digest_type *digest, + unsigned char *challenge, unsigned char *response, + char *message, int message_space); +#endif /* UNUSED */ + +#if PPP_SERVER +/* Called by authentication code to start authenticating the peer. */ +extern void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code); +#endif /* PPP_SERVER */ + +/* Called by auth. code to start authenticating us to the peer. */ +extern void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code); + +/* Represents the CHAP protocol to the main pppd code */ +extern const struct protent chap_protent; + +#endif /* CHAP_H */ +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap_ms.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap_ms.h new file mode 100644 index 0000000000..0795291158 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/chap_ms.h @@ -0,0 +1,44 @@ +/* + * chap_ms.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: chap_ms.h,v 1.13 2004/11/15 22:13:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef CHAPMS_INCLUDE +#define CHAPMS_INCLUDE + +extern const struct chap_digest_type chapms_digest; +extern const struct chap_digest_type chapms2_digest; + +#endif /* CHAPMS_INCLUDE */ + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eap.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eap.h new file mode 100644 index 0000000000..3ee9aaf81a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eap.h @@ -0,0 +1,169 @@ +/* + * eap.h - Extensible Authentication Protocol for PPP (RFC 2284) + * + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Non-exclusive rights to redistribute, modify, translate, and use + * this software in source and binary forms, in whole or in part, is + * hereby granted, provided that the above copyright notice is + * duplicated in any source form, and that neither the name of the + * copyright holder nor the author is used to endorse or promote + * products derived from this software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Original version by James Carlson + * + * $Id: eap.h,v 1.2 2003/06/11 23:56:26 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_EAP_H +#define PPP_EAP_H + +#include "ppp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Packet header = Code, id, length. + */ +#define EAP_HEADERLEN 4 + + +/* EAP message codes. */ +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +/* EAP types */ +#define EAPT_IDENTITY 1 +#define EAPT_NOTIFICATION 2 +#define EAPT_NAK 3 /* (response only) */ +#define EAPT_MD5CHAP 4 +#define EAPT_OTP 5 /* One-Time Password; RFC 1938 */ +#define EAPT_TOKEN 6 /* Generic Token Card */ +/* 7 and 8 are unassigned. */ +#define EAPT_RSA 9 /* RSA Public Key Authentication */ +#define EAPT_DSS 10 /* DSS Unilateral */ +#define EAPT_KEA 11 /* KEA */ +#define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */ +#define EAPT_TLS 13 /* EAP-TLS */ +#define EAPT_DEFENDER 14 /* Defender Token (AXENT) */ +#define EAPT_W2K 15 /* Windows 2000 EAP */ +#define EAPT_ARCOT 16 /* Arcot Systems */ +#define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */ +#define EAPT_NOKIACARD 18 /* Nokia IP smart card */ +#define EAPT_SRP 19 /* Secure Remote Password */ +/* 20 is deprecated */ + +/* EAP SRP-SHA1 Subtypes */ +#define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */ +#define EAPSRP_CKEY 1 /* Response 1 - Client Key */ +#define EAPSRP_SKEY 2 /* Request 2 - Server Key */ +#define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */ +#define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */ +#define EAPSRP_ACK 3 /* Response 3 - final ack */ +#define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */ + +#define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */ + +#define SRP_PSEUDO_ID "pseudo_" +#define SRP_PSEUDO_LEN 7 + +#define MD5_SIGNATURE_SIZE 16 +#define EAP_MIN_CHALLENGE_LENGTH 17 +#define EAP_MAX_CHALLENGE_LENGTH 24 +#define EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH 3 /* 2^3-1 = 7, 17+7 = 24 */ + +#define EAP_STATES \ + "Initial", "Pending", "Closed", "Listen", "Identify", \ + "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" + +#define eap_client_active(pcb) ((pcb)->eap.es_client.ea_state == eapListen) +#if PPP_SERVER +#define eap_server_active(pcb) \ + ((pcb)->eap.es_server.ea_state >= eapIdentify && \ + (pcb)->eap.es_server.ea_state <= eapMD5Chall) +#endif /* PPP_SERVER */ + +/* + * Complete EAP state for one PPP session. + */ +enum eap_state_code { + eapInitial = 0, /* No EAP authentication yet requested */ + eapPending, /* Waiting for LCP (no timer) */ + eapClosed, /* Authentication not in use */ + eapListen, /* Client ready (and timer running) */ + eapIdentify, /* EAP Identify sent */ + eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ + eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ + eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ + eapMD5Chall, /* Sent MD5-Challenge */ + eapOpen, /* Completed authentication */ + eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ + eapBadAuth /* Failed authentication */ +}; + +struct eap_auth { + const char *ea_name; /* Our name */ + char ea_peer[MAXNAMELEN +1]; /* Peer's name */ + void *ea_session; /* Authentication library linkage */ + u_char *ea_skey; /* Shared encryption key */ + u_short ea_namelen; /* Length of our name */ + u_short ea_peerlen; /* Length of peer's name */ + enum eap_state_code ea_state; + u_char ea_id; /* Current id */ + u_char ea_requests; /* Number of Requests sent/received */ + u_char ea_responses; /* Number of Responses */ + u_char ea_type; /* One of EAPT_* */ + u32_t ea_keyflags; /* SRP shared key usage flags */ +}; + +#ifndef EAP_MAX_CHALLENGE_LENGTH +#define EAP_MAX_CHALLENGE_LENGTH 24 +#endif +typedef struct eap_state { + struct eap_auth es_client; /* Client (authenticatee) data */ +#if PPP_SERVER + struct eap_auth es_server; /* Server (authenticator) data */ +#endif /* PPP_SERVER */ + int es_savedtime; /* Saved timeout */ + int es_rechallenge; /* EAP rechallenge interval */ + int es_lwrechallenge; /* SRP lightweight rechallenge inter */ + u8_t es_usepseudo; /* Use SRP Pseudonym if offered one */ + int es_usedpseudo; /* Set if we already sent PN */ + int es_challen; /* Length of challenge string */ + u_char es_challenge[EAP_MAX_CHALLENGE_LENGTH]; +} eap_state; + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ +#define EAP_DEFTRANSMITS 10 /* max # times to transmit */ +#define EAP_DEFREQTIME 20 /* Time to wait for peer request */ +#define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ +#endif /* moved to ppp_opts.h */ + +void eap_authwithpeer(ppp_pcb *pcb, const char *localname); +void eap_authpeer(ppp_pcb *pcb, const char *localname); + +extern const struct protent eap_protent; + +#ifdef __cplusplus +} +#endif + +#endif /* PPP_EAP_H */ + +#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ecp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ecp.h new file mode 100644 index 0000000000..5cdce29d5b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ecp.h @@ -0,0 +1,50 @@ +/* + * ecp.h - Definitions for PPP Encryption Control Protocol. + * + * Copyright (c) 2002 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ecp.h,v 1.2 2003/01/10 07:12:36 fcusack Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +typedef struct ecp_options { + bool required; /* Is ECP required? */ + unsigned enctype; /* Encryption type */ +} ecp_options; + +extern fsm ecp_fsm[]; +extern ecp_options ecp_wantoptions[]; +extern ecp_options ecp_gotoptions[]; +extern ecp_options ecp_allowoptions[]; +extern ecp_options ecp_hisoptions[]; + +extern const struct protent ecp_protent; + +#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eui64.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eui64.h new file mode 100644 index 0000000000..20ac22eede --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/eui64.h @@ -0,0 +1,94 @@ +/* + * eui64.h - EUI64 routines for IPv6CP. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: eui64.h,v 1.6 2002/12/04 23:03:32 paulus Exp $ +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef EUI64_H +#define EUI64_H + +/* + * @todo: + * + * Maybe this should be done by processing struct in6_addr directly... + */ +typedef union +{ + u8_t e8[8]; + u16_t e16[4]; + u32_t e32[2]; +} eui64_t; + +#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0) +#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \ + ((e).e32[1] == (o).e32[1])) +#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0; + +#define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t)) + +#define eui64_magic(e) do { \ + (e).e32[0] = magic(); \ + (e).e32[1] = magic(); \ + (e).e8[0] &= ~2; \ + } while (0) +#define eui64_magic_nz(x) do { \ + eui64_magic(x); \ + } while (eui64_iszero(x)) +#define eui64_magic_ne(x, y) do { \ + eui64_magic(x); \ + } while (eui64_equals(x, y)) + +#define eui64_get(ll, cp) do { \ + eui64_copy((*cp), (ll)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_put(ll, cp) do { \ + eui64_copy((ll), (*cp)); \ + (cp) += sizeof(eui64_t); \ + } while (0) + +#define eui64_set32(e, l) do { \ + (e).e32[0] = 0; \ + (e).e32[1] = lwip_htonl(l); \ + } while (0) +#define eui64_setlo32(e, l) eui64_set32(e, l) + +char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ + +#endif /* EUI64_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/fsm.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/fsm.h new file mode 100644 index 0000000000..b6915d3b80 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/fsm.h @@ -0,0 +1,175 @@ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: fsm.h,v 1.10 2004/11/13 02:28:15 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef FSM_H +#define FSM_H + +#include "ppp.h" + +/* + * Packet header = Code, id, length. + */ +#define HEADERLEN 4 + + +/* + * CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ 1 /* Configuration Request */ +#define CONFACK 2 /* Configuration Ack */ +#define CONFNAK 3 /* Configuration Nak */ +#define CONFREJ 4 /* Configuration Reject */ +#define TERMREQ 5 /* Termination Request */ +#define TERMACK 6 /* Termination Ack */ +#define CODEREJ 7 /* Code Reject */ + + +/* + * Each FSM is described by an fsm structure and fsm callbacks. + */ +typedef struct fsm { + ppp_pcb *pcb; /* PPP Interface */ + const struct fsm_callbacks *callbacks; /* Callback routines */ + const char *term_reason; /* Reason for closing protocol */ + u8_t seen_ack; /* Have received valid Ack/Nak/Rej to Req */ + /* -- This is our only flag, we might use u_int :1 if we have more flags */ + u16_t protocol; /* Data Link Layer Protocol field value */ + u8_t state; /* State */ + u8_t flags; /* Contains option bits */ + u8_t id; /* Current id */ + u8_t reqid; /* Current request id */ + u8_t retransmits; /* Number of retransmissions left */ + u8_t nakloops; /* Number of nak loops since last ack */ + u8_t rnakloops; /* Number of naks received */ + u8_t maxnakloops; /* Maximum number of nak loops tolerated + (necessary because IPCP require a custom large max nak loops value) */ + u8_t term_reason_len; /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { + void (*resetci) /* Reset our Configuration Information */ + (fsm *); + int (*cilen) /* Length of our Configuration Information */ + (fsm *); + void (*addci) /* Add our Configuration Information */ + (fsm *, u_char *, int *); + int (*ackci) /* ACK our Configuration Information */ + (fsm *, u_char *, int); + int (*nakci) /* NAK our Configuration Information */ + (fsm *, u_char *, int, int); + int (*rejci) /* Reject our Configuration Information */ + (fsm *, u_char *, int); + int (*reqci) /* Request peer's Configuration Information */ + (fsm *, u_char *, int *, int); + void (*up) /* Called when fsm reaches PPP_FSM_OPENED state */ + (fsm *); + void (*down) /* Called when fsm leaves PPP_FSM_OPENED state */ + (fsm *); + void (*starting) /* Called when we want the lower layer */ + (fsm *); + void (*finished) /* Called when we don't want the lower layer */ + (fsm *); + void (*protreject) /* Called when Protocol-Reject received */ + (int); + void (*retransmit) /* Retransmission is necessary */ + (fsm *); + int (*extcode) /* Called when unknown code received */ + (fsm *, int, int, u_char *, int); + const char *proto_name; /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/* + * Link states. + */ +#define PPP_FSM_INITIAL 0 /* Down, hasn't been opened */ +#define PPP_FSM_STARTING 1 /* Down, been opened */ +#define PPP_FSM_CLOSED 2 /* Up, hasn't been opened */ +#define PPP_FSM_STOPPED 3 /* Open, waiting for down event */ +#define PPP_FSM_CLOSING 4 /* Terminating the connection, not open */ +#define PPP_FSM_STOPPING 5 /* Terminating, but open */ +#define PPP_FSM_REQSENT 6 /* We've sent a Config Request */ +#define PPP_FSM_ACKRCVD 7 /* We've received a Config Ack */ +#define PPP_FSM_ACKSENT 8 /* We've sent a Config Ack */ +#define PPP_FSM_OPENED 9 /* Connection available */ + + +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT 4 /* Wait for peer to speak first */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define DEFTIMEOUT 3 /* Timeout time in seconds */ +#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif /* moved to ppp_opts.h */ + + +/* + * Prototypes + */ +void fsm_init(fsm *f); +void fsm_lowerup(fsm *f); +void fsm_lowerdown(fsm *f); +void fsm_open(fsm *f); +void fsm_close(fsm *f, const char *reason); +void fsm_input(fsm *f, u_char *inpacket, int l); +void fsm_protreject(fsm *f); +void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen); + + +#endif /* FSM_H */ +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipcp.h new file mode 100644 index 0000000000..45f46b31ff --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipcp.h @@ -0,0 +1,126 @@ +/* + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipcp.h,v 1.14 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPCP_H +#define IPCP_H + +/* + * Options. + */ +#define CI_ADDRS 1 /* IP Addresses */ +#if VJ_SUPPORT +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* VJ_SUPPORT */ +#define CI_ADDR 3 + +#if LWIP_DNS +#define CI_MS_DNS1 129 /* Primary DNS value */ +#define CI_MS_DNS2 131 /* Secondary DNS value */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ +#define CI_MS_WINS1 130 /* Primary WINS value */ +#define CI_MS_WINS2 132 /* Secondary WINS value */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT +#define MAX_STATES 16 /* from slcompress.h */ + +#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ +#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ +#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ + /* maxslot and slot number compression) */ + +#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ +#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ + /* compression option*/ +#endif /* VJ_SUPPORT */ + +typedef struct ipcp_options { + unsigned int neg_addr :1; /* Negotiate IP Address? */ + unsigned int old_addrs :1; /* Use old (IP-Addresses) option? */ + unsigned int req_addr :1; /* Ask peer to send IP address? */ +#if 0 /* UNUSED */ + unsigned int default_route :1; /* Assign default route through interface? */ + unsigned int replace_default_route :1; /* Replace default route through interface? */ +#endif /* UNUSED */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp :1; /* Make proxy ARP entry for peer? */ +#endif /* UNUSED - PROXY ARP */ +#if VJ_SUPPORT + unsigned int neg_vj :1; /* Van Jacobson Compression? */ + unsigned int old_vj :1; /* use old (short) form of VJ option? */ + unsigned int cflag :1; +#endif /* VJ_SUPPORT */ + unsigned int accept_local :1; /* accept peer's value for ouraddr */ + unsigned int accept_remote :1; /* accept peer's value for hisaddr */ +#if LWIP_DNS + unsigned int req_dns1 :1; /* Ask peer to send primary DNS address? */ + unsigned int req_dns2 :1; /* Ask peer to send secondary DNS address? */ +#endif /* LWIP_DNS */ + + u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ +#if LWIP_DNS + u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT + u16_t vj_protocol; /* protocol value to use in VJ option */ + u8_t maxslotindex; /* values for RFC1332 VJ compression neg. */ +#endif /* VJ_SUPPORT */ +} ipcp_options; + +#if 0 /* UNUSED, already defined by lwIP */ +char *ip_ntoa (u32_t); +#endif /* UNUSED, already defined by lwIP */ + +extern const struct protent ipcp_protent; + +#endif /* IPCP_H */ +#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipv6cp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipv6cp.h new file mode 100644 index 0000000000..07d1ae3186 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ipv6cp.h @@ -0,0 +1,183 @@ +/* + * ipv6cp.h - PPP IPV6 Control Protocol. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Original version, based on RFC2023 : + + Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt + Économique ayant pour membres BULL S.A. et l'INRIA). + + Ce logiciel informatique est disponible aux conditions + usuelles dans la recherche, c'est-à-dire qu'il peut + être utilisé, copié, modifié, distribué à l'unique + condition que ce texte soit conservé afin que + l'origine de ce logiciel soit reconnue. + + Le nom de l'Institut National de Recherche en Informatique + et en Automatique (INRIA), de l'IMAG, ou d'une personne morale + ou physique ayant participé à l'élaboration de ce logiciel ne peut + être utilisé sans son accord préalable explicite. + + Ce logiciel est fourni tel quel sans aucune garantie, + support ou responsabilité d'aucune sorte. + Ce logiciel est dérivé de sources d'origine + "University of California at Berkeley" et + "Digital Equipment Corporation" couvertes par des copyrights. + + L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) + est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National + Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant + sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + + This work has been done in the context of GIE DYADE (joint R & D venture + between BULL S.A. and INRIA). + + This software is available with usual "research" terms + with the aim of retain credits of the software. + Permission to use, copy, modify and distribute this software for any + purpose and without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies, + and the name of INRIA, IMAG, or any contributor not be used in advertising + or publicity pertaining to this material without the prior explicit + permission. The software is provided "as is" without any + warranties, support or liabilities of any kind. + This software is derived from source code from + "University of California at Berkeley" and + "Digital Equipment Corporation" protected by copyrights. + + Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) + is a federation of seven research units funded by the CNRS, National + Polytechnic Institute of Grenoble and University Joseph Fourier. + The research unit in Software, Systems, Networks (LSR) is member of IMAG. +*/ + +/* + * Derived from : + * + * + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipv6cp.h,v 1.7 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef IPV6CP_H +#define IPV6CP_H + +#include "eui64.h" + +/* + * Options. + */ +#define CI_IFACEID 1 /* Interface Identifier */ +#ifdef IPV6CP_COMP +#define CI_COMPRESSTYPE 2 /* Compression Type */ +#endif /* IPV6CP_COMP */ + +/* No compression types yet defined. + *#define IPV6CP_COMP 0x004f + */ +typedef struct ipv6cp_options { + unsigned int neg_ifaceid :1; /* Negotiate interface identifier? */ + unsigned int req_ifaceid :1; /* Ask peer to send interface identifier? */ + unsigned int accept_local :1; /* accept peer's value for iface id? */ + unsigned int opt_local :1; /* ourtoken set by option */ + unsigned int opt_remote :1; /* histoken set by option */ + unsigned int use_ip :1; /* use IP as interface identifier */ +#if 0 + unsigned int use_persistent :1; /* use uniquely persistent value for address */ +#endif +#ifdef IPV6CP_COMP + unsigned int neg_vj :1; /* Van Jacobson Compression? */ +#endif /* IPV6CP_COMP */ + +#ifdef IPV6CP_COMP + u_short vj_protocol; /* protocol value to use in VJ option */ +#endif /* IPV6CP_COMP */ + eui64_t ourid, hisid; /* Interface identifiers */ +} ipv6cp_options; + +extern const struct protent ipv6cp_protent; + +#endif /* IPV6CP_H */ +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/lcp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/lcp.h new file mode 100644 index 0000000000..12e2a05fc9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/lcp.h @@ -0,0 +1,171 @@ +/* + * lcp.h - Link Control Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: lcp.h,v 1.20 2004/11/14 22:53:42 carlsonj Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef LCP_H +#define LCP_H + +#include "ppp.h" + +/* + * Options. + */ +#define CI_VENDOR 0 /* Vendor Specific */ +#define CI_MRU 1 /* Maximum Receive Unit */ +#define CI_ASYNCMAP 2 /* Async Control Character Map */ +#define CI_AUTHTYPE 3 /* Authentication Type */ +#define CI_QUALITY 4 /* Quality Protocol */ +#define CI_MAGICNUMBER 5 /* Magic Number */ +#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ +#define CI_FCSALTERN 9 /* FCS-Alternatives */ +#define CI_SDP 10 /* Self-Describing-Pad */ +#define CI_NUMBERED 11 /* Numbered-Mode */ +#define CI_CALLBACK 13 /* callback */ +#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF 18 /* short sequence numbers for multilink */ +#define CI_EPDISC 19 /* endpoint discriminator */ +#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ +#define CI_LDISC 23 /* Link-Discriminator */ +#define CI_LCPAUTH 24 /* LCP Authentication */ +#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ +#define CI_PREFELIS 26 /* Prefix Elision */ +#define CI_MPHDRFMT 27 /* MP Header Format */ +#define CI_I18N 28 /* Internationalization */ +#define CI_SDL 29 /* Simple Data Link */ + +/* + * LCP-specific packet types (code numbers). + */ +#define PROTREJ 8 /* Protocol Reject */ +#define ECHOREQ 9 /* Echo Request */ +#define ECHOREP 10 /* Echo Reply */ +#define DISCREQ 11 /* Discard Request */ +#define IDENTIF 12 /* Identification */ +#define TIMEREM 13 /* Time Remaining */ + +/* Value used as data for CI_CALLBACK option */ +#define CBCP_OPT 6 /* Use callback control protocol */ + +#if 0 /* moved to ppp_opts.h */ +#define DEFMRU 1500 /* Try for this */ +#define MINMRU 128 /* No MRUs below this */ +#define MAXMRU 16384 /* Normally limit MRU to this */ +#endif /* moved to ppp_opts.h */ + +/* An endpoint discriminator, used with multilink. */ +#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ +struct epdisc { + unsigned char class_; /* -- The word "class" is reserved in C++. */ + unsigned char length; + unsigned char value[MAX_ENDP_LEN]; +}; + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { + unsigned int passive :1; /* Don't die if we don't get a response */ + unsigned int silent :1; /* Wait for the other end to start first */ +#if 0 /* UNUSED */ + unsigned int restart :1; /* Restart vs. exit after close */ +#endif /* UNUSED */ + unsigned int neg_mru :1; /* Negotiate the MRU? */ + unsigned int neg_asyncmap :1; /* Negotiate the async map? */ +#if PAP_SUPPORT + unsigned int neg_upap :1; /* Ask for UPAP authentication? */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int neg_chap :1; /* Ask for CHAP authentication? */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int neg_eap :1; /* Ask for EAP authentication? */ +#endif /* EAP_SUPPORT */ + unsigned int neg_magicnumber :1; /* Ask for magic number? */ + unsigned int neg_pcompression :1; /* HDLC Protocol Field Compression? */ + unsigned int neg_accompression :1; /* HDLC Address/Control Field Compression? */ +#if LQR_SUPPORT + unsigned int neg_lqr :1; /* Negotiate use of Link Quality Reports */ +#endif /* LQR_SUPPORT */ + unsigned int neg_cbcp :1; /* Negotiate use of CBCP */ +#ifdef HAVE_MULTILINK + unsigned int neg_mrru :1; /* negotiate multilink MRRU */ +#endif /* HAVE_MULTILINK */ + unsigned int neg_ssnhf :1; /* negotiate short sequence numbers */ + unsigned int neg_endpoint :1; /* negotiate endpoint discriminator */ + + u16_t mru; /* Value of MRU */ +#ifdef HAVE_MULTILINK + u16_t mrru; /* Value of MRRU, and multilink enable */ +#endif /* MULTILINK */ +#if CHAP_SUPPORT + u8_t chap_mdtype; /* which MD types (hashing algorithm) */ +#endif /* CHAP_SUPPORT */ + u32_t asyncmap; /* Value of async map */ + u32_t magicnumber; + u8_t numloops; /* Number of loops during magic number neg. */ +#if LQR_SUPPORT + u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ +#endif /* LQR_SUPPORT */ + struct epdisc endpoint; /* endpoint discriminator */ +} lcp_options; + +void lcp_open(ppp_pcb *pcb); +void lcp_close(ppp_pcb *pcb, const char *reason); +void lcp_lowerup(ppp_pcb *pcb); +void lcp_lowerdown(ppp_pcb *pcb); +void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len); /* send protocol reject */ + +extern const struct protent lcp_protent; + +#if 0 /* moved to ppp_opts.h */ +/* Default number of times we receive our magic number from the peer + before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 +#endif /* moved to ppp_opts.h */ + +#endif /* LCP_H */ +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/magic.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/magic.h new file mode 100644 index 0000000000..a2a9b530e5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/magic.h @@ -0,0 +1,122 @@ +/* + * magic.h - PPP Magic Number definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $ + */ +/***************************************************************************** +* randm.h - Random number generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-05-29 Guy Lancaster , Global Election Systems Inc. +* Extracted from avos. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MAGIC_H +#define MAGIC_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* + * Initialize the random number generator. + */ +void magic_init(void); + +/* + * Randomize our random seed value. To be called for truely random events + * such as user operations and network traffic. + */ +void magic_randomize(void); + +/* + * Return a new random number. + */ +u32_t magic(void); /* Returns the next magic number */ + +/* + * Fill buffer with random bytes + * + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using magic_churnrand(). + * Thus it's important to make sure that the results of this are not + * published directly because one could predict the next result to at + * least some degree. Also, it's important to get a good seed before + * the first use. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len); + +/* + * Return a new random number between 0 and (2^pow)-1 included. + */ +u32_t magic_pow(u8_t pow); + +#endif /* MAGIC_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/mppe.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/mppe.h new file mode 100644 index 0000000000..1ae8a5d924 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/mppe.h @@ -0,0 +1,173 @@ +/* + * mppe.h - Definitions for MPPE + * + * Copyright (c) 2008 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef MPPE_H +#define MPPE_H + +#include "netif/ppp/pppcrypt.h" + +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a lwip_htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + const u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) + +/* Shared MPPE padding between MSCHAP and MPPE */ +#define SHA1_PAD_SIZE 40 + +static const u8_t mppe_sha1_pad1[SHA1_PAD_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const u8_t mppe_sha1_pad2[SHA1_PAD_SIZE] = { + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 +}; + +/* + * State for an MPPE (de)compressor. + */ +typedef struct ppp_mppe_state { + lwip_arc4_context arc4; + u8_t master_key[MPPE_MAX_KEY_LEN]; + u8_t session_key[MPPE_MAX_KEY_LEN]; + u8_t keylen; /* key length in bytes */ + /* NB: 128-bit == 16, 40-bit == 8! + * If we want to support 56-bit, the unit has to change to bits + */ + u8_t bits; /* MPPE control bits */ + u16_t ccount; /* 12-bit coherency count (seqno) */ + u16_t sanity_errors; /* take down LCP if too many */ + unsigned int stateful :1; /* stateful mode flag */ + unsigned int discard :1; /* stateful mode packet loss flag */ +} ppp_mppe_state; + +void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key); +void mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options); +void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol); +void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state); +err_t mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb); + +#endif /* MPPE_H */ +#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/arc4.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/arc4.h new file mode 100644 index 0000000000..4af724cd90 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/arc4.h @@ -0,0 +1,81 @@ +/** + * \file arc4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_ARC4 + +#ifndef LWIP_INCLUDED_POLARSSL_ARC4_H +#define LWIP_INCLUDED_POLARSSL_ARC4_H + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +arc4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be initialized + * \param key the secret key + * \param keylen length of the key + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param buf buffer to be processed + * \param buflen amount of data in buf + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/des.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/des.h new file mode 100644 index 0000000000..e893890ed7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/des.h @@ -0,0 +1,92 @@ +/** + * \file des.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_DES + +#ifndef LWIP_INCLUDED_POLARSSL_DES_H +#define LWIP_INCLUDED_POLARSSL_DES_H + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< DES subkeys */ +} +des_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + */ +void des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_DES_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md4.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md4.h new file mode 100644 index 0000000000..570445687e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md4.h @@ -0,0 +1,97 @@ +/** + * \file md4.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD4 + +#ifndef LWIP_INCLUDED_POLARSSL_MD4_H +#define LWIP_INCLUDED_POLARSSL_MD4_H + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD4_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md5.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md5.h new file mode 100644 index 0000000000..1244011890 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/md5.h @@ -0,0 +1,96 @@ +/** + * \file md5.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_MD5 + +#ifndef LWIP_INCLUDED_POLARSSL_MD5_H +#define LWIP_INCLUDED_POLARSSL_MD5_H + +/** + * \brief MD5 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_MD5_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/sha1.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/sha1.h new file mode 100644 index 0000000000..a4c53e07c5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/polarssl/sha1.h @@ -0,0 +1,96 @@ +/** + * \file sha1.h + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if LWIP_INCLUDED_POLARSSL_SHA1 + +#ifndef LWIP_INCLUDED_POLARSSL_SHA1_H +#define LWIP_INCLUDED_POLARSSL_SHA1_H + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1_H */ + +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp.h new file mode 100644 index 0000000000..d9ea097efd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp.h @@ -0,0 +1,690 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_H +#define PPP_H + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#if PPP_IPV6_SUPPORT +#include "lwip/ip6_addr.h" +#endif /* PPP_IPV6_SUPPORT */ + +/* Disable non-working or rarely used PPP feature, so rarely that we don't want to bloat ppp_opts.h with them */ +#ifndef PPP_OPTIONS +#define PPP_OPTIONS 0 +#endif + +#ifndef PPP_NOTIFY +#define PPP_NOTIFY 0 +#endif + +#ifndef PPP_REMOTENAME +#define PPP_REMOTENAME 0 +#endif + +#ifndef PPP_IDLETIMELIMIT +#define PPP_IDLETIMELIMIT 0 +#endif + +#ifndef PPP_LCP_ADAPTIVE +#define PPP_LCP_ADAPTIVE 0 +#endif + +#ifndef PPP_MAXCONNECT +#define PPP_MAXCONNECT 0 +#endif + +#ifndef PPP_ALLOWED_ADDRS +#define PPP_ALLOWED_ADDRS 0 +#endif + +#ifndef PPP_PROTOCOLNAME +#define PPP_PROTOCOLNAME 0 +#endif + +#ifndef PPP_STATS_SUPPORT +#define PPP_STATS_SUPPORT 0 +#endif + +#ifndef DEFLATE_SUPPORT +#define DEFLATE_SUPPORT 0 +#endif + +#ifndef BSDCOMPRESS_SUPPORT +#define BSDCOMPRESS_SUPPORT 0 +#endif + +#ifndef PREDICTOR_SUPPORT +#define PREDICTOR_SUPPORT 0 +#endif + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ + +/* + * Values for phase. + */ +#define PPP_PHASE_DEAD 0 +#define PPP_PHASE_MASTER 1 +#define PPP_PHASE_HOLDOFF 2 +#define PPP_PHASE_INITIALIZE 3 +#define PPP_PHASE_SERIALCONN 4 +#define PPP_PHASE_DORMANT 5 +#define PPP_PHASE_ESTABLISH 6 +#define PPP_PHASE_AUTHENTICATE 7 +#define PPP_PHASE_CALLBACK 8 +#define PPP_PHASE_NETWORK 9 +#define PPP_PHASE_RUNNING 10 +#define PPP_PHASE_TERMINATE 11 +#define PPP_PHASE_DISCONNECT 12 + +/* Error codes. */ +#define PPPERR_NONE 0 /* No error. */ +#define PPPERR_PARAM 1 /* Invalid parameter. */ +#define PPPERR_OPEN 2 /* Unable to open PPP session. */ +#define PPPERR_DEVICE 3 /* Invalid I/O device for PPP. */ +#define PPPERR_ALLOC 4 /* Unable to allocate resources. */ +#define PPPERR_USER 5 /* User interrupt. */ +#define PPPERR_CONNECT 6 /* Connection lost. */ +#define PPPERR_AUTHFAIL 7 /* Failed authentication challenge. */ +#define PPPERR_PROTOCOL 8 /* Failed to meet protocol. */ +#define PPPERR_PEERDEAD 9 /* Connection timeout */ +#define PPPERR_IDLETIMEOUT 10 /* Idle Timeout */ +#define PPPERR_CONNECTTIME 11 /* Max connect time reached */ +#define PPPERR_LOOPBACK 12 /* Loopback detected */ + +/* Whether auth support is enabled at all */ +#define PPP_AUTH_SUPPORT (PAP_SUPPORT || CHAP_SUPPORT || EAP_SUPPORT) + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Other headers require ppp_pcb definition for prototypes, but ppp_pcb + * require some structure definition from other headers as well, we are + * fixing the dependency loop here by declaring the ppp_pcb type then + * by including headers containing necessary struct definition for ppp_pcb + */ +typedef struct ppp_pcb_s ppp_pcb; + +/* Type definitions for BSD code. */ +#ifndef __u_char_defined +typedef unsigned long u_long; +typedef unsigned int u_int; +typedef unsigned short u_short; +typedef unsigned char u_char; +#endif + +#include "fsm.h" +#include "lcp.h" +#if CCP_SUPPORT +#include "ccp.h" +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT +#include "mppe.h" +#endif /* MPPE_SUPPORT */ +#if PPP_IPV4_SUPPORT +#include "ipcp.h" +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +#include "ipv6cp.h" +#endif /* PPP_IPV6_SUPPORT */ +#if PAP_SUPPORT +#include "upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "eap.h" +#endif /* EAP_SUPPORT */ +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ + +/* Link status callback function prototype */ +typedef void (*ppp_link_status_cb_fn)(ppp_pcb *pcb, int err_code, void *ctx); + +/* + * PPP configuration. + */ +typedef struct ppp_settings_s { + +#if PPP_SERVER && PPP_AUTH_SUPPORT + unsigned int auth_required :1; /* Peer is required to authenticate */ + unsigned int null_login :1; /* Username of "" and a password of "" are acceptable */ +#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ +#if PPP_REMOTENAME + unsigned int explicit_remote :1; /* remote_name specified with remotename opt */ +#endif /* PPP_REMOTENAME */ +#if PAP_SUPPORT + unsigned int refuse_pap :1; /* Don't proceed auth. with PAP */ +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + unsigned int refuse_chap :1; /* Don't proceed auth. with CHAP */ +#endif /* CHAP_SUPPORT */ +#if MSCHAP_SUPPORT + unsigned int refuse_mschap :1; /* Don't proceed auth. with MS-CHAP */ + unsigned int refuse_mschap_v2 :1; /* Don't proceed auth. with MS-CHAPv2 */ +#endif /* MSCHAP_SUPPORT */ +#if EAP_SUPPORT + unsigned int refuse_eap :1; /* Don't proceed auth. with EAP */ +#endif /* EAP_SUPPORT */ +#if LWIP_DNS + unsigned int usepeerdns :1; /* Ask peer for DNS adds */ +#endif /* LWIP_DNS */ + unsigned int persist :1; /* Persist mode, always try to open the connection */ +#if PRINTPKT_SUPPORT + unsigned int hide_password :1; /* Hide password in dumped packets */ +#endif /* PRINTPKT_SUPPORT */ + unsigned int noremoteip :1; /* Let him have no IP address */ + unsigned int lax_recv :1; /* accept control chars in asyncmap */ + unsigned int noendpoint :1; /* don't send/accept endpoint discriminator */ +#if PPP_LCP_ADAPTIVE + unsigned int lcp_echo_adaptive :1; /* request echo only if the link was idle */ +#endif /* PPP_LCP_ADAPTIVE */ +#if MPPE_SUPPORT + unsigned int require_mppe :1; /* Require MPPE (Microsoft Point to Point Encryption) */ + unsigned int refuse_mppe_40 :1; /* Allow MPPE 40-bit mode? */ + unsigned int refuse_mppe_128 :1; /* Allow MPPE 128-bit mode? */ + unsigned int refuse_mppe_stateful :1; /* Allow MPPE stateful mode? */ +#endif /* MPPE_SUPPORT */ + + u16_t listen_time; /* time to listen first (ms), waiting for peer to send LCP packet */ + +#if PPP_IDLETIMELIMIT + u16_t idle_time_limit; /* Disconnect if idle for this many seconds */ +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT + u32_t maxconnect; /* Maximum connect time (seconds) */ +#endif /* PPP_MAXCONNECT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ + const char *user; /* Username for PAP */ + const char *passwd; /* Password for PAP, secret for CHAP */ +#if PPP_REMOTENAME + char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ +#endif /* PPP_REMOTENAME */ + +#if PAP_SUPPORT + u8_t pap_timeout_time; /* Timeout (seconds) for auth-req retrans. */ + u8_t pap_max_transmits; /* Number of auth-reqs sent */ +#if PPP_SERVER + u8_t pap_req_timeout; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* PAP_SUPPPORT */ + +#if CHAP_SUPPORT + u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ + u8_t chap_max_transmits; /* max # times to send challenge */ +#if PPP_SERVER + u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPPORT */ + +#if EAP_SUPPORT + u8_t eap_req_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_allow_req; /* Max Requests allowed */ +#if PPP_SERVER + u8_t eap_timeout_time; /* Time to wait (for retransmit/fail) */ + u8_t eap_max_transmits; /* Max Requests allowed */ +#endif /* PPP_SERVER */ +#endif /* EAP_SUPPORT */ + +#endif /* PPP_AUTH_SUPPORT */ + + u8_t fsm_timeout_time; /* Timeout time in seconds */ + u8_t fsm_max_conf_req_transmits; /* Maximum Configure-Request transmissions */ + u8_t fsm_max_term_transmits; /* Maximum Terminate-Request transmissions */ + u8_t fsm_max_nak_loops; /* Maximum number of nak loops tolerated */ + + u8_t lcp_loopbackfail; /* Number of times we receive our magic number from the peer + before deciding the link is looped-back. */ + u8_t lcp_echo_interval; /* Interval between LCP echo-requests */ + u8_t lcp_echo_fails; /* Tolerance to unanswered echo-requests */ + +} ppp_settings; + +#if PPP_SERVER +struct ppp_addrs { +#if PPP_IPV4_SUPPORT + ip4_addr_t our_ipaddr, his_ipaddr, netmask; +#if LWIP_DNS + ip4_addr_t dns1, dns2; +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + ip6_addr_t our6_ipaddr, his6_ipaddr; +#endif /* PPP_IPV6_SUPPORT */ +}; +#endif /* PPP_SERVER */ + +/* + * PPP interface control block. + */ +struct ppp_pcb_s { + ppp_settings settings; + const struct link_callbacks *link_cb; + void *link_ctx_cb; + void (*link_status_cb)(ppp_pcb *pcb, int err_code, void *ctx); /* Status change callback */ +#if PPP_NOTIFY_PHASE + void (*notify_phase_cb)(ppp_pcb *pcb, u8_t phase, void *ctx); /* Notify phase callback */ +#endif /* PPP_NOTIFY_PHASE */ + void *ctx_cb; /* Callbacks optional pointer */ + struct netif *netif; /* PPP interface */ + u8_t phase; /* where the link is at */ + u8_t err_code; /* Code indicating why interface is down. */ + + /* flags */ +#if PPP_IPV4_SUPPORT + unsigned int ask_for_local :1; /* request our address from peer */ + unsigned int ipcp_is_open :1; /* haven't called np_finished() */ + unsigned int ipcp_is_up :1; /* have called ipcp_up() */ + unsigned int if4_up :1; /* True when the IPv4 interface is up. */ +#if 0 /* UNUSED - PROXY ARP */ + unsigned int proxy_arp_set :1; /* Have created proxy arp entry */ +#endif /* UNUSED - PROXY ARP */ +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + unsigned int ipv6cp_is_up :1; /* have called ip6cp_up() */ + unsigned int if6_up :1; /* True when the IPv6 interface is up. */ +#endif /* PPP_IPV6_SUPPORT */ + unsigned int lcp_echo_timer_running :1; /* set if a timer is running */ +#if VJ_SUPPORT + unsigned int vj_enabled :1; /* Flag indicating VJ compression enabled. */ +#endif /* VJ_SUPPORT */ +#if CCP_SUPPORT + unsigned int ccp_all_rejected :1; /* we rejected all peer's options */ +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT + unsigned int mppe_keys_set :1; /* Have the MPPE keys been set? */ +#endif /* MPPE_SUPPORT */ + +#if PPP_AUTH_SUPPORT + /* auth data */ +#if PPP_SERVER && defined(HAVE_MULTILINK) + char peer_authname[MAXNAMELEN + 1]; /* The name by which the peer authenticated itself to us. */ +#endif /* PPP_SERVER && defined(HAVE_MULTILINK) */ + u16_t auth_pending; /* Records which authentication operations haven't completed yet. */ + u16_t auth_done; /* Records which authentication operations have been completed. */ + +#if PAP_SUPPORT + upap_state upap; /* PAP data */ +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + chap_client_state chap_client; /* CHAP client data */ +#if PPP_SERVER + chap_server_state chap_server; /* CHAP server data */ +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPORT */ + +#if EAP_SUPPORT + eap_state eap; /* EAP data */ +#endif /* EAP_SUPPORT */ +#endif /* PPP_AUTH_SUPPORT */ + + fsm lcp_fsm; /* LCP fsm structure */ + lcp_options lcp_wantoptions; /* Options that we want to request */ + lcp_options lcp_gotoptions; /* Options that peer ack'd */ + lcp_options lcp_allowoptions; /* Options we allow peer to request */ + lcp_options lcp_hisoptions; /* Options that we ack'd */ + u16_t peer_mru; /* currently negotiated peer MRU */ + u8_t lcp_echos_pending; /* Number of outstanding echo msgs */ + u8_t lcp_echo_number; /* ID number of next echo frame */ + + u8_t num_np_open; /* Number of network protocols which we have opened. */ + u8_t num_np_up; /* Number of network protocols which have come up. */ + +#if VJ_SUPPORT + struct vjcompress vj_comp; /* Van Jacobson compression header. */ +#endif /* VJ_SUPPORT */ + +#if CCP_SUPPORT + fsm ccp_fsm; /* CCP fsm structure */ + ccp_options ccp_wantoptions; /* what to request the peer to use */ + ccp_options ccp_gotoptions; /* what the peer agreed to do */ + ccp_options ccp_allowoptions; /* what we'll agree to do */ + ccp_options ccp_hisoptions; /* what we agreed to do */ + u8_t ccp_localstate; /* Local state (mainly for handling reset-reqs and reset-acks). */ + u8_t ccp_receive_method; /* Method chosen on receive path */ + u8_t ccp_transmit_method; /* Method chosen on transmit path */ +#if MPPE_SUPPORT + ppp_mppe_state mppe_comp; /* MPPE "compressor" structure */ + ppp_mppe_state mppe_decomp; /* MPPE "decompressor" structure */ +#endif /* MPPE_SUPPORT */ +#endif /* CCP_SUPPORT */ + +#if PPP_IPV4_SUPPORT + fsm ipcp_fsm; /* IPCP fsm structure */ + ipcp_options ipcp_wantoptions; /* Options that we want to request */ + ipcp_options ipcp_gotoptions; /* Options that peer ack'd */ + ipcp_options ipcp_allowoptions; /* Options we allow peer to request */ + ipcp_options ipcp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT + fsm ipv6cp_fsm; /* IPV6CP fsm structure */ + ipv6cp_options ipv6cp_wantoptions; /* Options that we want to request */ + ipv6cp_options ipv6cp_gotoptions; /* Options that peer ack'd */ + ipv6cp_options ipv6cp_allowoptions; /* Options we allow peer to request */ + ipv6cp_options ipv6cp_hisoptions; /* Options that we ack'd */ +#endif /* PPP_IPV6_SUPPORT */ +}; + +/************************ + *** PUBLIC FUNCTIONS *** + ************************/ + +/* + * WARNING: For multi-threads environment, all ppp_set_* functions most + * only be called while the PPP is in the dead phase (i.e. disconnected). + */ + +#if PPP_AUTH_SUPPORT +/* + * Set PPP authentication. + * + * Warning: Using PPPAUTHTYPE_ANY might have security consequences. + * RFC 1994 says: + * + * In practice, within or associated with each PPP server, there is a + * database which associates "user" names with authentication + * information ("secrets"). It is not anticipated that a particular + * named user would be authenticated by multiple methods. This would + * make the user vulnerable to attacks which negotiate the least secure + * method from among a set (such as PAP rather than CHAP). If the same + * secret was used, PAP would reveal the secret to be used later with + * CHAP. + * + * Instead, for each user name there should be an indication of exactly + * one method used to authenticate that user name. If a user needs to + * make use of different authentication methods under different + * circumstances, then distinct user names SHOULD be employed, each of + * which identifies exactly one authentication method. + * + * Default is none auth type, unset (NULL) user and passwd. + */ +#define PPPAUTHTYPE_NONE 0x00 +#define PPPAUTHTYPE_PAP 0x01 +#define PPPAUTHTYPE_CHAP 0x02 +#define PPPAUTHTYPE_MSCHAP 0x04 +#define PPPAUTHTYPE_MSCHAP_V2 0x08 +#define PPPAUTHTYPE_EAP 0x10 +#define PPPAUTHTYPE_ANY 0xff +void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd); + +/* + * If set, peer is required to authenticate. This is mostly necessary for PPP server support. + * + * Default is false. + */ +#define ppp_set_auth_required(ppp, boolval) (ppp->settings.auth_required = boolval) +#endif /* PPP_AUTH_SUPPORT */ + +#if PPP_IPV4_SUPPORT +/* + * Set PPP interface "our" and "his" IPv4 addresses. This is mostly necessary for PPP server + * support but it can also be used on a PPP link where each side choose its own IP address. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_ouraddr(ppp, addr) do { ppp->ipcp_wantoptions.ouraddr = ip4_addr_get_u32(addr); \ + ppp->ask_for_local = ppp->ipcp_wantoptions.ouraddr != 0; } while(0) +#define ppp_set_ipcp_hisaddr(ppp, addr) (ppp->ipcp_wantoptions.hisaddr = ip4_addr_get_u32(addr)) +#if LWIP_DNS +/* + * Set DNS server addresses that are sent if the peer asks for them. This is mostly necessary + * for PPP server support. + * + * Default is unset (0.0.0.0). + */ +#define ppp_set_ipcp_dnsaddr(ppp, index, addr) (ppp->ipcp_allowoptions.dnsaddr[index] = ip4_addr_get_u32(addr)) + +/* + * If set, we ask the peer for up to 2 DNS server addresses. Received DNS server addresses are + * registered using the dns_setserver() function. + * + * Default is false. + */ +#define ppp_set_usepeerdns(ppp, boolval) (ppp->settings.usepeerdns = boolval) +#endif /* LWIP_DNS */ +#endif /* PPP_IPV4_SUPPORT */ + +#if MPPE_SUPPORT +/* Disable MPPE (Microsoft Point to Point Encryption). This parameter is exclusive. */ +#define PPP_MPPE_DISABLE 0x00 +/* Require the use of MPPE (Microsoft Point to Point Encryption). */ +#define PPP_MPPE_ENABLE 0x01 +/* Allow MPPE to use stateful mode. Stateless mode is still attempted first. */ +#define PPP_MPPE_ALLOW_STATEFUL 0x02 +/* Refuse the use of MPPE with 40-bit encryption. Conflict with PPP_MPPE_REFUSE_128. */ +#define PPP_MPPE_REFUSE_40 0x04 +/* Refuse the use of MPPE with 128-bit encryption. Conflict with PPP_MPPE_REFUSE_40. */ +#define PPP_MPPE_REFUSE_128 0x08 +/* + * Set MPPE configuration + * + * Default is disabled. + */ +void ppp_set_mppe(ppp_pcb *pcb, u8_t flags); +#endif /* MPPE_SUPPORT */ + +/* + * Wait for up to intval milliseconds for a valid PPP packet from the peer. + * At the end of this time, or when a valid PPP packet is received from the + * peer, we commence negotiation by sending our first LCP packet. + * + * Default is 0. + */ +#define ppp_set_listen_time(ppp, intval) (ppp->settings.listen_time = intval) + +/* + * If set, we will attempt to initiate a connection but if no reply is received from + * the peer, we will then just wait passively for a valid LCP packet from the peer. + * + * Default is false. + */ +#define ppp_set_passive(ppp, boolval) (ppp->lcp_wantoptions.passive = boolval) + +/* + * If set, we will not transmit LCP packets to initiate a connection until a valid + * LCP packet is received from the peer. This is what we usually call the server mode. + * + * Default is false. + */ +#define ppp_set_silent(ppp, boolval) (ppp->lcp_wantoptions.silent = boolval) + +/* + * If set, enable protocol field compression negotiation in both the receive and + * the transmit direction. + * + * Default is true. + */ +#define ppp_set_neg_pcomp(ppp, boolval) (ppp->lcp_wantoptions.neg_pcompression = \ + ppp->lcp_allowoptions.neg_pcompression = boolval) + +/* + * If set, enable Address/Control compression in both the receive and the transmit + * direction. + * + * Default is true. + */ +#define ppp_set_neg_accomp(ppp, boolval) (ppp->lcp_wantoptions.neg_accompression = \ + ppp->lcp_allowoptions.neg_accompression = boolval) + +/* + * If set, enable asyncmap negotiation. Otherwise forcing all control characters to + * be escaped for both the transmit and the receive direction. + * + * Default is true. + */ +#define ppp_set_neg_asyncmap(ppp, boolval) (ppp->lcp_wantoptions.neg_asyncmap = \ + ppp->lcp_allowoptions.neg_asyncmap = boolval) + +/* + * This option sets the Async-Control-Character-Map (ACCM) for this end of the link. + * The ACCM is a set of 32 bits, one for each of the ASCII control characters with + * values from 0 to 31, where a 1 bit indicates that the corresponding control + * character should not be used in PPP packets sent to this system. The map is + * an unsigned 32 bits integer where the least significant bit (00000001) represents + * character 0 and the most significant bit (80000000) represents character 31. + * We will then ask the peer to send these characters as a 2-byte escape sequence. + * + * Default is 0. + */ +#define ppp_set_asyncmap(ppp, intval) (ppp->lcp_wantoptions.asyncmap = intval) + +/* + * Set a PPP interface as the default network interface + * (used to output all packets for which no specific route is found). + */ +#define ppp_set_default(ppp) netif_set_default(ppp->netif) + +#if PPP_NOTIFY_PHASE +/* + * Set a PPP notify phase callback. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +typedef void (*ppp_notify_phase_cb_fn)(ppp_pcb *pcb, u8_t phase, void *ctx); +void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ + +/* + * Initiate a PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * Holdoff is the time to wait (in seconds) before initiating + * the connection. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff); + +#if PPP_SERVER +/* + * Listen for an incoming PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +/* + * Initiate the end of a PPP connection. + * Any outstanding packets in the queues are dropped. + * + * Setting nocarrier to 1 close the PPP connection without initiating the + * shutdown procedure. Always using nocarrier = 0 is still recommended, + * this is going to take a little longer time if your link is down, but + * is a safer choice for the PPP state machine. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_close(ppp_pcb *pcb, u8_t nocarrier); + +/* + * Release the control block. + * + * This can only be called if PPP is in the dead phase. + * + * You must use ppp_close() before if you wish to terminate + * an established PPP session. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_free(ppp_pcb *pcb); + +/* + * PPP IOCTL commands. + * + * Get the up status - 0 for down, non-zero for up. The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 0 + +/* + * Get the PPP error code. The argument must point to an int. + * Returns a PPPERR_* value. + */ +#define PPPCTLG_ERRCODE 1 + +/* + * Get the fd associated with a PPP over serial + */ +#define PPPCTLG_FD 2 + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. + */ +err_t ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +/* Get the PPP netif interface */ +#define ppp_netif(ppp) (ppp->netif) + +/* Set an lwIP-style status-callback for the selected PPP device */ +#define ppp_set_netif_statuscallback(ppp, status_cb) \ + netif_set_status_callback(ppp->netif, status_cb); + +/* Set an lwIP-style link-callback for the selected PPP device */ +#define ppp_set_netif_linkcallback(ppp, link_cb) \ + netif_set_link_callback(ppp->netif, link_cb); + +#endif /* PPP_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_impl.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_impl.h new file mode 100644 index 0000000000..1d4c7742f3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_impl.h @@ -0,0 +1,629 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ +#ifndef LWIP_HDR_PPP_IMPL_H +#define LWIP_HDR_PPP_IMPL_H + +#include "netif/ppp/ppp_opts.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifdef PPP_INCLUDE_SETTINGS_HEADER +#include "ppp_settings.h" +#endif + +#include /* formats */ +#include +#include +#include /* strtol() */ + +#include "lwip/netif.h" +#include "lwip/def.h" +#include "lwip/timeouts.h" + +#include "ppp.h" +#include "pppdebug.h" + +/* + * Memory used for control packets. + * + * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we + * cannot figure out how much we are going to use before filling the buffer. + */ +#if PPP_USE_PBUF_RAM +#define PPP_CTRL_PBUF_TYPE PBUF_RAM +#define PPP_CTRL_PBUF_MAX_SIZE 512 +#else /* PPP_USE_PBUF_RAM */ +#define PPP_CTRL_PBUF_TYPE PBUF_POOL +#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE +#endif /* PPP_USE_PBUF_RAM */ + +/* + * The basic PPP frame. + */ +#define PPP_ADDRESS(p) (((u_char *)(p))[0]) +#define PPP_CONTROL(p) (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#if 0 /* UNUSED */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#endif /* UNUSED */ +#if VJ_SUPPORT +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#endif /* VJ_SUPPORT */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_COMP 0xfd /* compressed packet */ +#endif /* CCP_SUPPORT */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#if 0 /* UNUSED */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#endif /* UNUSED */ +#if PPP_IPV6_SUPPORT +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#endif /* ECP_SUPPORT */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#if PAP_SUPPORT +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#endif /* LQR_SUPPORT */ +#if CHAP_SUPPORT +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#endif /* CBCP_SUPPORT */ +#if EAP_SUPPORT +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ +#endif /* EAP_SUPPORT */ + +/* + * The following struct gives the addresses of procedures to call + * for a particular lower link level protocol. + */ +struct link_callbacks { + /* Start a connection (e.g. Initiate discovery phase) */ + void (*connect) (ppp_pcb *pcb, void *ctx); +#if PPP_SERVER + /* Listen for an incoming connection (Passive mode) */ + void (*listen) (ppp_pcb *pcb, void *ctx); +#endif /* PPP_SERVER */ + /* End a connection (i.e. initiate disconnect phase) */ + void (*disconnect) (ppp_pcb *pcb, void *ctx); + /* Free lower protocol control block */ + err_t (*free) (ppp_pcb *pcb, void *ctx); + /* Write a pbuf to a ppp link, only used from PPP functions to send PPP packets. */ + err_t (*write)(ppp_pcb *pcb, void *ctx, struct pbuf *p); + /* Send a packet from lwIP core (IPv4 or IPv6) */ + err_t (*netif_output)(ppp_pcb *pcb, void *ctx, struct pbuf *p, u_short protocol); + /* configure the transmit-side characteristics of the PPP interface */ + void (*send_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); + /* confire the receive-side characteristics of the PPP interface */ + void (*recv_config)(ppp_pcb *pcb, void *ctx, u32_t accm, int pcomp, int accomp); +}; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics. + */ +#if PPP_STATS_SUPPORT +struct pppstat { + unsigned int ppp_ibytes; /* bytes received */ + unsigned int ppp_ipackets; /* packets received */ + unsigned int ppp_ierrors; /* receive errors */ + unsigned int ppp_obytes; /* bytes sent */ + unsigned int ppp_opackets; /* packets sent */ + unsigned int ppp_oerrors; /* transmit errors */ +}; + +#if VJ_SUPPORT +struct vjstat { + unsigned int vjs_packets; /* outbound packets */ + unsigned int vjs_compressed; /* outbound compressed packets */ + unsigned int vjs_searches; /* searches for connection state */ + unsigned int vjs_misses; /* times couldn't find conn. state */ + unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ + unsigned int vjs_compressedin; /* inbound compressed packets */ + unsigned int vjs_errorin; /* inbound unknown type packets */ + unsigned int vjs_tossed; /* inbound packets tossed because of error */ +}; +#endif /* VJ_SUPPORT */ + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ +#if VJ_SUPPORT + struct vjstat vj; /* VJ header compression statistics */ +#endif /* VJ_SUPPORT */ +}; + +#if CCP_SUPPORT +struct compstat { + unsigned int unc_bytes; /* total uncompressed bytes */ + unsigned int unc_packets; /* total uncompressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned int comp_packets; /* compressed packets */ + unsigned int inc_bytes; /* incompressible bytes */ + unsigned int inc_packets; /* incompressible packets */ + unsigned int ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; +#endif /* CCP_SUPPORT */ + +#endif /* PPP_STATS_SUPPORT */ + +#if PPP_IDLETIMELIMIT +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; +#endif /* PPP_IDLETIMELIMIT */ + +/* values for epdisc.class */ +#define EPD_NULL 0 /* null discriminator, no data */ +#define EPD_LOCAL 1 +#define EPD_IP 2 +#define EPD_MAC 3 +#define EPD_MAGIC 4 +#define EPD_PHONENUM 5 + +/* + * Global variables. + */ +#ifdef HAVE_MULTILINK +extern u8_t multilink; /* enable multilink operation */ +extern u8_t doing_multilink; +extern u8_t multilink_master; +extern u8_t bundle_eof; +extern u8_t bundle_terminating; +#endif + +#ifdef MAXOCTETS +extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ +extern int maxoctets_dir; /* Direction : + 0 - in+out (default) + 1 - in + 2 - out + 3 - max(in,out) */ +extern int maxoctets_timeout; /* Timeout for check of octets limit */ +#define PPP_OCTETS_DIRECTION_SUM 0 +#define PPP_OCTETS_DIRECTION_IN 1 +#define PPP_OCTETS_DIRECTION_OUT 2 +#define PPP_OCTETS_DIRECTION_MAXOVERAL 3 +/* same as previos, but little different on RADIUS side */ +#define PPP_OCTETS_DIRECTION_MAXSESSION 4 +#endif + +/* Data input may be used by CCP and ECP, remove this entry + * from struct protent to save some flash + */ +#define PPP_DATAINPUT 0 + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { + u_short protocol; /* PPP protocol number */ + /* Initialization procedure */ + void (*init) (ppp_pcb *pcb); + /* Process a received packet */ + void (*input) (ppp_pcb *pcb, u_char *pkt, int len); + /* Process a received protocol-reject */ + void (*protrej) (ppp_pcb *pcb); + /* Lower layer has come up */ + void (*lowerup) (ppp_pcb *pcb); + /* Lower layer has gone down */ + void (*lowerdown) (ppp_pcb *pcb); + /* Open the protocol */ + void (*open) (ppp_pcb *pcb); + /* Close the protocol */ + void (*close) (ppp_pcb *pcb, const char *reason); +#if PRINTPKT_SUPPORT + /* Print a packet in readable form */ + int (*printpkt) (const u_char *pkt, int len, + void (*printer) (void *, const char *, ...), + void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + /* Process a received data packet */ + void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len); +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + const char *name; /* Text name of protocol */ + const char *data_name; /* Text name of corresponding data protocol */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + option_t *options; /* List of command-line options */ + /* Check requested options, assign defaults */ + void (*check_options) (void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + /* Configure interface for demand-dial */ + int (*demand_conf) (int unit); + /* Say whether to bring up link for this pkt */ + int (*active_pkt) (u_char *pkt, int len); +#endif /* DEMAND_SUPPORT */ +}; + +/* Table of pointers to supported protocols */ +extern const struct protent* const protocols[]; + + +/* Values for auth_pending, auth_done */ +#if PAP_SUPPORT +#define PAP_WITHPEER 0x1 +#define PAP_PEER 0x2 +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#define CHAP_WITHPEER 0x4 +#define CHAP_PEER 0x8 +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#define EAP_WITHPEER 0x10 +#define EAP_PEER 0x20 +#endif /* EAP_SUPPORT */ + +/* Values for auth_done only */ +#if CHAP_SUPPORT +#define CHAP_MD5_WITHPEER 0x40 +#define CHAP_MD5_PEER 0x80 +#if MSCHAP_SUPPORT +#define CHAP_MS_SHIFT 8 /* LSB position for MS auths */ +#define CHAP_MS_WITHPEER 0x100 +#define CHAP_MS_PEER 0x200 +#define CHAP_MS2_WITHPEER 0x400 +#define CHAP_MS2_PEER 0x800 +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ + +/* Supported CHAP protocols */ +#if CHAP_SUPPORT + +#if MSCHAP_SUPPORT +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) +#else /* MSCHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_MD5) +#endif /* MSCHAP_SUPPORT */ + +#else /* CHAP_SUPPORT */ +#define CHAP_MDTYPE_SUPPORTED (MDTYPE_NONE) +#endif /* CHAP_SUPPORT */ + +#if PPP_STATS_SUPPORT +/* + * PPP statistics structure + */ +struct pppd_stats { + unsigned int bytes_in; + unsigned int bytes_out; + unsigned int pkts_in; + unsigned int pkts_out; +}; +#endif /* PPP_STATS_SUPPORT */ + + +/* + * PPP private functions + */ + + +/* + * Functions called from lwIP core. + */ + +/* initialize the PPP subsystem */ +int ppp_init(void); + +/* + * Functions called from PPP link protocols. + */ + +/* Create a new PPP control block */ +ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* Initiate LCP open request */ +void ppp_start(ppp_pcb *pcb); + +/* Called when link failed to setup */ +void ppp_link_failed(ppp_pcb *pcb); + +/* Called when link is normally down (i.e. it was asked to end) */ +void ppp_link_end(ppp_pcb *pcb); + +/* function called to process input packet */ +void ppp_input(ppp_pcb *pcb, struct pbuf *pb); + +/* helper function, merge a pbuf chain into one pbuf */ +struct pbuf *ppp_singlebuf(struct pbuf *p); + + +/* + * Functions called by PPP protocols. + */ + +/* function called by all PPP subsystems to send packets */ +err_t ppp_write(ppp_pcb *pcb, struct pbuf *p); + +/* functions called by auth.c link_terminated() */ +void ppp_link_terminated(ppp_pcb *pcb); + +void new_phase(ppp_pcb *pcb, int p); + +int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp); +int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp); + +#if PPP_IPV4_SUPPORT +int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask); +int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr); +#if 0 /* UNUSED - PROXY ARP */ +int sifproxyarp(ppp_pcb *pcb, u32_t his_adr); +int cifproxyarp(ppp_pcb *pcb, u32_t his_adr); +#endif /* UNUSED - PROXY ARP */ +#if LWIP_DNS +int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); +#endif /* LWIP_DNS */ +#if VJ_SUPPORT +int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid); +#endif /* VJ_SUPPORT */ +int sifup(ppp_pcb *pcb); +int sifdown (ppp_pcb *pcb); +u32_t get_mask(u32_t addr); +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); +int sif6up(ppp_pcb *pcb); +int sif6down (ppp_pcb *pcb); +#endif /* PPP_IPV6_SUPPORT */ + +#if DEMAND_SUPPORT +int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); +#endif /* DEMAND_SUPPORt */ + +void netif_set_mtu(ppp_pcb *pcb, int mtu); +int netif_get_mtu(ppp_pcb *pcb); + +#if CCP_SUPPORT +#if 0 /* unused */ +int ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit); +#endif /* unused */ +void ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method); +void ccp_reset_comp(ppp_pcb *pcb); +void ccp_reset_decomp(ppp_pcb *pcb); +#if 0 /* unused */ +int ccp_fatal_error(ppp_pcb *pcb); +#endif /* unused */ +#endif /* CCP_SUPPORT */ + +#if PPP_IDLETIMELIMIT +int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip); +#endif /* PPP_IDLETIMELIMIT */ + +#if DEMAND_SUPPORT +int get_loop_output(void); +#endif /* DEMAND_SUPPORT */ + +/* Optional protocol names list, to make our messages a little more informative. */ +#if PPP_PROTOCOLNAME +const char * protocol_name(int proto); +#endif /* PPP_PROTOCOLNAME */ + +/* Optional stats support, to get some statistics on the PPP interface */ +#if PPP_STATS_SUPPORT +void print_link_stats(void); /* Print stats, if available */ +void reset_link_stats(int u); /* Reset (init) stats when link goes up */ +void update_link_stats(int u); /* Get stats at link termination */ +#endif /* PPP_STATS_SUPPORT */ + + + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ + (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ + *(cp)++ = (u_char) (c); \ +} +#define GETSHORT(s, cp) { \ + (s) = *(cp)++ << 8; \ + (s) |= *(cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s); \ +} +#define GETLONG(l, cp) { \ + (l) = *(cp)++ << 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; \ +} +#define PUTLONG(l, cp) { \ + *(cp)++ = (u_char) ((l) >> 24); \ + *(cp)++ = (u_char) ((l) >> 16); \ + *(cp)++ = (u_char) ((l) >> 8); \ + *(cp)++ = (u_char) (l); \ +} + +#define INCPTR(n, cp) ((cp) += (n)) +#define DECPTR(n, cp) ((cp) -= (n)) + +/* + * System dependent definitions for user-level 4.3BSD UNIX implementation. + */ +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) +#define TIMEOUTMS(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t), (f), (a)); } while(0) +#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) + +#define BZERO(s, n) memset(s, 0, n) +#define BCMP(s1, s2, l) memcmp(s1, s2, l) + +#define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } + +/* + * MAKEHEADER - Add Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/* Procedures exported from auth.c */ +void link_required(ppp_pcb *pcb); /* we are starting to use the link */ +void link_terminated(ppp_pcb *pcb); /* we are finished with the link */ +void link_down(ppp_pcb *pcb); /* the LCP layer has left the Opened state */ +void upper_layers_down(ppp_pcb *pcb); /* take all NCPs down */ +void link_established(ppp_pcb *pcb); /* the link is up; authenticate now */ +void start_networks(ppp_pcb *pcb); /* start all the network control protos */ +void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen); + /* check the user name and passwd against configuration */ +void auth_peer_fail(ppp_pcb *pcb, int protocol); + /* peer failed to authenticate itself */ +void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen); + /* peer successfully authenticated itself */ +#endif /* PPP_SERVER */ +void auth_withpeer_fail(ppp_pcb *pcb, int protocol); + /* we failed to authenticate ourselves */ +void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor); + /* we successfully authenticated ourselves */ +#endif /* PPP_AUTH_SUPPORT */ +void np_up(ppp_pcb *pcb, int proto); /* a network protocol has come up */ +void np_down(ppp_pcb *pcb, int proto); /* a network protocol has gone down */ +void np_finished(ppp_pcb *pcb, int proto); /* a network protocol no longer needs link */ +#if PPP_AUTH_SUPPORT +int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server); + /* get "secret" for chap */ +#endif /* PPP_AUTH_SUPPORT */ + +/* Procedures exported from ipcp.c */ +/* int parse_dotted_ip (char *, u32_t *); */ + +/* Procedures exported from demand.c */ +#if DEMAND_SUPPORT +void demand_conf (void); /* config interface(s) for demand-dial */ +void demand_block (void); /* set all NPs to queue up packets */ +void demand_unblock (void); /* set all NPs to pass packets */ +void demand_discard (void); /* set all NPs to discard packets */ +void demand_rexmit (int, u32_t); /* retransmit saved frames for an NP*/ +int loop_chars (unsigned char *, int); /* process chars from loopback */ +int loop_frame (unsigned char *, int); /* should we bring link up? */ +#endif /* DEMAND_SUPPORT */ + +/* Procedures exported from multilink.c */ +#ifdef HAVE_MULTILINK +void mp_check_options (void); /* Check multilink-related options */ +int mp_join_bundle (void); /* join our link to an appropriate bundle */ +void mp_exit_bundle (void); /* have disconnected our link from bundle */ +void mp_bundle_terminated (void); +char *epdisc_to_str (struct epdisc *); /* string from endpoint discrim. */ +int str_to_epdisc (struct epdisc *, char *); /* endpt disc. from str */ +#else +#define mp_bundle_terminated() /* nothing */ +#define mp_exit_bundle() /* nothing */ +#define doing_multilink 0 +#define multilink_master 0 +#endif + +/* Procedures exported from utils.c. */ +void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg); /* Format a string for output */ +int ppp_slprintf(char *buf, int buflen, const char *fmt, ...); /* sprintf++ */ +int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args); /* vsprintf++ */ +size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ +size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ +void ppp_dbglog(const char *fmt, ...); /* log a debug message */ +void ppp_info(const char *fmt, ...); /* log an informational message */ +void ppp_notice(const char *fmt, ...); /* log a notice-level message */ +void ppp_warn(const char *fmt, ...); /* log a warning message */ +void ppp_error(const char *fmt, ...); /* log an error message */ +void ppp_fatal(const char *fmt, ...); /* log an error message and die(1) */ +#if PRINTPKT_SUPPORT +void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len); + /* dump packet to debug log if interesting */ +#endif /* PRINTPKT_SUPPORT */ + + +#endif /* PPP_SUPPORT */ +#endif /* LWIP_HDR_PPP_IMPL_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_opts.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_opts.h new file mode 100644 index 0000000000..fa79c090f2 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/ppp_opts.h @@ -0,0 +1,593 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPP_OPTS_H +#define LWIP_PPP_OPTS_H + +#include "lwip/opt.h" + +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOL2TP_SUPPORT==1: Enable PPP Over L2TP + */ +#ifndef PPPOL2TP_SUPPORT +#define PPPOL2TP_SUPPORT 0 +#endif + +/** + * PPPOL2TP_AUTH_SUPPORT==1: Enable PPP Over L2TP Auth (enable MD5 support) + */ +#ifndef PPPOL2TP_AUTH_SUPPORT +#define PPPOL2TP_AUTH_SUPPORT PPPOL2TP_SUPPORT +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +/** + * LWIP_PPP_API==1: Enable PPP API (in pppapi.c) + */ +#ifndef LWIP_PPP_API +#define LWIP_PPP_API (PPP_SUPPORT && (NO_SYS == 0)) +#endif + +/** + * MEMP_NUM_PPP_PCB: the number of simultaneously active PPP + * connections (requires the PPP_SUPPORT option) + */ +#ifndef MEMP_NUM_PPP_PCB +#define MEMP_NUM_PPP_PCB 1 +#endif + +#if PPP_SUPPORT + +/** + * MEMP_NUM_PPPOS_INTERFACES: the number of concurrently active PPPoS + * interfaces (only used with PPPOS_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOS_INTERFACES +#define MEMP_NUM_PPPOS_INTERFACES MEMP_NUM_PPP_PCB +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPPOL2TP_INTERFACES: the number of concurrently active PPPoL2TP + * interfaces (only used with PPPOL2TP_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOL2TP_INTERFACES +#define MEMP_NUM_PPPOL2TP_INTERFACES 1 +#endif + +/** + * MEMP_NUM_PPP_API_MSG: Number of concurrent PPP API messages (in pppapi.c) + */ +#ifndef MEMP_NUM_PPP_API_MSG +#define MEMP_NUM_PPP_API_MSG 5 +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_INPROC_IRQ_SAFE==1 call pppos_input() using tcpip_callback(). + * + * Please read the "PPPoS input path" chapter in the PPP documentation about this option. + */ +#ifndef PPP_INPROC_IRQ_SAFE +#define PPP_INPROC_IRQ_SAFE 0 +#endif + +/** + * PRINTPKT_SUPPORT==1: Enable PPP print packet support + * + * Mandatory for debugging, it displays exchanged packet content in debug trace. + */ +#ifndef PRINTPKT_SUPPORT +#define PRINTPKT_SUPPORT 0 +#endif + +/** + * PPP_IPV4_SUPPORT==1: Enable PPP IPv4 support + */ +#ifndef PPP_IPV4_SUPPORT +#define PPP_IPV4_SUPPORT (LWIP_IPV4) +#endif + +/** + * PPP_IPV6_SUPPORT==1: Enable PPP IPv6 support + */ +#ifndef PPP_IPV6_SUPPORT +#define PPP_IPV6_SUPPORT (LWIP_IPV6) +#endif + +/** + * PPP_NOTIFY_PHASE==1: Support PPP notify phase support + * + * PPP notify phase support allows you to set a callback which is + * called on change of the internal PPP state machine. + * + * This can be used for example to set a LED pattern depending on the + * current phase of the PPP session. + */ +#ifndef PPP_NOTIFY_PHASE +#define PPP_NOTIFY_PHASE 0 +#endif + +/** + * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets. + * + * Memory allocated must be single buffered for PPP to works, it requires pbuf + * that are not going to be chained when allocated. This requires setting + * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. + * + * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous + * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. + */ +#ifndef PPP_USE_PBUF_RAM +#define PPP_USE_PBUF_RAM 0 +#endif + +/** + * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS + */ +#ifndef PPP_FCS_TABLE +#define PPP_FCS_TABLE 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif +#if MSCHAP_SUPPORT +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MSCHAP_SUPPORT */ + +/** + * EAP_SUPPORT==1: Support EAP. + */ +#ifndef EAP_SUPPORT +#define EAP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * MPPE_SUPPORT==1: Support MPPE. + */ +#ifndef MPPE_SUPPORT +#define MPPE_SUPPORT 0 +#endif +#if MPPE_SUPPORT +/* MPPE requires CCP support */ +#undef CCP_SUPPORT +#define CCP_SUPPORT 1 +/* MPPE requires MSCHAP support */ +#undef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 1 +/* MSCHAP requires CHAP support */ +#undef CHAP_SUPPORT +#define CHAP_SUPPORT 1 +#endif /* MPPE_SUPPORT */ + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * ECP_SUPPORT==1: Support ECP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef ECP_SUPPORT +#define ECP_SUPPORT 0 +#endif + +/** + * DEMAND_SUPPORT==1: Support dial on demand. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef DEMAND_SUPPORT +#define DEMAND_SUPPORT 0 +#endif + +/** + * LQR_SUPPORT==1: Support Link Quality Report. Do nothing except exchanging some LCP packets. + */ +#ifndef LQR_SUPPORT +#define LQR_SUPPORT 0 +#endif + +/** + * PPP_SERVER==1: Enable PPP server support (waiting for incoming PPP session). + * + * Currently only supported for PPPoS. + */ +#ifndef PPP_SERVER +#define PPP_SERVER 0 +#endif + +#if PPP_SERVER +/* + * PPP_OUR_NAME: Our name for authentication purposes + */ +#ifndef PPP_OUR_NAME +#define PPP_OUR_NAME "lwIP" +#endif +#endif /* PPP_SERVER */ + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 1 +#endif +/* VJ compression is only supported for TCP over IPv4 over PPPoS. */ +#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP +#undef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif /* !PPPOS_SUPPORT */ + +/** + * PPP_MD5_RANDM==1: Use MD5 for better randomness. + * Enabled by default if CHAP, EAP, or L2TP AUTH support is enabled. + */ +#ifndef PPP_MD5_RANDM +#define PPP_MD5_RANDM (CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT) +#endif + +/** + * PolarSSL embedded library + * + * + * lwIP contains some files fetched from the latest BSD release of + * the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption + * methods we need for lwIP PPP support. + * + * The PolarSSL files were cleaned to contain only the necessary struct + * fields and functions needed for lwIP. + * + * The PolarSSL API was not changed at all, so if you are already using + * PolarSSL you can choose to skip the compilation of the included PolarSSL + * library into lwIP. + * + * If you are not using the embedded copy you must include external + * libraries into your arch/cc.h port file. + * + * Beware of the stack requirements which can be a lot larger if you are not + * using our cleaned PolarSSL library. + */ + +/** + * LWIP_USE_EXTERNAL_POLARSSL: Use external PolarSSL library + */ +#ifndef LWIP_USE_EXTERNAL_POLARSSL +#define LWIP_USE_EXTERNAL_POLARSSL 0 +#endif + +/** + * LWIP_USE_EXTERNAL_MBEDTLS: Use external mbed TLS library + */ +#ifndef LWIP_USE_EXTERNAL_MBEDTLS +#define LWIP_USE_EXTERNAL_MBEDTLS 0 +#endif + +/* + * PPP Timeouts + */ + +/** + * FSM_DEFTIMEOUT: Timeout time in seconds + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 +#endif + +/** + * FSM_DEFMAXTERMREQS: Maximum Terminate-Request transmissions + */ +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 +#endif + +/** + * FSM_DEFMAXCONFREQS: Maximum Configure-Request transmissions + */ +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 +#endif + +/** + * FSM_DEFMAXNAKLOOPS: Maximum number of nak loops + */ +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 +#endif + +/** + * UPAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 +#endif + +/** + * UPAP_DEFTRANSMITS: Maximum number of auth-reqs to send + */ +#ifndef UPAP_DEFTRANSMITS +#define UPAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * UPAP_DEFREQTIME: Time to wait for auth-req from peer + */ +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 +#endif +#endif /* PPP_SERVER */ + +/** + * CHAP_DEFTIMEOUT: Timeout (seconds) for retransmitting req + */ +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 +#endif + +/** + * CHAP_DEFTRANSMITS: max # times to send challenge + */ +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 +#endif + +#if PPP_SERVER +/** + * CHAP_DEFRECHALLENGETIME: If this option is > 0, rechallenge the peer every n seconds + */ +#ifndef CHAP_DEFRECHALLENGETIME +#define CHAP_DEFRECHALLENGETIME 0 +#endif +#endif /* PPP_SERVER */ + +/** + * EAP_DEFREQTIME: Time to wait for peer request + */ +#ifndef EAP_DEFREQTIME +#define EAP_DEFREQTIME 6 +#endif + +/** + * EAP_DEFALLOWREQ: max # times to accept requests + */ +#ifndef EAP_DEFALLOWREQ +#define EAP_DEFALLOWREQ 10 +#endif + +#if PPP_SERVER +/** + * EAP_DEFTIMEOUT: Timeout (seconds) for rexmit + */ +#ifndef EAP_DEFTIMEOUT +#define EAP_DEFTIMEOUT 6 +#endif + +/** + * EAP_DEFTRANSMITS: max # times to transmit + */ +#ifndef EAP_DEFTRANSMITS +#define EAP_DEFTRANSMITS 10 +#endif +#endif /* PPP_SERVER */ + +/** + * LCP_DEFLOOPBACKFAIL: Default number of times we receive our magic number from the peer + * before deciding the link is looped-back. + */ +#ifndef LCP_DEFLOOPBACKFAIL +#define LCP_DEFLOOPBACKFAIL 10 +#endif + +/** + * LCP_ECHOINTERVAL: Interval in seconds between keepalive echo requests, 0 to disable. + */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/** + * LCP_MAXECHOFAILS: Number of unanswered echo requests before failure. + */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/** + * PPP_MAXIDLEFLAG: Max Xmit idle time (in ms) before resend flag char. + */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/** + * PPP Packet sizes + */ + +/** + * PPP_MRU: Default MRU + */ +#ifndef PPP_MRU +#define PPP_MRU 1500 +#endif + +/** + * PPP_DEFMRU: Default MRU to try + */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 1500 +#endif + +/** + * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384) + */ +#ifndef PPP_MAXMRU +#define PPP_MAXMRU 1500 +#endif + +/** + * PPP_MINMRU: No MRUs below this + */ +#ifndef PPP_MINMRU +#define PPP_MINMRU 128 +#endif + +/** + * PPPOL2TP_DEFMRU: Default MTU and MRU for L2TP + * Default = 1500 - PPPoE(6) - PPP Protocol(2) - IPv4 header(20) - UDP Header(8) + * - L2TP Header(6) - HDLC Header(2) - PPP Protocol(2) - MPPE Header(2) - PPP Protocol(2) + */ +#if PPPOL2TP_SUPPORT +#ifndef PPPOL2TP_DEFMRU +#define PPPOL2TP_DEFMRU 1450 +#endif +#endif /* PPPOL2TP_SUPPORT */ + +/** + * MAXNAMELEN: max length of hostname or name for auth + */ +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 +#endif + +/** + * MAXSECRETLEN: max length of password or secret + */ +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Build triggers for embedded PolarSSL + */ +#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS + +/* CHAP, EAP, L2TP AUTH and MD5 Random require MD5 support */ +#if CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#endif /* CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM */ + +#if MSCHAP_SUPPORT + +/* MSCHAP require MD4 support */ +#define LWIP_INCLUDED_POLARSSL_MD4 1 +/* MSCHAP require SHA1 support */ +#define LWIP_INCLUDED_POLARSSL_SHA1 1 +/* MSCHAP require DES support */ +#define LWIP_INCLUDED_POLARSSL_DES 1 + +/* MS-CHAP support is required for MPPE */ +#if MPPE_SUPPORT +/* MPPE require ARC4 support */ +#define LWIP_INCLUDED_POLARSSL_ARC4 1 +#endif /* MPPE_SUPPORT */ + +#endif /* MSCHAP_SUPPORT */ + +#endif /* !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* Default value if unset */ +#ifndef LWIP_INCLUDED_POLARSSL_MD4 +#define LWIP_INCLUDED_POLARSSL_MD4 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD4 */ +#ifndef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 0 +#endif /* LWIP_INCLUDED_POLARSSL_MD5 */ +#ifndef LWIP_INCLUDED_POLARSSL_SHA1 +#define LWIP_INCLUDED_POLARSSL_SHA1 0 +#endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ +#ifndef LWIP_INCLUDED_POLARSSL_DES +#define LWIP_INCLUDED_POLARSSL_DES 0 +#endif /* LWIP_INCLUDED_POLARSSL_DES */ +#ifndef LWIP_INCLUDED_POLARSSL_ARC4 +#define LWIP_INCLUDED_POLARSSL_ARC4 0 +#endif /* LWIP_INCLUDED_POLARSSL_ARC4 */ + +#endif /* PPP_SUPPORT */ + +#endif /* LWIP_PPP_OPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppapi.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppapi.h new file mode 100644 index 0000000000..913d93f749 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppapi.h @@ -0,0 +1,137 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PPPAPI_H +#define LWIP_PPPAPI_H + +#include "netif/ppp/ppp_opts.h" + +#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/priv/tcpip_priv.h" +#include "netif/ppp/ppp.h" +#if PPPOS_SUPPORT +#include "netif/ppp/pppos.h" +#endif /* PPPOS_SUPPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct pppapi_msg_msg { + ppp_pcb *ppp; + union { +#if PPP_NOTIFY_PHASE + struct { + ppp_notify_phase_cb_fn notify_phase_cb; + } setnotifyphasecb; +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT + struct { + struct netif *pppif; + pppos_output_cb_fn output_cb; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } serialcreate; +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT + struct { + struct netif *pppif; + struct netif *ethif; + const char *service_name; + const char *concentrator_name; + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } ethernetcreate; +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT + struct { + struct netif *pppif; + struct netif *netif; + API_MSG_M_DEF_C(ip_addr_t, ipaddr); + u16_t port; +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; + u8_t secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + ppp_link_status_cb_fn link_status_cb; + void *ctx_cb; + } l2tpcreate; +#endif /* PPPOL2TP_SUPPORT */ + struct { + u16_t holdoff; + } connect; + struct { + u8_t nocarrier; + } close; + struct { + u8_t cmd; + void *arg; + } ioctl; + } msg; +}; + +struct pppapi_msg { + struct tcpip_api_call_data call; + struct pppapi_msg_msg msg; +}; + +/* API for application */ +err_t pppapi_set_default(ppp_pcb *pcb); +#if PPP_NOTIFY_PHASE +err_t pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); +#endif /* PPP_NOTIFY_PHASE */ +#if PPPOS_SUPPORT +ppp_pcb *pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT +ppp_pcb *pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, + const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, + void *ctx_cb); +#endif /* PPPOE_SUPPORT */ +#if PPPOL2TP_SUPPORT +ppp_pcb *pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); +#endif /* PPPOL2TP_SUPPORT */ +err_t pppapi_connect(ppp_pcb *pcb, u16_t holdoff); +#if PPP_SERVER +err_t pppapi_listen(ppp_pcb *pcb); +#endif /* PPP_SERVER */ +err_t pppapi_close(ppp_pcb *pcb, u8_t nocarrier); +err_t pppapi_free(ppp_pcb *pcb); +err_t pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PPP_API */ + +#endif /* LWIP_PPPAPI_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppcrypt.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppcrypt.h new file mode 100644 index 0000000000..a7b2099f25 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppcrypt.h @@ -0,0 +1,136 @@ +/* + * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 + * + * Extracted from chap_ms.c by James Carlson. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* This header file is included in all PPP modules needing hashes and/or ciphers */ + +#ifndef PPPCRYPT_H +#define PPPCRYPT_H + +/* + * If included PolarSSL copy is not used, user is expected to include + * external libraries in arch/cc.h (which is included by lwip/arch.h). + */ +#include "lwip/arch.h" + +/* + * Map hashes and ciphers functions to PolarSSL + */ +#if !LWIP_USE_EXTERNAL_MBEDTLS + +#include "netif/ppp/polarssl/md4.h" +#define lwip_md4_context md4_context +#define lwip_md4_init(context) +#define lwip_md4_starts md4_starts +#define lwip_md4_update md4_update +#define lwip_md4_finish md4_finish +#define lwip_md4_free(context) + +#include "netif/ppp/polarssl/md5.h" +#define lwip_md5_context md5_context +#define lwip_md5_init(context) +#define lwip_md5_starts md5_starts +#define lwip_md5_update md5_update +#define lwip_md5_finish md5_finish +#define lwip_md5_free(context) + +#include "netif/ppp/polarssl/sha1.h" +#define lwip_sha1_context sha1_context +#define lwip_sha1_init(context) +#define lwip_sha1_starts sha1_starts +#define lwip_sha1_update sha1_update +#define lwip_sha1_finish sha1_finish +#define lwip_sha1_free(context) + +#include "netif/ppp/polarssl/des.h" +#define lwip_des_context des_context +#define lwip_des_init(context) +#define lwip_des_setkey_enc des_setkey_enc +#define lwip_des_crypt_ecb des_crypt_ecb +#define lwip_des_free(context) + +#include "netif/ppp/polarssl/arc4.h" +#define lwip_arc4_context arc4_context +#define lwip_arc4_init(context) +#define lwip_arc4_setup arc4_setup +#define lwip_arc4_crypt arc4_crypt +#define lwip_arc4_free(context) + +#endif /* !LWIP_USE_EXTERNAL_MBEDTLS */ + +/* + * Map hashes and ciphers functions to mbed TLS + */ +#if LWIP_USE_EXTERNAL_MBEDTLS + +#define lwip_md4_context mbedtls_md4_context +#define lwip_md4_init mbedtls_md4_init +#define lwip_md4_starts mbedtls_md4_starts +#define lwip_md4_update mbedtls_md4_update +#define lwip_md4_finish mbedtls_md4_finish +#define lwip_md4_free mbedtls_md4_free + +#define lwip_md5_context mbedtls_md5_context +#define lwip_md5_init mbedtls_md5_init +#define lwip_md5_starts mbedtls_md5_starts +#define lwip_md5_update mbedtls_md5_update +#define lwip_md5_finish mbedtls_md5_finish +#define lwip_md5_free mbedtls_md5_free + +#define lwip_sha1_context mbedtls_sha1_context +#define lwip_sha1_init mbedtls_sha1_init +#define lwip_sha1_starts mbedtls_sha1_starts +#define lwip_sha1_update mbedtls_sha1_update +#define lwip_sha1_finish mbedtls_sha1_finish +#define lwip_sha1_free mbedtls_sha1_free + +#define lwip_des_context mbedtls_des_context +#define lwip_des_init mbedtls_des_init +#define lwip_des_setkey_enc mbedtls_des_setkey_enc +#define lwip_des_crypt_ecb mbedtls_des_crypt_ecb +#define lwip_des_free mbedtls_des_free + +#define lwip_arc4_context mbedtls_arc4_context +#define lwip_arc4_init mbedtls_arc4_init +#define lwip_arc4_setup mbedtls_arc4_setup +#define lwip_arc4_crypt(context, buffer, length) mbedtls_arc4_crypt(context, length, buffer, buffer) +#define lwip_arc4_free mbedtls_arc4_free + +#endif /* LWIP_USE_EXTERNAL_MBEDTLS */ + +void pppcrypt_56_to_64_bit_key(u_char *key, u_char *des_key); + +#endif /* PPPCRYPT_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppdebug.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppdebug.h new file mode 100644 index 0000000000..7ead045910 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppdebug.h @@ -0,0 +1,80 @@ +/***************************************************************************** +* pppdebug.h - System debugging utilities. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* portions Copyright (c) 2001 by Cognizant Pty Ltd. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY (please don't use tabs!) +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-07-29 Guy Lancaster , Global Election Systems Inc. +* Original. +* +***************************************************************************** +*/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPDEBUG_H +#define PPPDEBUG_H + +/* Trace levels. */ +#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_INFO (PPP_DEBUG) +#define LOG_DETAIL (PPP_DEBUG) +#define LOG_DEBUG (PPP_DEBUG) + +#if PPP_DEBUG + +#define MAINDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define SYSDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define FSMDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define LCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define IPV6CPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define UPAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define CHAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) +#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) + +#else /* PPP_DEBUG */ + +#define MAINDEBUG(a) +#define SYSDEBUG(a) +#define FSMDEBUG(a) +#define LCPDEBUG(a) +#define IPCPDEBUG(a) +#define IPV6CPDEBUG(a) +#define UPAPDEBUG(a) +#define CHAPDEBUG(a) +#define PPPDEBUG(a, b) + +#endif /* PPP_DEBUG */ + +#endif /* PPPDEBUG_H */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppoe.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppoe.h new file mode 100644 index 0000000000..9f8f2892b4 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppoe.h @@ -0,0 +1,179 @@ +/***************************************************************************** +* pppoe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "ppp.h" +#include "lwip/etharp.h" + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { + PACK_STRUCT_FLD_8(u8_t vertype); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +/* passive */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif + +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + ppp_pcb *pcb; /* PPP PCB */ + + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + u8_t sc_state; /* discovery phase or session connected */ + +#ifdef PPPOE_TODO + u8_t *sc_service_name; /* if != NULL: requested name of service */ + u8_t *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_TODO */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + u8_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + u8_t sc_hunique_len; /* length of host unique */ +#endif + u8_t sc_padi_retried; /* number of PADI retries already done */ + u8_t sc_padr_retried; /* number of PADR retries already done */ +}; + + +#define pppoe_init() /* compatibility define, no initialization needed */ + +ppp_pcb *pppoe_create(struct netif *pppif, + struct netif *ethif, + const char *service_name, const char *concentrator_name, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +#endif /* PPP_OE_H */ + +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppol2tp.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppol2tp.h new file mode 100644 index 0000000000..f03950e65d --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppol2tp.h @@ -0,0 +1,201 @@ +/** + * @file + * Network Point to Point Protocol over Layer 2 Tunneling Protocol header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOL2TP_H +#define PPPOL2TP_H + +#include "ppp.h" + +/* Timeout */ +#define PPPOL2TP_CONTROL_TIMEOUT (5*1000) /* base for quick timeout calculation */ +#define PPPOL2TP_SLOW_RETRY (60*1000) /* persistent retry interval */ + +#define PPPOL2TP_MAXSCCRQ 4 /* retry SCCRQ four times (quickly) */ +#define PPPOL2TP_MAXICRQ 4 /* retry IRCQ four times */ +#define PPPOL2TP_MAXICCN 4 /* retry ICCN four times */ + +/* L2TP header flags */ +#define PPPOL2TP_HEADERFLAG_CONTROL 0x8000 +#define PPPOL2TP_HEADERFLAG_LENGTH 0x4000 +#define PPPOL2TP_HEADERFLAG_SEQUENCE 0x0800 +#define PPPOL2TP_HEADERFLAG_OFFSET 0x0200 +#define PPPOL2TP_HEADERFLAG_PRIORITY 0x0100 +#define PPPOL2TP_HEADERFLAG_VERSION 0x0002 + +/* Mandatory bits for control: Control, Length, Sequence, Version 2 */ +#define PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY (PPPOL2TP_HEADERFLAG_CONTROL|PPPOL2TP_HEADERFLAG_LENGTH|PPPOL2TP_HEADERFLAG_SEQUENCE|PPPOL2TP_HEADERFLAG_VERSION) +/* Forbidden bits for control: Offset, Priority */ +#define PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN (PPPOL2TP_HEADERFLAG_OFFSET|PPPOL2TP_HEADERFLAG_PRIORITY) + +/* Mandatory bits for data: Version 2 */ +#define PPPOL2TP_HEADERFLAG_DATA_MANDATORY (PPPOL2TP_HEADERFLAG_VERSION) + +/* AVP (Attribute Value Pair) header */ +#define PPPOL2TP_AVPHEADERFLAG_MANDATORY 0x8000 +#define PPPOL2TP_AVPHEADERFLAG_HIDDEN 0x4000 +#define PPPOL2TP_AVPHEADERFLAG_LENGTHMASK 0x03ff + +/* -- AVP - Message type */ +#define PPPOL2TP_AVPTYPE_MESSAGE 0 /* Message type */ + +/* Control Connection Management */ +#define PPPOL2TP_MESSAGETYPE_SCCRQ 1 /* Start Control Connection Request */ +#define PPPOL2TP_MESSAGETYPE_SCCRP 2 /* Start Control Connection Reply */ +#define PPPOL2TP_MESSAGETYPE_SCCCN 3 /* Start Control Connection Connected */ +#define PPPOL2TP_MESSAGETYPE_STOPCCN 4 /* Stop Control Connection Notification */ +#define PPPOL2TP_MESSAGETYPE_HELLO 6 /* Hello */ +/* Call Management */ +#define PPPOL2TP_MESSAGETYPE_OCRQ 7 /* Outgoing Call Request */ +#define PPPOL2TP_MESSAGETYPE_OCRP 8 /* Outgoing Call Reply */ +#define PPPOL2TP_MESSAGETYPE_OCCN 9 /* Outgoing Call Connected */ +#define PPPOL2TP_MESSAGETYPE_ICRQ 10 /* Incoming Call Request */ +#define PPPOL2TP_MESSAGETYPE_ICRP 11 /* Incoming Call Reply */ +#define PPPOL2TP_MESSAGETYPE_ICCN 12 /* Incoming Call Connected */ +#define PPPOL2TP_MESSAGETYPE_CDN 14 /* Call Disconnect Notify */ +/* Error reporting */ +#define PPPOL2TP_MESSAGETYPE_WEN 15 /* WAN Error Notify */ +/* PPP Session Control */ +#define PPPOL2TP_MESSAGETYPE_SLI 16 /* Set Link Info */ + +/* -- AVP - Result code */ +#define PPPOL2TP_AVPTYPE_RESULTCODE 1 /* Result code */ +#define PPPOL2TP_RESULTCODE 1 /* General request to clear control connection */ + +/* -- AVP - Protocol version (!= L2TP Header version) */ +#define PPPOL2TP_AVPTYPE_VERSION 2 +#define PPPOL2TP_VERSION 0x0100 /* L2TP Protocol version 1, revision 0 */ + +/* -- AVP - Framing capabilities */ +#define PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES 3 /* Bearer capabilities */ +#define PPPOL2TP_FRAMINGCAPABILITIES 0x00000003 /* Async + Sync framing */ + +/* -- AVP - Bearer capabilities */ +#define PPPOL2TP_AVPTYPE_BEARERCAPABILITIES 4 /* Bearer capabilities */ +#define PPPOL2TP_BEARERCAPABILITIES 0x00000003 /* Analog + Digital Access */ + +/* -- AVP - Tie breaker */ +#define PPPOL2TP_AVPTYPE_TIEBREAKER 5 + +/* -- AVP - Host name */ +#define PPPOL2TP_AVPTYPE_HOSTNAME 7 /* Host name */ +#define PPPOL2TP_HOSTNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Vendor name */ +#define PPPOL2TP_AVPTYPE_VENDORNAME 8 /* Vendor name */ +#define PPPOL2TP_VENDORNAME "lwIP" /* FIXME: make it configurable */ + +/* -- AVP - Assign tunnel ID */ +#define PPPOL2TP_AVPTYPE_TUNNELID 9 /* Assign Tunnel ID */ + +/* -- AVP - Receive window size */ +#define PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE 10 /* Receive window size */ +#define PPPOL2TP_RECEIVEWINDOWSIZE 8 /* FIXME: make it configurable */ + +/* -- AVP - Challenge */ +#define PPPOL2TP_AVPTYPE_CHALLENGE 11 /* Challenge */ + +/* -- AVP - Cause code */ +#define PPPOL2TP_AVPTYPE_CAUSECODE 12 /* Cause code*/ + +/* -- AVP - Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE 13 /* Challenge response */ +#define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE 16 + +/* -- AVP - Assign session ID */ +#define PPPOL2TP_AVPTYPE_SESSIONID 14 /* Assign Session ID */ + +/* -- AVP - Call serial number */ +#define PPPOL2TP_AVPTYPE_CALLSERIALNUMBER 15 /* Call Serial Number */ + +/* -- AVP - Framing type */ +#define PPPOL2TP_AVPTYPE_FRAMINGTYPE 19 /* Framing Type */ +#define PPPOL2TP_FRAMINGTYPE 0x00000001 /* Sync framing */ + +/* -- AVP - TX Connect Speed */ +#define PPPOL2TP_AVPTYPE_TXCONNECTSPEED 24 /* TX Connect Speed */ +#define PPPOL2TP_TXCONNECTSPEED 100000000 /* Connect speed: 100 Mbits/s */ + +/* L2TP Session state */ +#define PPPOL2TP_STATE_INITIAL 0 +#define PPPOL2TP_STATE_SCCRQ_SENT 1 +#define PPPOL2TP_STATE_ICRQ_SENT 2 +#define PPPOL2TP_STATE_ICCN_SENT 3 +#define PPPOL2TP_STATE_DATA 4 + +#define PPPOL2TP_OUTPUT_DATA_HEADER_LEN 6 /* Our data header len */ + +/* + * PPPoL2TP interface control block. + */ +typedef struct pppol2tp_pcb_s pppol2tp_pcb; +struct pppol2tp_pcb_s { + ppp_pcb *ppp; /* PPP PCB */ + u8_t phase; /* L2TP phase */ + struct udp_pcb *udp; /* UDP L2TP Socket */ + struct netif *netif; /* Output interface, used as a default route */ + ip_addr_t remote_ip; /* LNS IP Address */ + u16_t remote_port; /* LNS port */ +#if PPPOL2TP_AUTH_SUPPORT + const u8_t *secret; /* Secret string */ + u8_t secret_len; /* Secret string length */ + u8_t secret_rv[16]; /* Random vector */ + u8_t challenge_hash[16]; /* Challenge response */ + u8_t send_challenge; /* Boolean whether the next sent packet should contains a challenge response */ +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + u16_t tunnel_port; /* Tunnel port */ + u16_t our_ns; /* NS to peer */ + u16_t peer_nr; /* NR from peer */ + u16_t peer_ns; /* NS from peer */ + u16_t source_tunnel_id; /* Tunnel ID assigned by peer */ + u16_t remote_tunnel_id; /* Tunnel ID assigned to peer */ + u16_t source_session_id; /* Session ID assigned by peer */ + u16_t remote_session_id; /* Session ID assigned to peer */ + + u8_t sccrq_retried; /* number of SCCRQ retries already done */ + u8_t icrq_retried; /* number of ICRQ retries already done */ + u8_t iccn_retried; /* number of ICCN retries already done */ +}; + + +/* Create a new L2TP session. */ +ppp_pcb *pppol2tp_create(struct netif *pppif, + struct netif *netif, const ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#endif /* PPPOL2TP_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppos.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppos.h new file mode 100644 index 0000000000..d924a9fc7e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/pppos.h @@ -0,0 +1,118 @@ +/** + * @file + * Network Point to Point Protocol over Serial header file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef PPPOS_H +#define PPPOS_H + +#include "lwip/sys.h" + +#include "ppp.h" +#include "vj.h" + +/* PPP packet parser states. Current state indicates operation yet to be + * completed. */ +enum { + PDIDLE = 0, /* Idle state - waiting. */ + PDSTART, /* Process start flag. */ + PDADDRESS, /* Process address field. */ + PDCONTROL, /* Process control field. */ + PDPROTOCOL1, /* Process protocol field 1. */ + PDPROTOCOL2, /* Process protocol field 2. */ + PDDATA /* Process data byte. */ +}; + +/* PPPoS serial output callback function prototype */ +typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx); + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u8_t ext_accm[32]; + +/* + * PPPoS interface control block. + */ +typedef struct pppos_pcb_s pppos_pcb; +struct pppos_pcb_s { + /* -- below are data that will NOT be cleared between two sessions */ + ppp_pcb *ppp; /* PPP PCB */ + pppos_output_cb_fn output_cb; /* PPP serial output callback */ + + /* -- below are data that will be cleared between two sessions + * + * last_xmit must be the first member of cleared members, because it is + * used to know which part must not be cleared. + */ + u32_t last_xmit; /* Time of last transmission. */ + ext_accm out_accm; /* Async-Ctl-Char-Map for output. */ + + /* flags */ + unsigned int open :1; /* Set if PPPoS is open */ + unsigned int pcomp :1; /* Does peer accept protocol compression? */ + unsigned int accomp :1; /* Does peer accept addr/ctl compression? */ + + /* PPPoS rx */ + ext_accm in_accm; /* Async-Ctl-Char-Map for input. */ + struct pbuf *in_head, *in_tail; /* The input packet. */ + u16_t in_protocol; /* The input protocol code. */ + u16_t in_fcs; /* Input Frame Check Sequence value. */ + u8_t in_state; /* The input process state. */ + u8_t in_escaped; /* Escape next character. */ +}; + +/* Create a new PPPoS session. */ +ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb); + +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +/* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */ +err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +/* PPP over Serial: this is the input function to be called for received data. */ +void pppos_input(ppp_pcb *ppp, u8_t* data, int len); + + +/* + * Functions called from lwIP + * DO NOT CALL FROM lwIP USER APPLICATION. + */ +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +err_t pppos_input_sys(struct pbuf *p, struct netif *inp); +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +#endif /* PPPOS_H */ +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/upap.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/upap.h new file mode 100644 index 0000000000..7da792ecc7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/upap.h @@ -0,0 +1,123 @@ +/* + * upap.h - User/Password Authentication Protocol definitions. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: upap.h,v 1.8 2002/12/04 23:03:33 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef UPAP_H +#define UPAP_H + +#include "ppp.h" + +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN 4 + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + + +/* + * Client states. + */ +#define UPAPCS_INITIAL 0 /* Connection down */ +#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ +#define UPAPCS_OPEN 4 /* We've received an Ack */ +#define UPAPCS_BADAUTH 5 /* We've received a Nak */ + +/* + * Server states. + */ +#define UPAPSS_INITIAL 0 /* Connection down */ +#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ +#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ +#define UPAPSS_OPEN 4 /* We've sent an Ack */ +#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ + + +/* + * Timeouts. + */ +#if 0 /* moved to ppp_opts.h */ +#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif /* moved to ppp_opts.h */ + +/* + * Each interface is described by upap structure. + */ +#if PAP_SUPPORT +typedef struct upap_state { + const char *us_user; /* User */ + u8_t us_userlen; /* User length */ + const char *us_passwd; /* Password */ + u8_t us_passwdlen; /* Password length */ + u8_t us_clientstate; /* Client state */ +#if PPP_SERVER + u8_t us_serverstate; /* Server state */ +#endif /* PPP_SERVER */ + u8_t us_id; /* Current id */ + u8_t us_transmits; /* Number of auth-reqs sent */ +} upap_state; +#endif /* PAP_SUPPORT */ + + +void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password); +#if PPP_SERVER +void upap_authpeer(ppp_pcb *pcb); +#endif /* PPP_SERVER */ + +extern const struct protent pap_protent; + +#endif /* UPAP_H */ +#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/vj.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/vj.h new file mode 100644 index 0000000000..7f389c846f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/ppp/vj.h @@ -0,0 +1,161 @@ +/* + * Definitions for tcp compression routines. + * + * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#ifndef VJ_H +#define VJ_H + +#include "lwip/ip.h" +#include "lwip/priv/tcp_priv.h" + +#define MAX_SLOTS 16 /* must be > 2 and < 256 */ +#define MAX_HDR 128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP 0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP 0x80 +#define TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + struct cstate *cs_next; /* next most recently used state (xmit only) */ + u16_t cs_hlen; /* size of hdr (receive only) */ + u8_t cs_id; /* connection # associated with this state */ + u8_t cs_filler; + union { + char csu_hdr[MAX_HDR]; + struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ + } vjcs_u; +}; +#define cs_ip vjcs_u.csu_ip +#define cs_hdr vjcs_u.csu_hdr + + +struct vjstat { + u32_t vjs_packets; /* outbound packets */ + u32_t vjs_compressed; /* outbound compressed packets */ + u32_t vjs_searches; /* searches for connection state */ + u32_t vjs_misses; /* times couldn't find conn. state */ + u32_t vjs_uncompressedin; /* inbound uncompressed packets */ + u32_t vjs_compressedin; /* inbound compressed packets */ + u32_t vjs_errorin; /* inbound unknown type packets */ + u32_t vjs_tossed; /* inbound packets tossed because of error */ +}; + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct vjcompress { + struct cstate *last_cs; /* most recently used tstate */ + u8_t last_recv; /* last rcvd conn. id */ + u8_t last_xmit; /* last sent conn. id */ + u16_t flags; + u8_t maxSlotIndex; + u8_t compressSlot; /* Flag indicating OK to compress slot ID. */ +#if LINK_STATS + struct vjstat stats; +#endif + struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ + struct cstate rstate[MAX_SLOTS]; /* receive connection states */ +}; + +/* flag values */ +#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ + +extern void vj_compress_init (struct vjcompress *comp); +extern u8_t vj_compress_tcp (struct vjcompress *comp, struct pbuf **pb); +extern void vj_uncompress_err (struct vjcompress *comp); +extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); +extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp); + +#endif /* VJ_H */ + +#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/netif/slipif.h b/Sming/third-party/lwip2/lwip2-src/src/include/netif/slipif.h new file mode 100644 index 0000000000..65ba31f835 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/netif/slipif.h @@ -0,0 +1,87 @@ +/** + * @file + * + * SLIP netif API + */ + +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_HDR_NETIF_SLIPIF_H +#define LWIP_HDR_NETIF_SLIPIF_H + +#include "lwip/opt.h" +#include "lwip/netif.h" + +/** Set this to 1 to start a thread that blocks reading on the serial line + * (using sio_read()). + */ +#ifndef SLIP_USE_RX_THREAD +#define SLIP_USE_RX_THREAD !NO_SYS +#endif + +/** Set this to 1 to enable functions to pass in RX bytes from ISR context. + * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled + * packets on a queue, which is fed into lwIP from slipif_poll(). + * If disabled, slipif_poll() polls the serial line (using sio_tryread()). + */ +#ifndef SLIP_RX_FROM_ISR +#define SLIP_RX_FROM_ISR 0 +#endif + +/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets + * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. + * If disabled, packets will be dropped if more than one packet is received. + */ +#ifndef SLIP_RX_QUEUE +#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +err_t slipif_init(struct netif * netif); +void slipif_poll(struct netif *netif); +#if SLIP_RX_FROM_ISR +void slipif_process_rxqueue(struct netif *netif); +void slipif_received_byte(struct netif *netif, u8_t data); +void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); +#endif /* SLIP_RX_FROM_ISR */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_NETIF_SLIPIF_H */ + diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/posix/errno.h b/Sming/third-party/lwip2/lwip2-src/src/include/posix/errno.h new file mode 100644 index 0000000000..5917c75e24 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/posix/errno.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/errno.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/errno.h" diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/posix/netdb.h b/Sming/third-party/lwip2/lwip2-src/src/include/posix/netdb.h new file mode 100644 index 0000000000..12d4c7f566 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/posix/netdb.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/netdb.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/netdb.h" diff --git a/Sming/third-party/lwip2/lwip2-src/src/include/posix/sys/socket.h b/Sming/third-party/lwip2/lwip2-src/src/include/posix/sys/socket.h new file mode 100644 index 0000000000..0ed9baf3d9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/include/posix/sys/socket.h @@ -0,0 +1,33 @@ +/** + * @file + * This file is a posix wrapper for lwip/sockets.h. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/sockets.h" diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/FILES b/Sming/third-party/lwip2/lwip2-src/src/netif/FILES new file mode 100644 index 0000000000..a3ff431d42 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/FILES @@ -0,0 +1,24 @@ +This directory contains generic network interface device drivers that +do not contain any hardware or architecture specific code. The files +are: + +ethernet.c + Shared code for Ethernet based interfaces. + +ethernetif.c + An example of how an Ethernet device driver could look. This + file can be used as a "skeleton" for developing new Ethernet + network device drivers. It uses the etharp.c ARP code. + +lowpan6.c + A 6LoWPAN implementation as a netif. + +slipif.c + A generic implementation of the SLIP (Serial Line IP) + protocol. It requires a sio (serial I/O) module to work. + +ppp/ Point-to-Point Protocol stack + The lwIP PPP support is based from pppd (http://ppp.samba.org) with + huge changes to match code size and memory requirements for embedded + devices. Please read /doc/ppp.txt and ppp/PPPD_FOLLOWUP for a detailed + explanation. diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ethernet.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ethernet.c new file mode 100644 index 0000000000..52ea4236d5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ethernet.c @@ -0,0 +1,314 @@ +/** + * @file + * Ethernet common functions + * + * @defgroup ethernet Ethernet + * @ingroup callbackstyle_api + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/opt.h" + +#if LWIP_ARP || LWIP_ETHERNET + +#include "netif/ethernet.h" +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/etharp.h" +#include "lwip/ip.h" +#include "lwip/snmp.h" + +#include + +#include "netif/ppp/ppp_opts.h" +#if PPPOE_SUPPORT +#include "netif/ppp/pppoe.h" +#endif /* PPPOE_SUPPORT */ + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +const struct eth_addr ethzero = {{0,0,0,0,0,0}}; + +/** + * @ingroup lwip_nosys + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access.\n + * Don't call directly, pass to netif_add() and call netif->input(). + * + * @param p the received packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + * + * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL + * @see ETHARP_SUPPORT_VLAN + * @see LWIP_HOOK_VLAN_CHECK + */ +err_t +ethernet_input(struct pbuf *p, struct netif *netif) +{ + struct eth_hdr* ethhdr; + u16_t type; +#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 + s16_t ip_hdr_offset = SIZEOF_ETH_HDR; +#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ + + if (p->len <= SIZEOF_ETH_HDR) { + /* a packet with only an ethernet header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinerrors); + goto free_and_return; + } + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = (struct eth_hdr *)p->payload; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", + (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], + (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], + (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], + (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], + lwip_htons(ethhdr->type))); + + type = ethhdr->type; +#if ETHARP_SUPPORT_VLAN + if (type == PP_HTONS(ETHTYPE_VLAN)) { + struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); + if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { + /* a packet with only an ethernet/vlan header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinerrors); + goto free_and_return; + } +#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ +#ifdef LWIP_HOOK_VLAN_CHECK + if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { +#elif defined(ETHARP_VLAN_CHECK_FN) + if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { +#elif defined(ETHARP_VLAN_CHECK) + if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { +#endif + /* silently ignore this packet: not for our VLAN */ + pbuf_free(p); + return ERR_OK; + } +#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ + type = vlan->tpid; + ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; + } +#endif /* ETHARP_SUPPORT_VLAN */ + +#if LWIP_ARP_FILTER_NETIF + netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); +#endif /* LWIP_ARP_FILTER_NETIF*/ + + if (ethhdr->dest.addr[0] & 1) { + /* this might be a multicast or broadcast packet */ + if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { +#if LWIP_IPV4 + if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && + (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } +#endif /* LWIP_IPV4 */ + } +#if LWIP_IPV6 + else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && + (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } +#endif /* LWIP_IPV6 */ + else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { + /* mark the pbuf as link-layer broadcast */ + p->flags |= PBUF_FLAG_LLBCAST; + } + } + + switch (type) { +#if LWIP_IPV4 && LWIP_ARP + /* IP packet? */ + case PP_HTONS(ETHTYPE_IP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } + /* skip Ethernet header */ + if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n", + p->tot_len, ip_hdr_offset)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + goto free_and_return; + } else { + /* pass to IP layer */ + ip4_input(p, netif); + } + break; + + case PP_HTONS(ETHTYPE_ARP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } + /* skip Ethernet header */ + if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: ARP response packet dropped, too short (%"S16_F"/%"S16_F")\n", + p->tot_len, ip_hdr_offset)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); + ETHARP_STATS_INC(etharp.lenerr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } else { + /* pass p to ARP module */ + etharp_input(p, netif); + } + break; +#endif /* LWIP_IPV4 && LWIP_ARP */ +#if PPPOE_SUPPORT + case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ + pppoe_disc_input(netif, p); + break; + + case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ + pppoe_data_input(netif, p); + break; +#endif /* PPPOE_SUPPORT */ + +#if LWIP_IPV6 + case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ + /* skip Ethernet header */ + if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + ("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n", + p->tot_len, ip_hdr_offset)); + goto free_and_return; + } else { + /* pass to IPv6 layer */ + ip6_input(p, netif); + } + break; +#endif /* LWIP_IPV6 */ + + default: +#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL + if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { + break; + } +#endif + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); + goto free_and_return; + } + + /* This means the pbuf is freed or consumed, + so the caller doesn't have to free it again */ + return ERR_OK; + +free_and_return: + pbuf_free(p); + return ERR_OK; +} + +/** + * @ingroup ethernet + * Send an ethernet packet on the network using netif->linkoutput(). + * The ethernet header is filled in before sending. + * + * @see LWIP_HOOK_VLAN_SET + * + * @param netif the lwIP network interface on which to send the packet + * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. + * @param src the source MAC address to be copied into the ethernet header + * @param dst the destination MAC address to be copied into the ethernet header + * @param eth_type ethernet type (@ref eth_type) + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +err_t +ethernet_output(struct netif* netif, struct pbuf* p, + const struct eth_addr* src, const struct eth_addr* dst, + u16_t eth_type) +{ + struct eth_hdr* ethhdr; + u16_t eth_type_be = lwip_htons(eth_type); + +#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) + s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); + if (vlan_prio_vid >= 0) { + struct eth_vlan_hdr* vlanhdr; + + LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); + + if (pbuf_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { + goto pbuf_header_failed; + } + vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR); + vlanhdr->tpid = eth_type_be; + vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); + + eth_type_be = PP_HTONS(ETHTYPE_VLAN); + } else +#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ + { + if (pbuf_header(p, SIZEOF_ETH_HDR) != 0) { + goto pbuf_header_failed; + } + } + + ethhdr = (struct eth_hdr*)p->payload; + ethhdr->type = eth_type_be; + ETHADDR32_COPY(ðhdr->dest, dst); + ETHADDR16_COPY(ðhdr->src, src); + + LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", + (netif->hwaddr_len == ETH_HWADDR_LEN)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, + ("ethernet_output: sending packet %p\n", (void *)p)); + + /* send the packet */ + return netif->linkoutput(netif, p); + +pbuf_header_failed: + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("ethernet_output: could not allocate room for header.\n")); + LINK_STATS_INC(link.lenerr); + return ERR_BUF; +} + +#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ethernetif.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ethernetif.c new file mode 100644 index 0000000000..dc8ae6c42a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ethernetif.c @@ -0,0 +1,335 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" + +#if 0 /* don't build, this is only a skeleton, see previous comment */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "lwip/etharp.h" +#include "netif/ppp/pppoe.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +/* Forward declarations. */ +static void ethernetif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = ; + ... + netif->hwaddr[5] = ; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + /* Do whatever else is needed to initialize interface. */ +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + + initiate transfer(); + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + for (q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + send data from(q->payload, q->len); + } + + signal that packet should be sent(); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t*)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } else { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + /* increase ifoutdiscards or ifouterrors on error */ + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p, *q; + u16_t len; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + len = ; + +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) { + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for (q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + * available data in the pbuf is given by the q->len + * variable. + * This does not necessarily have to be a memcpy, you can also preallocate + * pbufs for a DMA-enabled MAC and after receiving truncate it to the + * actually received size. In this case, ensure the tot_len member of the + * pbuf is the sum of the chained pbuf len members. + */ + read data into(q->payload, q->len); + } + acknowledge that packet has been read(); + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + if (((u8_t*)p->payload)[0] & 1) { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } else { + /* unicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } else { + drop packet(); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +static void +ethernetif_input(struct netif *netif) +{ + struct ethernetif *ethernetif; + struct eth_hdr *ethhdr; + struct pbuf *p; + + ethernetif = netif->state; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + /* if no packet could be read, silently ignore this */ + if (p != NULL) { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; + } + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ + netif->output = etharp_output; +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + +#endif /* 0 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/lowpan6.c b/Sming/third-party/lwip2/lwip2-src/src/netif/lowpan6.c new file mode 100644 index 0000000000..9a84cbccc7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/lowpan6.c @@ -0,0 +1,1193 @@ +/** + * @file + * + * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. + */ + +/* + * Copyright (c) 2015 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/** + * @defgroup sixlowpan 6LowPAN netif + * @ingroup addons + * 6LowPAN netif implementation + */ + +#include "netif/lowpan6.h" + +#if LWIP_IPV6 && LWIP_6LOWPAN + +#include "lwip/ip.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/nd6.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" +#include "lwip/snmp.h" + +#include + +struct ieee_802154_addr { + u8_t addr_len; + u8_t addr[8]; +}; + +/** This is a helper struct. + */ +struct lowpan6_reass_helper { + struct pbuf *pbuf; + struct lowpan6_reass_helper *next_packet; + u8_t timer; + struct ieee_802154_addr sender_addr; + u16_t datagram_size; + u16_t datagram_tag; +}; + +static struct lowpan6_reass_helper * reass_list; + +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 +static ip6_addr_t lowpan6_context[LWIP_6LOWPAN_NUM_CONTEXTS]; +#endif + +static u16_t ieee_802154_pan_id; + +static const struct ieee_802154_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS +static struct ieee_802154_addr short_mac_addr = {2, {0,0}}; +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +static err_t dequeue_datagram(struct lowpan6_reass_helper *lrh); + +/** + * Periodic timer for 6LowPAN functions: + * + * - Remove incomplete/old packets + */ +void +lowpan6_tmr(void) +{ + struct lowpan6_reass_helper *lrh, *lrh_temp; + + lrh = reass_list; + while (lrh != NULL) { + lrh_temp = lrh->next_packet; + if ((--lrh->timer) == 0) { + dequeue_datagram(lrh); + pbuf_free(lrh->pbuf); + mem_free(lrh); + } + lrh = lrh_temp; + } +} + +/** + * Removes a datagram from the reassembly queue. + **/ +static err_t +dequeue_datagram(struct lowpan6_reass_helper *lrh) +{ + struct lowpan6_reass_helper *lrh_temp; + + if (reass_list == lrh) { + reass_list = reass_list->next_packet; + } else { + lrh_temp = reass_list; + while (lrh_temp != NULL) { + if (lrh_temp->next_packet == lrh) { + lrh_temp->next_packet = lrh->next_packet; + break; + } + lrh_temp = lrh_temp->next_packet; + } + } + + return ERR_OK; +} + +static s8_t +lowpan6_context_lookup(const ip6_addr_t *ip6addr) +{ + s8_t i; + + for (i = 0; i < LWIP_6LOWPAN_NUM_CONTEXTS; i++) { + if (ip6_addr_netcmp(&lowpan6_context[i], ip6addr)) { + return i; + } + } + + return -1; +} + +/* Determine compression mode for unicast address. */ +static s8_t +lowpan6_get_address_mode(const ip6_addr_t *ip6addr, const struct ieee_802154_addr *mac_addr) +{ + if (mac_addr->addr_len == 2) { + if ((ip6addr->addr[2] == (u32_t)PP_HTONL(0x000000ff)) && + ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000))) { + if ((ip6addr->addr[3] & PP_HTONL(0x0000ffff)) == lwip_ntohl((mac_addr->addr[0] << 8) | mac_addr->addr[1])) { + return 3; + } + } + } else if (mac_addr->addr_len == 8) { + if ((ip6addr->addr[2] == lwip_ntohl(((mac_addr->addr[0] ^ 2) << 24) | (mac_addr->addr[1] << 16) | mac_addr->addr[2] << 8 | mac_addr->addr[3])) && + (ip6addr->addr[3] == lwip_ntohl((mac_addr->addr[4] << 24) | (mac_addr->addr[5] << 16) | mac_addr->addr[6] << 8 | mac_addr->addr[7]))) { + return 3; + } + } + + if ((ip6addr->addr[2] == PP_HTONL(0x000000ffUL)) && + ((ip6addr->addr[3] & PP_HTONL(0xffff0000)) == PP_NTOHL(0xfe000000UL))) { + return 2; + } + + return 1; +} + +/* Determine compression mode for multicast address. */ +static s8_t +lowpan6_get_address_mode_mc(const ip6_addr_t *ip6addr) +{ + if ((ip6addr->addr[0] == PP_HTONL(0xff020000)) && + (ip6addr->addr[1] == 0) && + (ip6addr->addr[2] == 0) && + ((ip6addr->addr[3] & PP_HTONL(0xffffff00)) == 0)) { + return 3; + } else if (((ip6addr->addr[0] & PP_HTONL(0xff00ffff)) == PP_HTONL(0xff000000)) && + (ip6addr->addr[1] == 0)) { + if ((ip6addr->addr[2] == 0) && + ((ip6addr->addr[3] & PP_HTONL(0xff000000)) == 0)) { + return 2; + } else if ((ip6addr->addr[2] & PP_HTONL(0xffffff00)) == 0) { + return 1; + } + } + + return 0; +} + +/* + * Encapsulates data into IEEE 802.15.4 frames. + * Fragments an IPv6 datagram into 6LowPAN units, which fit into IEEE 802.15.4 frames. + * If configured, will compress IPv6 and or UDP headers. + * */ +static err_t +lowpan6_frag(struct netif *netif, struct pbuf *p, const struct ieee_802154_addr *src, const struct ieee_802154_addr *dst) +{ + struct pbuf * p_frag; + u16_t frag_len, remaining_len; + u8_t * buffer; + u8_t ieee_header_len; + u8_t lowpan6_header_len; + s8_t i; + static u8_t frame_seq_num; + static u16_t datagram_tag; + u16_t datagram_offset; + err_t err = ERR_IF; + + /* We'll use a dedicated pbuf for building 6LowPAN fragments. */ + p_frag = pbuf_alloc(PBUF_RAW, 127, PBUF_RAM); + if (p_frag == NULL) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return ERR_MEM; + } + + /* Write IEEE 802.15.4 header. */ + buffer = (u8_t*)p_frag->payload; + ieee_header_len = 0; + if (dst == &ieee_802154_broadcast) { + buffer[ieee_header_len++] = 0x01; /* data packet, no ack required. */ + } else { + buffer[ieee_header_len++] = 0x21; /* data packet, ack required. */ + } + buffer[ieee_header_len] = (0x00 << 4); /* 2003 frame version */ + buffer[ieee_header_len] |= (dst->addr_len == 2) ? (0x02 << 2) : (0x03 << 2); /* destination addressing mode */ + buffer[ieee_header_len] |= (src->addr_len == 2) ? (0x02 << 6) : (0x03 << 6); /* source addressing mode */ + ieee_header_len++; + buffer[ieee_header_len++] = frame_seq_num++; + + buffer[ieee_header_len++] = ieee_802154_pan_id & 0xff; /* pan id */ + buffer[ieee_header_len++] = (ieee_802154_pan_id >> 8) & 0xff; /* pan id */ + i = dst->addr_len; + while (i-- > 0) { + buffer[ieee_header_len++] = dst->addr[i]; + } + + buffer[ieee_header_len++] = ieee_802154_pan_id & 0xff; /* pan id */ + buffer[ieee_header_len++] = (ieee_802154_pan_id >> 8) & 0xff; /* pan id */ + i = src->addr_len; + while (i-- > 0) { + buffer[ieee_header_len++] = src->addr[i]; + } + +#if LWIP_6LOWPAN_IPHC + /* Perform 6LowPAN IPv6 header compression according to RFC 6282 */ + { + struct ip6_hdr *ip6hdr; + + /* Point to ip6 header and align copies of src/dest addresses. */ + ip6hdr = (struct ip6_hdr *)p->payload; + ip_addr_copy_from_ip6(ip_data.current_iphdr_dest, ip6hdr->dest); + ip_addr_copy_from_ip6(ip_data.current_iphdr_src, ip6hdr->src); + + /* Basic length of 6LowPAN header, set dispatch and clear fields. */ + lowpan6_header_len = 2; + buffer[ieee_header_len] = 0x60; + buffer[ieee_header_len + 1] = 0; + + /* Determine whether there will be a Context Identifier Extension byte or not. + * If so, set it already. */ +#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 + buffer[ieee_header_len + 2] = 0; + + i = lowpan6_context_lookup(ip_2_ip6(&ip_data.current_iphdr_src)); + if (i >= 0) { + /* Stateful source address compression. */ + buffer[ieee_header_len + 1] |= 0x40; + buffer[ieee_header_len + 2] |= (i & 0x0f) << 4; + } + + i = lowpan6_context_lookup(ip_2_ip6(&ip_data.current_iphdr_dest)); + if (i >= 0) { + /* Stateful destination address compression. */ + buffer[ieee_header_len + 1] |= 0x04; + buffer[ieee_header_len + 2] |= i & 0x0f; + } + + if (buffer[ieee_header_len + 2] != 0x00) { + /* Context identifier extension byte is appended. */ + buffer[ieee_header_len + 1] |= 0x80; + lowpan6_header_len++; + } +#endif /* LWIP_6LOWPAN_NUM_CONTEXTS > 0 */ + + /* Determine TF field: Traffic Class, Flow Label */ + if (IP6H_FL(ip6hdr) == 0) { + /* Flow label is elided. */ + buffer[ieee_header_len] |= 0x10; + if (IP6H_TC(ip6hdr) == 0) { + /* Traffic class (ECN+DSCP) elided too. */ + buffer[ieee_header_len] |= 0x08; + } else { + /* Traffic class (ECN+DSCP) appended. */ + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_TC(ip6hdr); + } + } else { + if (((IP6H_TC(ip6hdr) & 0x3f) == 0)) { + /* DSCP portion of Traffic Class is elided, ECN and FL are appended (3 bytes) */ + buffer[ieee_header_len] |= 0x08; + + buffer[ieee_header_len + lowpan6_header_len] = IP6H_TC(ip6hdr) & 0xc0; + buffer[ieee_header_len + lowpan6_header_len++] |= (IP6H_FL(ip6hdr) >> 16) & 0x0f; + buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; + } else { + /* Traffic class and flow label are appended (4 bytes) */ + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_TC(ip6hdr); + buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 16) & 0x0f; + buffer[ieee_header_len + lowpan6_header_len++] = (IP6H_FL(ip6hdr) >> 8) & 0xff; + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_FL(ip6hdr) & 0xff; + } + } + + /* Compress NH? + * Only if UDP for now. @todo support other NH compression. */ + if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { + buffer[ieee_header_len] |= 0x04; + } else { + /* append nexth. */ + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_NEXTH(ip6hdr); + } + + /* Compress hop limit? */ + if (IP6H_HOPLIM(ip6hdr) == 255) { + buffer[ieee_header_len] |= 0x03; + } else if (IP6H_HOPLIM(ip6hdr) == 64) { + buffer[ieee_header_len] |= 0x02; + } else if (IP6H_HOPLIM(ip6hdr) == 1) { + buffer[ieee_header_len] |= 0x01; + } else { + /* append hop limit */ + buffer[ieee_header_len + lowpan6_header_len++] = IP6H_HOPLIM(ip6hdr); + } + + /* Compress source address */ + if (((buffer[ieee_header_len + 1] & 0x40) != 0) || + (ip6_addr_islinklocal(ip_2_ip6(&ip_data.current_iphdr_src)))) { + /* Context-based or link-local source address compression. */ + i = lowpan6_get_address_mode(ip_2_ip6(&ip_data.current_iphdr_src), src); + buffer[ieee_header_len + 1] |= (i & 0x03) << 4; + if (i == 1) { + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 16, 8); + lowpan6_header_len += 8; + } else if (i == 2) { + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 22, 2); + lowpan6_header_len += 2; + } + } else if (ip6_addr_isany(ip_2_ip6(&ip_data.current_iphdr_src))) { + /* Special case: mark SAC and leave SAM=0 */ + buffer[ieee_header_len + 1] |= 0x40; + } else { + /* Append full address. */ + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 8, 16); + lowpan6_header_len += 16; + } + + /* Compress destination address */ + if (ip6_addr_ismulticast(ip_2_ip6(&ip_data.current_iphdr_dest))) { + /* @todo support stateful multicast address compression */ + + buffer[ieee_header_len + 1] |= 0x08; + + i = lowpan6_get_address_mode_mc(ip_2_ip6(&ip_data.current_iphdr_dest)); + buffer[ieee_header_len + 1] |= i & 0x03; + if (i == 0) { + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 24, 16); + lowpan6_header_len += 16; + } else if (i == 1) { + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[25]; + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 35, 5); + lowpan6_header_len += 5; + } else if (i == 2) { + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[25]; + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 37, 3); + lowpan6_header_len += 3; + } else if (i == 3) { + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[39]; + } + } else if (((buffer[ieee_header_len + 1] & 0x04) != 0) || + (ip6_addr_islinklocal(ip_2_ip6(&ip_data.current_iphdr_dest)))) { + /* Context-based or link-local destination address compression. */ + i = lowpan6_get_address_mode(ip_2_ip6(&ip_data.current_iphdr_dest), dst); + buffer[ieee_header_len + 1] |= i & 0x03; + if (i == 1) { + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 32, 8); + lowpan6_header_len += 8; + } else if (i == 2) { + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 38, 2); + lowpan6_header_len += 2; + } + } else { + /* Append full address. */ + MEMCPY(buffer + ieee_header_len + lowpan6_header_len, (u8_t*)p->payload + 24, 16); + lowpan6_header_len += 16; + } + + /* Move to payload. */ + pbuf_header(p, -IP6_HLEN); + + /* Compress UDP header? */ + if (IP6H_NEXTH(ip6hdr) == IP6_NEXTH_UDP) { + /* @todo support optional checksum compression */ + + buffer[ieee_header_len + lowpan6_header_len] = 0xf0; + + /* determine port compression mode. */ + if ((((u8_t *)p->payload)[0] == 0xf0) && ((((u8_t *)p->payload)[1] & 0xf0) == 0xb0) && + (((u8_t *)p->payload)[2] == 0xf0) && ((((u8_t *)p->payload)[3] & 0xf0) == 0xb0)) { + /* Compress source and dest ports. */ + buffer[ieee_header_len + lowpan6_header_len++] |= 0x03; + buffer[ieee_header_len + lowpan6_header_len++] = ((((u8_t *)p->payload)[1] & 0x0f) << 4) | (((u8_t *)p->payload)[3] & 0x0f); + } else if (((u8_t *)p->payload)[0] == 0xf0) { + /* Compress source port. */ + buffer[ieee_header_len + lowpan6_header_len++] |= 0x02; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[2]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; + } else if (((u8_t *)p->payload)[2] == 0xf0) { + /* Compress dest port. */ + buffer[ieee_header_len + lowpan6_header_len++] |= 0x01; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[0]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; + } else { + /* append full ports. */ + lowpan6_header_len++; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[0]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[1]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[2]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[3]; + } + + /* elide length and copy checksum */ + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[6]; + buffer[ieee_header_len + lowpan6_header_len++] = ((u8_t *)p->payload)[7]; + + pbuf_header(p, -UDP_HLEN); + } + } + +#else /* LWIP_6LOWPAN_HC */ + /* Send uncompressed IPv6 header with appropriate dispatch byte. */ + lowpan6_header_len = 1; + buffer[ieee_header_len] = 0x41; /* IPv6 dispatch */ +#endif /* LWIP_6LOWPAN_HC */ + + /* Calculate remaining packet length */ + remaining_len = p->tot_len; + + if (remaining_len > 0x7FF) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + /* datagram_size must fit into 11 bit */ + pbuf_free(p_frag); + return ERR_VAL; + } + + /* Fragment, or 1 packet? */ + if (remaining_len > (127 - ieee_header_len - lowpan6_header_len - 3)) { /* 127 - header - 1 byte dispatch - 2 bytes CRC */ + /* We must move the 6LowPAN header to make room for the FRAG header. */ + i = lowpan6_header_len; + while (i-- != 0) { + buffer[ieee_header_len + i + 4] = buffer[ieee_header_len + i]; + } + + /* Now we need to fragment the packet. FRAG1 header first */ + buffer[ieee_header_len] = 0xc0 | (((p->tot_len + lowpan6_header_len) >> 8) & 0x7); + buffer[ieee_header_len + 1] = (p->tot_len + lowpan6_header_len) & 0xff; + + datagram_tag++; + buffer[ieee_header_len + 2] = datagram_tag & 0xff; + buffer[ieee_header_len + 3] = (datagram_tag >> 8) & 0xff; + + /* Fragment follows. */ + frag_len = (127 - ieee_header_len - 4 - 2) & 0xf8; + + pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len + 4, frag_len - lowpan6_header_len, 0); + remaining_len -= frag_len - lowpan6_header_len; + datagram_offset = frag_len; + + /* 2 bytes CRC */ +#if LWIP_6LOWPAN_HW_CRC + /* Leave blank, will be filled by HW. */ +#else /* LWIP_6LOWPAN_HW_CRC */ + /* @todo calculate CRC */ +#endif /* LWIP_6LOWPAN_HW_CRC */ + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = ieee_header_len + 4 + frag_len + 2; /* add 2 dummy bytes for crc*/ + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + + while ((remaining_len > 0) && (err == ERR_OK)) { + /* new frame, new seq num for ACK */ + buffer[2] = frame_seq_num++; + + buffer[ieee_header_len] |= 0x20; /* Change FRAG1 to FRAGN */ + + buffer[ieee_header_len + 4] = (u8_t)(datagram_offset >> 3); /* datagram offset in FRAGN header (datagram_offset is max. 11 bit) */ + + frag_len = (127 - ieee_header_len - 5 - 2) & 0xf8; + if (frag_len > remaining_len) { + frag_len = remaining_len; + } + + pbuf_copy_partial(p, buffer + ieee_header_len + 5, frag_len, p->tot_len - remaining_len); + remaining_len -= frag_len; + datagram_offset += frag_len; + + /* 2 bytes CRC */ +#if LWIP_6LOWPAN_HW_CRC + /* Leave blank, will be filled by HW. */ +#else /* LWIP_6LOWPAN_HW_CRC */ + /* @todo calculate CRC */ +#endif /* LWIP_6LOWPAN_HW_CRC */ + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = frag_len + 5 + ieee_header_len + 2; + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + } + } else { + /* It fits in one frame. */ + frag_len = remaining_len; + + /* Copy IPv6 packet */ + pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len, frag_len, 0); + remaining_len = 0; + + /* 2 bytes CRC */ +#if LWIP_6LOWPAN_HW_CRC + /* Leave blank, will be filled by HW. */ +#else /* LWIP_6LOWPAN_HW_CRC */ + /* @todo calculate CRC */ +#endif /* LWIP_6LOWPAN_HW_CRC */ + + /* Calculate frame length */ + p_frag->len = p_frag->tot_len = frag_len + lowpan6_header_len + ieee_header_len + 2; + + /* send the packet */ + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); + LWIP_DEBUGF(LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); + err = netif->linkoutput(netif, p_frag); + } + + pbuf_free(p_frag); + + return err; +} + +err_t +lowpan6_set_context(u8_t idx, const ip6_addr_t * context) +{ + if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) { + return ERR_ARG; + } + + ip6_addr_set(&lowpan6_context[idx], context); + + return ERR_OK; +} + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS +err_t +lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low) +{ + short_mac_addr.addr[0] = addr_high; + short_mac_addr.addr[1] = addr_low; + + return ERR_OK; +} +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +#if LWIP_IPV4 +err_t +lowpan4_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) +{ + (void)netif; + (void)q; + (void)ipaddr; + + return ERR_IF; +} +#endif /* LWIP_IPV4 */ + +/** + * Resolve and fill-in IEEE 802.15.4 address header for outgoing IPv6 packet. + * + * Perform Header Compression and fragment if necessary. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return err_t + */ +err_t +lowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) +{ + err_t result; + const u8_t *hwaddr; + struct ieee_802154_addr src, dest; +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + ip6_addr_t ip6_src; + struct ip6_hdr * ip6_hdr; +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + /* Check if we can compress source address (use aligned copy) */ + ip6_hdr = (struct ip6_hdr *)q->payload; + ip6_addr_set(&ip6_src, &ip6_hdr->src); + if (lowpan6_get_address_mode(&ip6_src, &short_mac_addr) == 3) { + src.addr_len = 2; + src.addr[0] = short_mac_addr.addr[0]; + src.addr[1] = short_mac_addr.addr[1]; + } else +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + { + src.addr_len = netif->hwaddr_len; + SMEMCPY(src.addr, netif->hwaddr, netif->hwaddr_len); + } + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + /* We need to send to the broadcast address.*/ + return lowpan6_frag(netif, q, &src, &ieee_802154_broadcast); + } + + /* We have a unicast destination IP address */ + /* @todo anycast? */ + +#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS + if (src.addr_len == 2) { + /* If source address was compressable to short_mac_addr, and dest has same subnet and + * is also compressable to 2-bytes, assume we can infer dest as a short address too. */ + dest.addr_len = 2; + dest.addr[0] = ((u8_t *)q->payload)[38]; + dest.addr[1] = ((u8_t *)q->payload)[39]; + if ((src.addr_len == 2) && (ip6_addr_netcmp(&ip6_hdr->src, &ip6_hdr->dest)) && + (lowpan6_get_address_mode(ip6addr, &dest) == 3)) { + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + return lowpan6_frag(netif, q, &src, &dest); + } + } +#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ + + /* Ask ND6 what to do with the packet. */ + result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); + if (result != ERR_OK) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + return result; + } + + /* If no hardware address is returned, nd6 has queued the packet for later. */ + if (hwaddr == NULL) { + return ERR_OK; + } + + /* Send out the packet using the returned hardware address. */ + dest.addr_len = netif->hwaddr_len; + SMEMCPY(dest.addr, hwaddr, netif->hwaddr_len); + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + return lowpan6_frag(netif, q, &src, &dest); +} + +static struct pbuf * +lowpan6_decompress(struct pbuf * p, struct ieee_802154_addr * src, struct ieee_802154_addr * dest) +{ + struct pbuf * q; + u8_t * lowpan6_buffer; + s8_t lowpan6_offset; + struct ip6_hdr *ip6hdr; + s8_t i; + s8_t ip6_offset = IP6_HLEN; + + + q = pbuf_alloc(PBUF_IP, p->len + IP6_HLEN + UDP_HLEN, PBUF_POOL); + if (q == NULL) { + pbuf_free(p); + return NULL; + } + + lowpan6_buffer = (u8_t *)p->payload; + ip6hdr = (struct ip6_hdr *)q->payload; + + lowpan6_offset = 2; + if (lowpan6_buffer[1] & 0x80) { + lowpan6_offset++; + } + + /* Set IPv6 version, traffic class and flow label. */ + if ((lowpan6_buffer[0] & 0x18) == 0x00) { + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset], ((lowpan6_buffer[lowpan6_offset+1] & 0x0f) << 16) | (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset+3]); + lowpan6_offset += 4; + } else if ((lowpan6_buffer[0] & 0x18) == 0x08) { + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset] & 0xc0, ((lowpan6_buffer[lowpan6_offset] & 0x0f) << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset+2]); + lowpan6_offset += 3; + } else if ((lowpan6_buffer[0] & 0x18) == 0x10) { + IP6H_VTCFL_SET(ip6hdr, 6, lowpan6_buffer[lowpan6_offset],0); + lowpan6_offset += 1; + } else if ((lowpan6_buffer[0] & 0x18) == 0x18) { + IP6H_VTCFL_SET(ip6hdr, 6, 0, 0); + } + + /* Set Next Header */ + if ((lowpan6_buffer[0] & 0x04) == 0x00) { + IP6H_NEXTH_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); + } else { + /* We should fill this later with NHC decoding */ + IP6H_NEXTH_SET(ip6hdr, 0); + } + + /* Set Hop Limit */ + if ((lowpan6_buffer[0] & 0x03) == 0x00) { + IP6H_HOPLIM_SET(ip6hdr, lowpan6_buffer[lowpan6_offset++]); + } else if ((lowpan6_buffer[0] & 0x03) == 0x01) { + IP6H_HOPLIM_SET(ip6hdr, 1); + } else if ((lowpan6_buffer[0] & 0x03) == 0x02) { + IP6H_HOPLIM_SET(ip6hdr, 64); + } else if ((lowpan6_buffer[0] & 0x03) == 0x03) { + IP6H_HOPLIM_SET(ip6hdr, 255); + } + + /* Source address decoding. */ + if ((lowpan6_buffer[1] & 0x40) == 0x00) { + /* Stateless compression */ + if ((lowpan6_buffer[1] & 0x30) == 0x00) { + /* copy full address */ + MEMCPY(&ip6hdr->src.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x30) == 0x10) { + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | + lowpan6_buffer[lowpan6_offset+1]); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { + ip6hdr->src.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->src.addr[1] = 0; + if (src->addr_len == 2) { + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); + } else { + ip6hdr->src.addr[2] = lwip_htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | + (src->addr[2] << 8) | src->addr[3]); + ip6hdr->src.addr[3] = lwip_htonl((src->addr[4] << 24) | (src->addr[5] << 16) | + (src->addr[6] << 8) | src->addr[7]); + } + } + } else { + /* Stateful compression */ + if ((lowpan6_buffer[1] & 0x30) == 0x00) { + /* ANY address */ + ip6hdr->src.addr[0] = 0; + ip6hdr->src.addr[1] = 0; + ip6hdr->src.addr[2] = 0; + ip6hdr->src.addr[3] = 0; + } else { + /* Set prefix from context info */ + if (lowpan6_buffer[1] & 0x80) { + i = (lowpan6_buffer[2] >> 4) & 0x0f; + } else { + i = 0; + } + if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { + /* Error */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + ip6hdr->src.addr[0] = lowpan6_context[i].addr[0]; + ip6hdr->src.addr[1] = lowpan6_context[i].addr[1]; + } + + if ((lowpan6_buffer[1] & 0x30) == 0x10) { + MEMCPY(&ip6hdr->src.addr[2], lowpan6_buffer + lowpan6_offset, 8); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x30) == 0x20) { + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset+1]); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x30) == 0x30) { + if (src->addr_len == 2) { + ip6hdr->src.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->src.addr[3] = lwip_htonl(0xfe000000UL | (src->addr[0] << 8) | src->addr[1]); + } else { + ip6hdr->src.addr[2] = lwip_htonl(((src->addr[0] ^ 2) << 24) | (src->addr[1] << 16) | (src->addr[2] << 8) | src->addr[3]); + ip6hdr->src.addr[3] = lwip_htonl((src->addr[4] << 24) | (src->addr[5] << 16) | (src->addr[6] << 8) | src->addr[7]); + } + } + } + + /* Destination address decoding. */ + if (lowpan6_buffer[1] & 0x08) { + /* Multicast destination */ + if (lowpan6_buffer[1] & 0x04) { + /* @todo support stateful multicast addressing */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + if ((lowpan6_buffer[1] & 0x03) == 0x00) { + /* copy full address */ + MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { + ip6hdr->dest.addr[0] = lwip_htonl(0xff000000UL | (lowpan6_buffer[lowpan6_offset++] << 16)); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = lwip_htonl(lowpan6_buffer[lowpan6_offset++]); + ip6hdr->dest.addr[3] = lwip_htonl((lowpan6_buffer[lowpan6_offset] << 24) | (lowpan6_buffer[lowpan6_offset + 1] << 16) | (lowpan6_buffer[lowpan6_offset + 2] << 8) | lowpan6_buffer[lowpan6_offset + 3]); + lowpan6_offset += 4; + } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { + ip6hdr->dest.addr[0] = lwip_htonl(0xff000000UL | lowpan6_buffer[lowpan6_offset++]); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = 0; + ip6hdr->dest.addr[3] = lwip_htonl((lowpan6_buffer[lowpan6_offset] << 16) | (lowpan6_buffer[lowpan6_offset + 1] << 8) | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { + ip6hdr->dest.addr[0] = PP_HTONL(0xff020000UL); + ip6hdr->dest.addr[1] = 0; + ip6hdr->dest.addr[2] = 0; + ip6hdr->dest.addr[3] = lwip_htonl(lowpan6_buffer[lowpan6_offset++]); + } + + } else { + if (lowpan6_buffer[1] & 0x04) { + /* Stateful destination compression */ + /* Set prefix from context info */ + if (lowpan6_buffer[1] & 0x80) { + i = lowpan6_buffer[2] & 0x0f; + } else { + i = 0; + } + if (i >= LWIP_6LOWPAN_NUM_CONTEXTS) { + /* Error */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + ip6hdr->dest.addr[0] = lowpan6_context[i].addr[0]; + ip6hdr->dest.addr[1] = lowpan6_context[i].addr[1]; + } else { + /* Link local address compression */ + ip6hdr->dest.addr[0] = PP_HTONL(0xfe800000UL); + ip6hdr->dest.addr[1] = 0; + } + + if ((lowpan6_buffer[1] & 0x03) == 0x00) { + /* copy full address */ + MEMCPY(&ip6hdr->dest.addr[0], lowpan6_buffer + lowpan6_offset, 16); + lowpan6_offset += 16; + } else if ((lowpan6_buffer[1] & 0x03) == 0x01) { + MEMCPY(&ip6hdr->dest.addr[2], lowpan6_buffer + lowpan6_offset, 8); + lowpan6_offset += 8; + } else if ((lowpan6_buffer[1] & 0x03) == 0x02) { + ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->dest.addr[3] = lwip_htonl(0xfe000000UL | (lowpan6_buffer[lowpan6_offset] << 8) | lowpan6_buffer[lowpan6_offset + 1]); + lowpan6_offset += 2; + } else if ((lowpan6_buffer[1] & 0x03) == 0x03) { + if (dest->addr_len == 2) { + ip6hdr->dest.addr[2] = PP_HTONL(0x000000ffUL); + ip6hdr->dest.addr[3] = lwip_htonl(0xfe000000UL | (dest->addr[0] << 8) | dest->addr[1]); + } else { + ip6hdr->dest.addr[2] = lwip_htonl(((dest->addr[0] ^ 2) << 24) | (dest->addr[1] << 16) | dest->addr[2] << 8 | dest->addr[3]); + ip6hdr->dest.addr[3] = lwip_htonl((dest->addr[4] << 24) | (dest->addr[5] << 16) | dest->addr[6] << 8 | dest->addr[7]); + } + } + } + + + /* Next Header Compression (NHC) decoding? */ + if (lowpan6_buffer[0] & 0x04) { + if ((lowpan6_buffer[lowpan6_offset] & 0xf8) == 0xf0) { + struct udp_hdr *udphdr; + + /* UDP compression */ + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_UDP); + udphdr = (struct udp_hdr *)((u8_t *)q->payload + ip6_offset); + + if (lowpan6_buffer[lowpan6_offset] & 0x04) { + /* @todo support checksum decompress */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + + /* Decompress ports */ + i = lowpan6_buffer[lowpan6_offset++] & 0x03; + if (i == 0) { + udphdr->src = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + udphdr->dest = lwip_htons(lowpan6_buffer[lowpan6_offset + 2] << 8 | lowpan6_buffer[lowpan6_offset + 3]); + lowpan6_offset += 4; + } else if (i == 0x01) { + udphdr->src = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + udphdr->dest = lwip_htons(0xf000 | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if (i == 0x02) { + udphdr->src = lwip_htons(0xf000 | lowpan6_buffer[lowpan6_offset]); + udphdr->dest = lwip_htons(lowpan6_buffer[lowpan6_offset + 1] << 8 | lowpan6_buffer[lowpan6_offset + 2]); + lowpan6_offset += 3; + } else if (i == 0x03) { + udphdr->src = lwip_htons(0xf0b0 | ((lowpan6_buffer[lowpan6_offset] >> 4) & 0x0f)); + udphdr->dest = lwip_htons(0xf0b0 | (lowpan6_buffer[lowpan6_offset] & 0x0f)); + lowpan6_offset += 1; + } + + udphdr->chksum = lwip_htons(lowpan6_buffer[lowpan6_offset] << 8 | lowpan6_buffer[lowpan6_offset + 1]); + lowpan6_offset += 2; + udphdr->len = lwip_htons(p->tot_len - lowpan6_offset + UDP_HLEN); + + ip6_offset += UDP_HLEN; + } else { + /* @todo support NHC other than UDP */ + pbuf_free(p); + pbuf_free(q); + return NULL; + } + } + + /* Now we copy leftover contents from p to q, so we have all L2 and L3 headers (and L4?) in a single PBUF. + * Replace p with q, and free p */ + pbuf_header(p, -lowpan6_offset); + MEMCPY((u8_t*)q->payload + ip6_offset, p->payload, p->len); + q->len = q->tot_len = ip6_offset + p->len; + if (p->next != NULL) { + pbuf_cat(q, p->next); + } + p->next = NULL; + pbuf_free(p); + + /* Infer IPv6 payload length for header */ + IP6H_PLEN_SET(ip6hdr, q->tot_len - IP6_HLEN); + + /* all done */ + return q; +} + +err_t +lowpan6_input(struct pbuf * p, struct netif *netif) +{ + u8_t * puc; + s8_t i; + struct ieee_802154_addr src, dest; + u16_t datagram_size, datagram_offset, datagram_tag; + struct lowpan6_reass_helper *lrh, *lrh_temp; + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + + /* Analyze header. @todo validate. */ + puc = (u8_t*)p->payload; + datagram_offset = 5; + if ((puc[1] & 0x0c) == 0x0c) { + dest.addr_len = 8; + for (i = 0; i < 8; i++) { + dest.addr[i] = puc[datagram_offset + 7 - i]; + } + datagram_offset += 8; + } else { + dest.addr_len = 2; + dest.addr[0] = puc[datagram_offset + 1]; + dest.addr[1] = puc[datagram_offset]; + datagram_offset += 2; + } + + datagram_offset += 2; /* skip PAN ID. */ + + if ((puc[1] & 0xc0) == 0xc0) { + src.addr_len = 8; + for (i = 0; i < 8; i++) { + src.addr[i] = puc[datagram_offset + 7 - i]; + } + datagram_offset += 8; + } else { + src.addr_len = 2; + src.addr[0] = puc[datagram_offset + 1]; + src.addr[1] = puc[datagram_offset]; + datagram_offset += 2; + } + + pbuf_header(p, -datagram_offset); /* hide IEEE802.15.4 header. */ + + /* Check dispatch. */ + puc = (u8_t*)p->payload; + + if ((*puc & 0xf8) == 0xc0) { + /* FRAG1 dispatch. add this packet to reassembly list. */ + datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; + datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; + + /* check for duplicate */ + lrh = reass_list; + while (lrh != NULL) { + if ((lrh->sender_addr.addr_len == src.addr_len) && + (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0)) { + /* address match with packet in reassembly. */ + if ((datagram_tag == lrh->datagram_tag) && (datagram_size == lrh->datagram_size)) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + /* duplicate fragment. */ + pbuf_free(p); + return ERR_OK; + } else { + /* We are receiving the start of a new datagram. Discard old one (incomplete). */ + lrh_temp = lrh->next_packet; + dequeue_datagram(lrh); + pbuf_free(lrh->pbuf); + mem_free(lrh); + + /* Check next datagram in queue. */ + lrh = lrh_temp; + } + } else { + /* Check next datagram in queue. */ + lrh = lrh->next_packet; + } + } + + pbuf_header(p, -4); /* hide frag1 dispatch */ + + lrh = (struct lowpan6_reass_helper *) mem_malloc(sizeof(struct lowpan6_reass_helper)); + if (lrh == NULL) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + pbuf_free(p); + return ERR_MEM; + } + + lrh->sender_addr.addr_len = src.addr_len; + for (i = 0; i < src.addr_len; i++) { + lrh->sender_addr.addr[i] = src.addr[i]; + } + lrh->datagram_size = datagram_size; + lrh->datagram_tag = datagram_tag; + lrh->pbuf = p; + lrh->next_packet = reass_list; + lrh->timer = 2; + reass_list = lrh; + + return ERR_OK; + } else if ((*puc & 0xf8) == 0xe0) { + /* FRAGN dispatch, find packet being reassembled. */ + datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; + datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; + datagram_offset = (u16_t)puc[4] << 3; + pbuf_header(p, -5); /* hide frag1 dispatch */ + + for (lrh = reass_list; lrh != NULL; lrh = lrh->next_packet) { + if ((lrh->sender_addr.addr_len == src.addr_len) && + (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0) && + (datagram_tag == lrh->datagram_tag) && + (datagram_size == lrh->datagram_size)) { + break; + } + } + if (lrh == NULL) { + /* rogue fragment */ + MIB2_STATS_NETIF_INC(netif, ifindiscards); + pbuf_free(p); + return ERR_OK; + } + + if (lrh->pbuf->tot_len < datagram_offset) { + /* duplicate, ignore. */ + pbuf_free(p); + return ERR_OK; + } else if (lrh->pbuf->tot_len > datagram_offset) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + /* We have missed a fragment. Delete whole reassembly. */ + dequeue_datagram(lrh); + pbuf_free(lrh->pbuf); + mem_free(lrh); + pbuf_free(p); + return ERR_OK; + } + pbuf_cat(lrh->pbuf, p); + p = NULL; + + /* is packet now complete?*/ + if (lrh->pbuf->tot_len >= lrh->datagram_size) { + /* dequeue from reass list. */ + dequeue_datagram(lrh); + + /* get pbuf */ + p = lrh->pbuf; + + /* release helper */ + mem_free(lrh); + } else { + return ERR_OK; + } + } + + if (p == NULL) { + return ERR_OK; + } + + /* We have a complete packet, check dispatch for headers. */ + puc = (u8_t*)p->payload; + + if (*puc == 0x41) { + /* This is a complete IPv6 packet, just skip dispatch byte. */ + pbuf_header(p, -1); /* hide dispatch byte. */ + } else if ((*puc & 0xe0 )== 0x60) { + /* IPv6 headers are compressed using IPHC. */ + p = lowpan6_decompress(p, &src, &dest); + if (p == NULL) { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + return ERR_OK; + } + } else { + MIB2_STATS_NETIF_INC(netif, ifindiscards); + pbuf_free(p); + return ERR_OK; + } + + /* @todo: distinguish unicast/multicast */ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + + return ip6_input(p, netif); +} + +err_t +lowpan6_if_init(struct netif *netif) +{ + netif->name[0] = 'L'; + netif->name[1] = '6'; +#if LWIP_IPV4 + netif->output = lowpan4_output; +#endif /* LWIP_IPV4 */ + netif->output_ip6 = lowpan6_output; + + MIB2_INIT_NETIF(netif, snmp_ifType_other, 0); + + /* maximum transfer unit */ + netif->mtu = 1280; + + /* broadcast capability */ + netif->flags = NETIF_FLAG_BROADCAST /* | NETIF_FLAG_LOWPAN6 */; + + return ERR_OK; +} + +err_t +lowpan6_set_pan_id(u16_t pan_id) +{ + ieee_802154_pan_id = pan_id; + + return ERR_OK; +} + +#if !NO_SYS +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the + * IEEE 802.15.4 header. + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_6lowpan_input(struct pbuf *p, struct netif *inp) +{ + return tcpip_inpkt(p, inp, lowpan6_input); +} +#endif /* !NO_SYS */ + +#endif /* LWIP_IPV6 && LWIP_6LOWPAN */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/PPPD_FOLLOWUP b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/PPPD_FOLLOWUP new file mode 100644 index 0000000000..c231982ae7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/PPPD_FOLLOWUP @@ -0,0 +1,473 @@ +The lwIP PPP support is based from pppd 2.4.5 (http://ppp.samba.org) with +huge changes to match code size and memory requirements for embedded devices. + +Anyway, pppd has a mature codebase for years and the average commit count +is getting low on their Git repository, meaning that we can follow what +is happening on their side and merge what is relevant for lwIP. + +So, here is the pppd follow up, so that we don't get away too far from pppd. + + +== Patch fetched from from pppd Debian packages == + +This has nothing to do with pppd, but we merged some good patch from +Debian and this is a good place to be. + +- LCP adaptive echo, so that we don't send LCP echo request if we + are receiving data from peer, can be enabled by setting PPP_LCP_ADAPTIVE + to true. + +- IPCP no/replace default route option, were added in the early stage of + the ppp port, but it wasn't really helpful and was disabled when adding + the new API ppp_set_default() call, which gives the lwIP user control over + which one is the default interface, it was actually a requirement if you + are doing PPP over PPP (i.e. PPPoL2TP, VPN link, over PPPoE, ADSL link). + +- using rp-pppoe pppd exits with EXIT_OK after receiving a timeout waiting + for PADO due to no modem attached, bug reported to pppd bug tracker, fixed + in Debian but not in the latest (at the time when the port were started) + pppd release. + + +== Commits on pppd == + +2010-03-06 - Document +ipv6 and ipv6cp-accept-local + e7537958aee79b3f653c601e903cb31d78fb7dcc + +Don't care. + + +2010-03-06 - Install pppol2tp plugins with sane permissions + 406215672cfadc03017341fe03802d1c7294b903 + +Don't care. + + +2010-03-07 - pppd: Terminate correctly if lcp_lowerup delayed calling + fsm_lowerup + 3eb9e810cfa515543655659b72dde30c54fea0a5 + +Merged 2012-05-17. + + +2010-03-07 - rp_pppoe: Copy acName and pppd_pppoe_service after option parsing + cab58617fd9d328029fffabc788020264b4fa91f + +Don't care, is a patch for pppd/plugins/rp-pppoe/plugin.c which is not part +of the port. + + +2010-08-23 - set and reset options to control environment variables + for scripts. + 2b6310fd24dba8e0fca8999916a162f0a1842a84 + +We can't fork processes in embedded, therefore all the pppd process run +feature is disabled in the port, so we don't care about the new +"environment variables" pppd feature. + + +2010-08-23 - Nit: use _exit when exec fails and restrict values to 0-255 + per POSIX. + 2b4ea140432eeba5a007c0d4e6236bd0e0c12ba4 + +Again, we are not running as a heavy process, so all exit() or _exit() calls +were removed. + + +2010-08-23 - Fix quote handling in configuration files to be more like shell + quoting. + 3089132cdf5b58dbdfc2daf08ec5c08eb47f8aca + +We are not parsing config file, all the filesystem I/O stuff were disabled +in our port. + + +2010-08-24 - rp-pppoe: allow MTU to be increased up to 1500 + fd1dcdf758418f040da3ed801ab001b5e46854e7 + +Only concern changes on RP-PPPoE plugin, which we don't use. + + +2010-09-11 - chat: Allow TIMEOUT value to come from environment variable + ae80bf833e48a6202f44a935a68083ae52ad3824 + +See 2b6310fd24dba8e0fca8999916a162f0a1842a84. + + +2011-03-05 - pppdump: Fix printfs with insufficient arguments + 7b8db569642c83ba3283745034f2e2c95e459423 + +pppdump is a ppp tool outside pppd source tree. + + +2012-05-06 - pppd: Don't unconditionally disable VJ compression under Linux + d8a66adf98a0e525cf38031b42098d539da6eeb6 + +Patch for sys-linux.c, which we don't use. + + +2012-05-20 - Remove old version of Linux if_pppol2tp.h + c41092dd4c49267f232f6cba3d31c6c68bfdf68d + +Not in the port. + + +2012-05-20 - pppd: Make MSCHAP-v2 cope better with packet loss + 08ef47ca532294eb428238c831616748940e24a2 + +This is an interesting patch. However it consumes much more memory for +MSCHAP and I am not sure if the benefit worth it. The PPP client can +always start the authentication again if it failed for whatever reason. + + +2012-05-20 - scripts: Make poff ignore extra arguments to pppd + 18f515f32c9f5723a9c2c912601e04335106534b + +Again, we are not running scripts. + + +2012-05-20 - rp-pppoe plugin: Print leading zeros in MAC address + f5dda0cfc220c4b52e26144096d729e27b30f0f7 + +Again, we are not using the RP-PPPoE plugin. + + +2012-05-20 - pppd: Notify IPv6 up/down as we do for IPv4 + 845cda8fa18939cf56e60b073f63a7efa65336fc + +This is just a patch that adds plugins hooks for IPv6, the plugin interface +was disabled because we don't have .so plugins in embedded. + + +2012-05-20 - pppd: Enable IPV6 by default and fix some warnings + 0b6118239615e98959f7e0b4e746bdd197533248 + +Change on Makefile for IPv6, warnings were already cleared during port. + + +2012-05-20 - contrib: Fix pppgetpass.gtk compilation + 80a8e2ce257ca12cce723519a0f20ea1d663b14a + +Change on Makefile, don't care. + + +2012-05-20 - pppd: Don't crash if crypt() returns NULL + 04c4348108d847e034dd91066cc6843f60d71731 + +We are using the PolarSSL DES implementation that does not return NULL. + + +2012-05-20 - pppd: Eliminate some warnings + c44ae5e6a7338c96eb463881fe709b2dfaffe568 + +Again, we are handling compilation warnings on our own. + + +2012-05-20 - rp-pppoe plugin: Import some fixes from rp-pppoe-3.10 + 1817d83e51a411044e730ba89ebdb0480e1c8cd4 + +Once more, we are not using the RP-PPPoE plugin. + + +2013-01-23 - pppd: Clarify circumstances where DNS1/DNS2 environment variables are set + cf2f5c9538b9400ade23446a194729b0a4113b3a + +Documentation only. + + +2013-02-03 - ppp: ignore unrecognised radiusclient configuration directives + 7f736dde0da3c19855997d9e67370e351e15e923 + +Radius plugin, not in the port. + + +2013-02-03 - pppd: Take out unused %r conversion completely + 356d8d558d844412119aa18c8e5a113bc6459c7b + +Merged 2014-04-15. + + +2013-02-03 - pppd: Arrange to use logwtmp from libutil on Linux + 9617a7eb137f4fee62799a677a9ecf8d834db3f5 + +Patch for sys-linux.c, which we don't use. + + +2013-02-03 - pppdump: Eliminate some compiler warnings + 3e3acf1ba2b3046c072a42c19164788a9e419bd1 + +pppdump is a ppp tool outside pppd source tree. + + +2013-02-03 - chat: Correct spelling errors in the man page + 8dea1b969d266ccbf6f3a8c5474eb6dcd8838e3b + +Documentation only. + + +2013-02-03 - pppd: Fix spelling errors in man page + 9e05a25d76b3f83096c661678010320df673df6b + +Documentation only. + + +2013-02-03 - plugins/passprompt: Fix potential out-of-bounds array reference + 8edb889b753056a691a3e4b217a110a35f9fdedb + +Plugin patch, we do not have plugins. + + +2013-02-03 - chat: Fix *roff errors in the man page + a7c3489eeaf44e83ce592143c7c8a5b5c29f4c48 + +Documentation only. + + +2013-03-02 - pppd: Fix man page description of case when remote IP address isn't known + 224841f4799f4f1e2e71bc490c54448d66740f4f + +Documentation only. + + +2013-03-02 - pppd: Add master_detach option + 398ed2585640d198c53e736ee5bbd67f7ce8168e + +Option for multilink support, we do not support multilink and this option +is about detaching from the terminal, which is out of the embedded scope. + + +2013-03-11 - pppd: Default exit status to EXIT_CONNECT_FAILED during connection phase + 225361d64ae737afdc8cb57579a2f33525461bc9 + +Commented out in our port, and already fixed by a previously applied Debian patch. + + +2013-03-11 - pppstats: Fix undefined macro in man page + d16a3985eade5280b8e171f5dd0670a91cba0d39 + +Documentation only. + + +2013-05-11 - plugins/radius: Handle bindaddr keyword in radiusclient.conf + d883b2dbafeed3ebd9d7a56ab1469373bd001a3b + +Radius plugin, not in the port. + + +2013-06-09 - pppoatm: Remove explicit loading of pppoatm kernel module + 52cd43a84bea524033b918b603698104f221bbb7 + +PPPoATM plugin, not in the port. + + +2013-06-09 - pppd: Fix segfault in update_db_entry() + 37476164f15a45015310b9d4b197c2d7db1f7f8f + +We do not use the samba db. + + +2013-06-09 - chat: Fix some text that was intended to be literal + cd9683676618adcee8add2c3cfa3382341b5a1f6 + +Documentation only. + + +2013-06-09 - README.pppoe: Minor semantic fix + b5b8898af6fd3d44e873cfc66810ace5f1f47e17 + +Documentation only. + + +2013-06-10 - radius: Handle additional attributes + 2f581cd986a56f2ec4a95abad4f8297a1b10d7e2 + +Radius plugin, not in the port. + + +2013-06-10 - chat, pppd: Use \e instead of \\ in man pages + 8d6942415d22f6ca4377340ca26e345c3f5fa5db + +Documentation only. + + +2014-01-02 - pppd: Don't crash if NULL pointer passed to vslprintf for %q or %v + 906814431bddeb2061825fa1ebad1a967b6d87a9 + +Merged 2014-04-15. + + +2014-01-02 - pppd: Accept IPCP ConfAck packets containing MS-WINS options + a243f217f1c6ac1aa7793806bc88590d077f490a + +Merged 2014-04-15. + + +2014-01-02 - config: Update Solaris compiler options and enable CHAPMS and IPV6 + 99c46caaed01b7edba87962aa52b77fad61bfd7b + +Solaris port, don't care. + + +2014-01-02 - Update README and patchlevel for 2.4.6 release + 4043750fca36e7e0eb90d702e048ad1da4929418 + +Just release stuff. + + +2014-02-18 - pppd: Add option "stop-bits" to set number of serial port stop bits. + ad993a20ee485f0d0e2ac4105221641b200da6e2 + +Low level serial port, not in the port. + + +2014-03-09 - pppd: Separate IPv6 handling for sifup/sifdown + b04d2dc6df5c6b5650fea44250d58757ee3dac4a + +Reimplemented. + + +2014-03-09 - pppol2tp: Connect up/down events to notifiers and add IPv6 ones + fafbe50251efc7d6b4a8be652d085316e112b34f + +Not in the port. + + +2014-03-09 - pppd: Add declarations to eliminate compile warnings + 50967962addebe15c7a7e63116ff46a0441dc464 + +We are handling compilation warnings on our own + + +2014-03-09 - pppd: Eliminate some unnecessary ifdefs + de8da14d845ee6db9236ccfddabf1d8ebf045ddb + +We mostly did that previously. Anyway, merged 2014-12-24. + + +2014-08-01 - radius: Fix realms-config-file option + 880a81be7c8e0fe8567227bc17a1bff3ea035943 + +Radius plugin, not in the port. + + +2014-08-01 - pppd: Eliminate potential integer overflow in option parsing + 7658e8257183f062dc01f87969c140707c7e52cb + +pppd config file parser, not in the port. + + +2014-08-01 - pppd: Eliminate memory leak with multiple instances of a string option + b94b7fbbaa0589aa6ec5fdc733aeb9ff294d2656 + +pppd config file parser, not in the port. + + +2014-08-01 - pppd: Fix a stack variable overflow in MSCHAP-v2 + 36733a891fb56594fcee580f667b33a64b990981 + +This fixes a bug introduced in 08ef47ca ("pppd: Make MSCHAP-v2 cope better with packet loss"). + +We didn't merge 08ef47ca ;-) + + +2014-08-01 - winbind plugin: Add -DMPPE=1 to eliminate compiler warnings + 2b05e22c62095e97dd0a97e4b5588402c2185071 + +Linux plugin, not in the port. + + +2014-08-09 - Update README and patchlevel for 2.4.7 release + 6e8eaa7a78b31cdab2edf140a9c8afdb02ffaca5 + +Just release stuff. + + +2014-08-10 - abort on errors in subdir builds + 5e90783d11a59268e05f4cfb29ce2343b13e8ab2 + +Linux Makefile, not in the port. + + +2014-06-03 - pppd: add support for defaultroute-metric option + 35e5a569c988b1ff865b02a24d9a727a00db4da9 + +Only necessary for Linux, lwIP does not support route metrics. + + +2014-12-13 - scripts: Avoid killing wrong pppd + 67811a647d399db5d188a242827760615a0f86b5 + +pppd helper script, not in the port. + + +2014-12-20 - pppd: Fix sign-extension when displaying bytes in octal + 5e8c3cb256a7e86e3572a82a75d51c6850efdbdc + +Merged 2016-07-02. + + +2015-03-01 - Suppress false error message on PPPoE disconnect + 219aac3b53d0827549377f1bfe22853ee52d4405 + +PPPoE plugin, not in the port. + + +2015-03-01 - Send PADT on PPPoE disconnect + cd2c14f998c57bbe6a01dc5854f2763c0d7f31fb + +PPPoE plugin, not in the port. And our PPPoE implementation already does +that: pppoe_disconnect() calls pppoe_send_padt(). + + +2015-08-14 - pppd: ipxcp: Prevent buffer overrun on remote router name + fe149de624f96629a7f46732055d8f718c74b856 + +We never ported IPX support. lwIP does not support IPX. + + +2015-03-25 - pppd: Fix ccp_options.mppe type + 234edab99a6bb250cc9ecd384cca27b0c8b475ce + +We found that while working on MPPE support in lwIP, that's our patch ;-) + + +2015-03-24 - pppd: Fix ccp_cilen calculated size if both deflate_correct and deflate_draft are enabled + 094cb8ae4c61db225e67fedadb4964f846dd0c27 + +We found that while working on MPPE support in lwIP, that's our patch ;-) + + +2015-08-14 - Merge branch 'master' of https://github.com/ncopa/ppp + 3a5c9a8fbc8970375cd881151d44e4b6fe249c6a + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'master' of git://github.com/vapier/ppp + 912e4fc6665aca188dced7ea7fdc663ce5a2dd24 + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'bug_fix' of git://github.com/radaiming/ppp + dfd33d7f526ecd7b39dd1bba8101260d02af5ebb + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'master' of git://github.com/pprindeville/ppp + aa4a985f6114d08cf4e47634fb6325da71016473 + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'no-error-on-already-closed' of git://github.com/farnz/ppp + 6edf252483b30dbcdcc5059f01831455365d5b6e + +Merge commit, we don't care. + + +2015-08-14 - Merge branch 'send-padt-on-disconnect' of git://github.com/farnz/ppp + 84684243d651f55f6df69d2a6707b52fbbe62bb9 + +Merge commit, we don't care. diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/auth.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/auth.c new file mode 100644 index 0000000000..c8673ad0fb --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/auth.c @@ -0,0 +1,2510 @@ +/* + * auth.c - PPP authentication and phase control. + * + * Copyright (c) 1993-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from main.c, which is: + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_PATH_LASTLOG) && defined(__linux__) +#include +#endif + +#include +#include +#include + +#ifdef HAS_SHADOW +#include +#ifndef PW_PPP +#define PW_PPP PW_LOGIN +#endif +#endif + +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#if CCP_SUPPORT +#include "netif/ppp/ccp.h" +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT +#include "netif/ppp/ecp.h" +#endif /* ECP_SUPPORT */ +#include "netif/ppp/ipcp.h" +#if PAP_SUPPORT +#include "netif/ppp/upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "netif/ppp/eap.h" +#endif /* EAP_SUPPORT */ +#if CBCP_SUPPORT +#include "netif/ppp/cbcp.h" +#endif + +#if 0 /* UNUSED */ +#include "session.h" +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* Bits in scan_authfile return value */ +#define NONWILD_SERVER 1 +#define NONWILD_CLIENT 2 + +#define ISWILD(word) (word[0] == '*' && word[1] == 0) +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* List of addresses which the peer may use. */ +static struct permitted_ip *addresses[NUM_PPP]; + +/* Wordlist giving addresses which the peer may use + without authenticating itself. */ +static struct wordlist *noauth_addrs; + +/* Remote telephone number, if available */ +char remote_number[MAXNAMELEN]; + +/* Wordlist giving remote telephone numbers which may connect. */ +static struct wordlist *permitted_numbers; + +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* Set if we require authentication only because we have a default route. */ +static bool default_auth; + +/* Hook to enable a plugin to control the idle time limit */ +int (*idle_time_hook) (struct ppp_idle *) = NULL; + +/* Hook for a plugin to say whether we can possibly authenticate any peer */ +int (*pap_check_hook) (void) = NULL; + +/* Hook for a plugin to check the PAP user and password */ +int (*pap_auth_hook) (char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts) = NULL; + +/* Hook for a plugin to know about the PAP user logout */ +void (*pap_logout_hook) (void) = NULL; + +/* Hook for a plugin to get the PAP password for authenticating us */ +int (*pap_passwd_hook) (char *user, char *passwd) = NULL; + +/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */ +int (*chap_check_hook) (void) = NULL; + +/* Hook for a plugin to get the CHAP password for authenticating us */ +int (*chap_passwd_hook) (char *user, char *passwd) = NULL; + +/* Hook for a plugin to say whether it is OK if the peer + refuses to authenticate. */ +int (*null_auth_hook) (struct wordlist **paddrs, + struct wordlist **popts) = NULL; + +int (*allowed_address_hook) (u32_t addr) = NULL; +#endif /* UNUSED */ + +#ifdef HAVE_MULTILINK +/* Hook for plugin to hear when an interface joins a multilink bundle */ +void (*multilink_join_hook) (void) = NULL; +#endif + +#if PPP_NOTIFY +/* A notifier for when the peer has authenticated itself, + and we are proceeding to the network phase. */ +struct notifier *auth_up_notifier = NULL; + +/* A notifier for when the link goes down. */ +struct notifier *link_down_notifier = NULL; +#endif /* PPP_NOTIFY */ + +/* + * Option variables. + */ +#if 0 /* MOVED TO ppp_settings */ +bool uselogin = 0; /* Use /etc/passwd for checking PAP */ +bool session_mgmt = 0; /* Do session management (login records) */ +bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ +bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ +bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ +bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */ +#if MSCHAP_SUPPORT +bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */ +bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */ +#else /* MSCHAP_SUPPORT */ +bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */ +bool refuse_mschap_v2 = 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */ +#endif /* MSCHAP_SUPPORT */ +bool usehostname = 0; /* Use hostname for our_name */ +bool auth_required = 0; /* Always require authentication from peer */ +bool allow_any_ip = 0; /* Allow peer to use any IP address */ +bool explicit_remote = 0; /* User specified explicit remote name */ +bool explicit_user = 0; /* Set if "user" option supplied */ +bool explicit_passwd = 0; /* Set if "password" option supplied */ +char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +static char *uafname; /* name of most recent +ua file */ + +extern char *crypt (const char *, const char *); +#endif /* UNUSED */ +/* Prototypes for procedures local to this file. */ + +static void network_phase(ppp_pcb *pcb); +#if PPP_IDLETIMELIMIT +static void check_idle(void *arg); +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT +static void connect_time_expired(void *arg); +#endif /* PPP_MAXCONNECT */ +#if 0 /* UNUSED */ +static int null_login (int); +/* static int get_pap_passwd (char *); */ +static int have_pap_secret (int *); +static int have_chap_secret (char *, char *, int, int *); +static int have_srp_secret (char *client, char *server, int need_ip, + int *lacks_ipp); +static int ip_addr_check (u32_t, struct permitted_ip *); +static int scan_authfile (FILE *, char *, char *, char *, + struct wordlist **, struct wordlist **, + char *, int); +static void free_wordlist (struct wordlist *); +static void set_allowed_addrs (int, struct wordlist *, struct wordlist *); +static int some_ip_ok (struct wordlist *); +static int setupapfile (char **); +static int privgroup (char **); +static int set_noauth_addr (char **); +static int set_permitted_number (char **); +static void check_access (FILE *, char *); +static int wordlist_count (struct wordlist *); +#endif /* UNUSED */ + +#ifdef MAXOCTETS +static void check_maxoctets (void *); +#endif + +#if PPP_OPTIONS +/* + * Authentication-related options. + */ +option_t auth_options[] = { + { "auth", o_bool, &auth_required, + "Require authentication from peer", OPT_PRIO | 1 }, + { "noauth", o_bool, &auth_required, + "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV, + &allow_any_ip }, + { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", + OPT_PRIOSUB | 1, &auth_required }, + { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required }, + { "require-chap", o_bool, &auth_required, + "Require CHAP authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, + &lcp_wantoptions[0].chap_mdtype }, + { "+chap", o_bool, &auth_required, + "Require CHAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, + &lcp_wantoptions[0].chap_mdtype }, +#if MSCHAP_SUPPORT + { "require-mschap", o_bool, &auth_required, + "Require MS-CHAP authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, + &lcp_wantoptions[0].chap_mdtype }, + { "+mschap", o_bool, &auth_required, + "Require MS-CHAP authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, + &lcp_wantoptions[0].chap_mdtype }, + { "require-mschap-v2", o_bool, &auth_required, + "Require MS-CHAPv2 authentication from peer", + OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, + &lcp_wantoptions[0].chap_mdtype }, + { "+mschap-v2", o_bool, &auth_required, + "Require MS-CHAPv2 authentication from peer", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, + &lcp_wantoptions[0].chap_mdtype }, +#endif /* MSCHAP_SUPPORT */ +#if 0 + { "refuse-pap", o_bool, &refuse_pap, + "Don't agree to auth to peer with PAP", 1 }, + { "-pap", o_bool, &refuse_pap, + "Don't allow PAP authentication with peer", OPT_ALIAS | 1 }, + { "refuse-chap", o_bool, &refuse_chap, + "Don't agree to auth to peer with CHAP", + OPT_A2CLRB | MDTYPE_MD5, + &lcp_allowoptions[0].chap_mdtype }, + { "-chap", o_bool, &refuse_chap, + "Don't allow CHAP authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5, + &lcp_allowoptions[0].chap_mdtype }, +#endif +#if MSCHAP_SUPPORT +#if 0 + { "refuse-mschap", o_bool, &refuse_mschap, + "Don't agree to auth to peer with MS-CHAP", + OPT_A2CLRB | MDTYPE_MICROSOFT, + &lcp_allowoptions[0].chap_mdtype }, + { "-mschap", o_bool, &refuse_mschap, + "Don't allow MS-CHAP authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT, + &lcp_allowoptions[0].chap_mdtype }, + { "refuse-mschap-v2", o_bool, &refuse_mschap_v2, + "Don't agree to auth to peer with MS-CHAPv2", + OPT_A2CLRB | MDTYPE_MICROSOFT_V2, + &lcp_allowoptions[0].chap_mdtype }, + { "-mschap-v2", o_bool, &refuse_mschap_v2, + "Don't allow MS-CHAPv2 authentication with peer", + OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2, + &lcp_allowoptions[0].chap_mdtype }, +#endif +#endif /* MSCHAP_SUPPORT*/ +#if EAP_SUPPORT + { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap, + "Require EAP authentication from peer", OPT_PRIOSUB | 1, + &auth_required }, +#if 0 + { "refuse-eap", o_bool, &refuse_eap, + "Don't agree to authenticate to peer with EAP", 1 }, +#endif +#endif /* EAP_SUPPORT */ + { "name", o_string, our_name, + "Set local name for authentication", + OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN }, + + { "+ua", o_special, (void *)setupapfile, + "Get PAP user and password from file", + OPT_PRIO | OPT_A2STRVAL, &uafname }, + +#if 0 + { "user", o_string, user, + "Set name for auth with peer", OPT_PRIO | OPT_STATIC, + &explicit_user, MAXNAMELEN }, + + { "password", o_string, passwd, + "Password for authenticating us to the peer", + OPT_PRIO | OPT_STATIC | OPT_HIDE, + &explicit_passwd, MAXSECRETLEN }, +#endif + + { "usehostname", o_bool, &usehostname, + "Must use hostname for authentication", 1 }, + + { "remotename", o_string, remote_name, + "Set remote name for authentication", OPT_PRIO | OPT_STATIC, + &explicit_remote, MAXNAMELEN }, + + { "login", o_bool, &uselogin, + "Use system password database for PAP", OPT_A2COPY | 1 , + &session_mgmt }, + { "enable-session", o_bool, &session_mgmt, + "Enable session accounting for remote peers", OPT_PRIV | 1 }, + + { "papcrypt", o_bool, &cryptpap, + "PAP passwords are encrypted", 1 }, + + { "privgroup", o_special, (void *)privgroup, + "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST }, + + { "allow-ip", o_special, (void *)set_noauth_addr, + "Set IP address(es) which can be used without authentication", + OPT_PRIV | OPT_A2LIST }, + + { "remotenumber", o_string, remote_number, + "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC, + NULL, MAXNAMELEN }, + + { "allow-number", o_special, (void *)set_permitted_number, + "Set telephone number(s) which are allowed to connect", + OPT_PRIV | OPT_A2LIST }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +#if 0 /* UNUSED */ +/* + * setupapfile - specifies UPAP info for authenticating with peer. + */ +static int +setupapfile(argv) + char **argv; +{ + FILE *ufile; + int l; + uid_t euid; + char u[MAXNAMELEN], p[MAXSECRETLEN]; + char *fname; + + lcp_allowoptions[0].neg_upap = 1; + + /* open user info file */ + fname = strdup(*argv); + if (fname == NULL) + novm("+ua file name"); + euid = geteuid(); + if (seteuid(getuid()) == -1) { + option_error("unable to reset uid before opening %s: %m", fname); + return 0; + } + ufile = fopen(fname, "r"); + if (seteuid(euid) == -1) + fatal("unable to regain privileges: %m"); + if (ufile == NULL) { + option_error("unable to open user login data file %s", fname); + return 0; + } + check_access(ufile, fname); + uafname = fname; + + /* get username */ + if (fgets(u, MAXNAMELEN - 1, ufile) == NULL + || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) { + fclose(ufile); + option_error("unable to read user login data file %s", fname); + return 0; + } + fclose(ufile); + + /* get rid of newlines */ + l = strlen(u); + if (l > 0 && u[l-1] == '\n') + u[l-1] = 0; + l = strlen(p); + if (l > 0 && p[l-1] == '\n') + p[l-1] = 0; + + if (override_value("user", option_priority, fname)) { + strlcpy(ppp_settings.user, u, sizeof(ppp_settings.user)); + explicit_user = 1; + } + if (override_value("passwd", option_priority, fname)) { + strlcpy(ppp_settings.passwd, p, sizeof(ppp_settings.passwd)); + explicit_passwd = 1; + } + + return (1); +} + +/* + * privgroup - allow members of the group to have privileged access. + */ +static int +privgroup(argv) + char **argv; +{ + struct group *g; + int i; + + g = getgrnam(*argv); + if (g == 0) { + option_error("group %s is unknown", *argv); + return 0; + } + for (i = 0; i < ngroups; ++i) { + if (groups[i] == g->gr_gid) { + privileged = 1; + break; + } + } + return 1; +} + + +/* + * set_noauth_addr - set address(es) that can be used without authentication. + * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. + */ +static int +set_noauth_addr(argv) + char **argv; +{ + char *addr = *argv; + int l = strlen(addr) + 1; + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); + if (wp == NULL) + novm("allow-ip argument"); + wp->word = (char *) (wp + 1); + wp->next = noauth_addrs; + MEMCPY(wp->word, addr, l); + noauth_addrs = wp; + return 1; +} + + +/* + * set_permitted_number - set remote telephone number(s) that may connect. + */ +static int +set_permitted_number(argv) + char **argv; +{ + char *number = *argv; + int l = strlen(number) + 1; + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); + if (wp == NULL) + novm("allow-number argument"); + wp->word = (char *) (wp + 1); + wp->next = permitted_numbers; + MEMCPY(wp->word, number, l); + permitted_numbers = wp; + return 1; +} +#endif + +/* + * An Open on LCP has requested a change from Dead to Establish phase. + */ +void link_required(ppp_pcb *pcb) { + LWIP_UNUSED_ARG(pcb); +} + +#if 0 +/* + * Bring the link up to the point of being able to do ppp. + */ +void start_link(unit) + int unit; +{ + ppp_pcb *pcb = &ppp_pcb_list[unit]; + char *msg; + + status = EXIT_NEGOTIATION_FAILED; + new_phase(pcb, PPP_PHASE_SERIALCONN); + + hungup = 0; + devfd = the_channel->connect(); + msg = "Connect script failed"; + if (devfd < 0) + goto fail; + + /* set up the serial device as a ppp interface */ + /* + * N.B. we used to do tdb_writelock/tdb_writeunlock around this + * (from establish_ppp to set_ifunit). However, we won't be + * doing the set_ifunit in multilink mode, which is the only time + * we need the atomicity that the tdb_writelock/tdb_writeunlock + * gives us. Thus we don't need the tdb_writelock/tdb_writeunlock. + */ + fd_ppp = the_channel->establish_ppp(devfd); + msg = "ppp establishment failed"; + if (fd_ppp < 0) { + status = EXIT_FATAL_ERROR; + goto disconnect; + } + + if (!demand && ifunit >= 0) + set_ifunit(1); + + /* + * Start opening the connection and wait for + * incoming events (reply, timeout, etc.). + */ + if (ifunit >= 0) + ppp_notice("Connect: %s <--> %s", ifname, ppp_devnam); + else + ppp_notice("Starting negotiation on %s", ppp_devnam); + add_fd(fd_ppp); + + new_phase(pcb, PPP_PHASE_ESTABLISH); + + lcp_lowerup(pcb); + return; + + disconnect: + new_phase(pcb, PPP_PHASE_DISCONNECT); + if (the_channel->disconnect) + the_channel->disconnect(); + + fail: + new_phase(pcb, PPP_PHASE_DEAD); + if (the_channel->cleanup) + (*the_channel->cleanup)(); +} +#endif + +/* + * LCP has terminated the link; go to the Dead phase and take the + * physical layer down. + */ +void link_terminated(ppp_pcb *pcb) { + if (pcb->phase == PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + || pcb->phase == PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + return; + new_phase(pcb, PPP_PHASE_DISCONNECT); + +#if 0 /* UNUSED */ + if (pap_logout_hook) { + pap_logout_hook(); + } + session_end(devnam); +#endif /* UNUSED */ + + if (!doing_multilink) { + ppp_notice("Connection terminated."); +#if PPP_STATS_SUPPORT + print_link_stats(); +#endif /* PPP_STATS_SUPPORT */ + } else + ppp_notice("Link terminated."); + + lcp_lowerdown(pcb); + + ppp_link_terminated(pcb); +#if 0 + /* + * Delete pid files before disestablishing ppp. Otherwise it + * can happen that another pppd gets the same unit and then + * we delete its pid file. + */ + if (!doing_multilink && !demand) + remove_pidfiles(); + + /* + * If we may want to bring the link up again, transfer + * the ppp unit back to the loopback. Set the + * real serial device back to its normal mode of operation. + */ + if (fd_ppp >= 0) { + remove_fd(fd_ppp); + clean_check(); + the_channel->disestablish_ppp(devfd); + if (doing_multilink) + mp_exit_bundle(); + fd_ppp = -1; + } + if (!hungup) + lcp_lowerdown(pcb); + if (!doing_multilink && !demand) + script_unsetenv("IFNAME"); + + /* + * Run disconnector script, if requested. + * XXX we may not be able to do this if the line has hung up! + */ + if (devfd >= 0 && the_channel->disconnect) { + the_channel->disconnect(); + devfd = -1; + } + if (the_channel->cleanup) + (*the_channel->cleanup)(); + + if (doing_multilink && multilink_master) { + if (!bundle_terminating) + new_phase(pcb, PPP_PHASE_MASTER); + else + mp_bundle_terminated(); + } else + new_phase(pcb, PPP_PHASE_DEAD); +#endif +} + +/* + * LCP has gone down; it will either die or try to re-establish. + */ +void link_down(ppp_pcb *pcb) { +#if PPP_NOTIFY + notify(link_down_notifier, 0); +#endif /* PPP_NOTIFY */ + + if (!doing_multilink) { + upper_layers_down(pcb); + if (pcb->phase != PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + && pcb->phase != PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + new_phase(pcb, PPP_PHASE_ESTABLISH); + } + /* XXX if doing_multilink, should do something to stop + network-layer traffic on the link */ +} + +void upper_layers_down(ppp_pcb *pcb) { + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) + (*protp->lowerdown)(pcb); + if (protp->protocol < 0xC000 && protp->close != NULL) + (*protp->close)(pcb, "LCP down"); + } + pcb->num_np_open = 0; + pcb->num_np_up = 0; +} + +/* + * The link is established. + * Proceed to the Dead, Authenticate or Network phase as appropriate. + */ +void link_established(ppp_pcb *pcb) { +#if PPP_AUTH_SUPPORT + int auth; +#if PPP_SERVER +#if PAP_SUPPORT + lcp_options *wo = &pcb->lcp_wantoptions; +#endif /* PAP_SUPPORT */ + lcp_options *go = &pcb->lcp_gotoptions; +#endif /* PPP_SERVER */ + lcp_options *ho = &pcb->lcp_hisoptions; +#endif /* PPP_AUTH_SUPPORT */ + int i; + const struct protent *protp; + + /* + * Tell higher-level protocols that LCP is up. + */ + if (!doing_multilink) { + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol != PPP_LCP + && protp->lowerup != NULL) + (*protp->lowerup)(pcb); + } + +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +#if PPP_ALLOWED_ADDRS + if (!auth_required && noauth_addrs != NULL) + set_allowed_addrs(unit, NULL, NULL); +#endif /* PPP_ALLOWED_ADDRS */ + + if (pcb->settings.auth_required && !(0 +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + )) { + +#if PPP_ALLOWED_ADDRS + /* + * We wanted the peer to authenticate itself, and it refused: + * if we have some address(es) it can use without auth, fine, + * otherwise treat it as though it authenticated with PAP using + * a username of "" and a password of "". If that's not OK, + * boot it out. + */ + if (noauth_addrs != NULL) { + set_allowed_addrs(unit, NULL, NULL); + } else +#endif /* PPP_ALLOWED_ADDRS */ + if (!pcb->settings.null_login +#if PAP_SUPPORT + || !wo->neg_upap +#endif /* PAP_SUPPORT */ + ) { + ppp_warn("peer refused to authenticate: terminating link"); +#if 0 /* UNUSED */ + status = EXIT_PEER_AUTH_FAILED; +#endif /* UNUSED */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "peer refused to authenticate"); + return; + } + } +#endif /* PPP_SERVER */ + + new_phase(pcb, PPP_PHASE_AUTHENTICATE); + auth = 0; +#if PPP_SERVER +#if EAP_SUPPORT + if (go->neg_eap) { + eap_authpeer(pcb, PPP_OUR_NAME); + auth |= EAP_PEER; + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (go->neg_chap) { + chap_auth_peer(pcb, PPP_OUR_NAME, CHAP_DIGEST(go->chap_mdtype)); + auth |= CHAP_PEER; + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if (go->neg_upap) { + upap_authpeer(pcb); + auth |= PAP_PEER; + } else +#endif /* PAP_SUPPORT */ + {} +#endif /* PPP_SERVER */ + +#if EAP_SUPPORT + if (ho->neg_eap) { + eap_authwithpeer(pcb, pcb->settings.user); + auth |= EAP_WITHPEER; + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (ho->neg_chap) { + chap_auth_with_peer(pcb, pcb->settings.user, CHAP_DIGEST(ho->chap_mdtype)); + auth |= CHAP_WITHPEER; + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if (ho->neg_upap) { + upap_authwithpeer(pcb, pcb->settings.user, pcb->settings.passwd); + auth |= PAP_WITHPEER; + } else +#endif /* PAP_SUPPORT */ + {} + + pcb->auth_pending = auth; + pcb->auth_done = 0; + + if (!auth) +#endif /* PPP_AUTH_SUPPORT */ + network_phase(pcb); +} + +/* + * Proceed to the network phase. + */ +static void network_phase(ppp_pcb *pcb) { +#if CBCP_SUPPORT + ppp_pcb *pcb = &ppp_pcb_list[unit]; +#endif +#if 0 /* UNUSED */ + lcp_options *go = &lcp_gotoptions[unit]; +#endif /* UNUSED */ + +#if 0 /* UNUSED */ + /* Log calling number. */ + if (*remote_number) + ppp_notice("peer from calling number %q authorized", remote_number); +#endif /* UNUSED */ + +#if PPP_NOTIFY + /* + * If the peer had to authenticate, notify it now. + */ + if (0 +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + ) { + notify(auth_up_notifier, 0); + } +#endif /* PPP_NOTIFY */ + +#if CBCP_SUPPORT + /* + * If we negotiated callback, do it now. + */ + if (go->neg_cbcp) { + new_phase(pcb, PPP_PHASE_CALLBACK); + (*cbcp_protent.open)(pcb); + return; + } +#endif + +#if PPP_OPTIONS + /* + * Process extra options from the secrets file + */ + if (extra_options) { + options_from_list(extra_options, 1); + free_wordlist(extra_options); + extra_options = 0; + } +#endif /* PPP_OPTIONS */ + start_networks(pcb); +} + +void start_networks(ppp_pcb *pcb) { +#if CCP_SUPPORT || ECP_SUPPORT + int i; + const struct protent *protp; +#endif /* CCP_SUPPORT || ECP_SUPPORT */ + + new_phase(pcb, PPP_PHASE_NETWORK); + +#ifdef HAVE_MULTILINK + if (multilink) { + if (mp_join_bundle()) { + if (multilink_join_hook) + (*multilink_join_hook)(); + if (updetach && !nodetach) + detach(); + return; + } + } +#endif /* HAVE_MULTILINK */ + +#ifdef PPP_FILTER + if (!demand) + set_filters(&pass_filter, &active_filter); +#endif +#if CCP_SUPPORT || ECP_SUPPORT + /* Start CCP and ECP */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if ( + (0 +#if ECP_SUPPORT + || protp->protocol == PPP_ECP +#endif /* ECP_SUPPORT */ +#if CCP_SUPPORT + || protp->protocol == PPP_CCP +#endif /* CCP_SUPPORT */ + ) + && protp->open != NULL) + (*protp->open)(pcb); +#endif /* CCP_SUPPORT || ECP_SUPPORT */ + + /* + * Bring up other network protocols iff encryption is not required. + */ + if (1 +#if ECP_SUPPORT + && !ecp_gotoptions[unit].required +#endif /* ECP_SUPPORT */ +#if MPPE_SUPPORT + && !pcb->ccp_gotoptions.mppe +#endif /* MPPE_SUPPORT */ + ) + continue_networks(pcb); +} + +void continue_networks(ppp_pcb *pcb) { + int i; + const struct protent *protp; + + /* + * Start the "real" network protocols. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol < 0xC000 +#if CCP_SUPPORT + && protp->protocol != PPP_CCP +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT + && protp->protocol != PPP_ECP +#endif /* ECP_SUPPORT */ + && protp->open != NULL) { + (*protp->open)(pcb); + ++pcb->num_np_open; + } + + if (pcb->num_np_open == 0) + /* nothing to do */ + lcp_close(pcb, "No network protocols running"); +} + +#if PPP_AUTH_SUPPORT +#if PPP_SERVER +/* + * auth_check_passwd - Check the user name and passwd against configuration. + * + * returns: + * 0: Authentication failed. + * 1: Authentication succeeded. + * In either case, msg points to an appropriate message and msglen to the message len. + */ +int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen) { + int secretuserlen; + int secretpasswdlen; + + if (pcb->settings.user && pcb->settings.passwd) { + secretuserlen = (int)strlen(pcb->settings.user); + secretpasswdlen = (int)strlen(pcb->settings.passwd); + if (secretuserlen == userlen + && secretpasswdlen == passwdlen + && !memcmp(auser, pcb->settings.user, userlen) + && !memcmp(apasswd, pcb->settings.passwd, passwdlen) ) { + *msg = "Login ok"; + *msglen = sizeof("Login ok")-1; + return 1; + } + } + + *msg = "Login incorrect"; + *msglen = sizeof("Login incorrect")-1; + return 0; +} + +/* + * The peer has failed to authenticate himself using `protocol'. + */ +void auth_peer_fail(ppp_pcb *pcb, int protocol) { + LWIP_UNUSED_ARG(protocol); + /* + * Authentication failure: take the link down + */ +#if 0 /* UNUSED */ + status = EXIT_PEER_AUTH_FAILED; +#endif /* UNUSED */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "Authentication failed"); +} + +/* + * The peer has been successfully authenticated using `protocol'. + */ +void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *name, int namelen) { + int bit; +#ifndef HAVE_MULTILINK + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(namelen); +#endif /* HAVE_MULTILINK */ + + switch (protocol) { +#if CHAP_SUPPORT + case PPP_CHAP: + bit = CHAP_PEER; + switch (prot_flavor) { + case CHAP_MD5: + bit |= CHAP_MD5_PEER; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + bit |= CHAP_MS_PEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_PEER; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + break; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + case PPP_PAP: + bit = PAP_PEER; + break; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + bit = EAP_PEER; + break; +#endif /* EAP_SUPPORT */ + default: + ppp_warn("auth_peer_success: unknown protocol %x", protocol); + return; + } + +#ifdef HAVE_MULTILINK + /* + * Save the authenticated name of the peer for later. + */ + if (namelen > (int)sizeof(pcb->peer_authname) - 1) + namelen = (int)sizeof(pcb->peer_authname) - 1; + MEMCPY(pcb->peer_authname, name, namelen); + pcb->peer_authname[namelen] = 0; +#endif /* HAVE_MULTILINK */ +#if 0 /* UNUSED */ + script_setenv("PEERNAME", , 0); +#endif /* UNUSED */ + + /* Save the authentication method for later. */ + pcb->auth_done |= bit; + + /* + * If there is no more authentication still to be done, + * proceed to the network (or callback) phase. + */ + if ((pcb->auth_pending &= ~bit) == 0) + network_phase(pcb); +} +#endif /* PPP_SERVER */ + +/* + * We have failed to authenticate ourselves to the peer using `protocol'. + */ +void auth_withpeer_fail(ppp_pcb *pcb, int protocol) { + LWIP_UNUSED_ARG(protocol); + /* + * We've failed to authenticate ourselves to our peer. + * + * Some servers keep sending CHAP challenges, but there + * is no point in persisting without any way to get updated + * authentication secrets. + * + * He'll probably take the link down, and there's not much + * we can do except wait for that. + */ + pcb->err_code = PPPERR_AUTHFAIL; + lcp_close(pcb, "Failed to authenticate ourselves to peer"); +} + +/* + * We have successfully authenticated ourselves with the peer using `protocol'. + */ +void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { + int bit; + const char *prot = ""; + + switch (protocol) { +#if CHAP_SUPPORT + case PPP_CHAP: + bit = CHAP_WITHPEER; + prot = "CHAP"; + switch (prot_flavor) { + case CHAP_MD5: + bit |= CHAP_MD5_WITHPEER; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + bit |= CHAP_MS_WITHPEER; + break; + case CHAP_MICROSOFT_V2: + bit |= CHAP_MS2_WITHPEER; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + break; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + case PPP_PAP: + bit = PAP_WITHPEER; + prot = "PAP"; + break; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + bit = EAP_WITHPEER; + prot = "EAP"; + break; +#endif /* EAP_SUPPORT */ + default: + ppp_warn("auth_withpeer_success: unknown protocol %x", protocol); + bit = 0; + /* no break */ + } + + ppp_notice("%s authentication succeeded", prot); + + /* Save the authentication method for later. */ + pcb->auth_done |= bit; + + /* + * If there is no more authentication still being done, + * proceed to the network (or callback) phase. + */ + if ((pcb->auth_pending &= ~bit) == 0) + network_phase(pcb); +} +#endif /* PPP_AUTH_SUPPORT */ + + +/* + * np_up - a network protocol has come up. + */ +void np_up(ppp_pcb *pcb, int proto) { +#if PPP_IDLETIMELIMIT + int tlim; +#endif /* PPP_IDLETIMELIMIT */ + LWIP_UNUSED_ARG(proto); + + if (pcb->num_np_up == 0) { + /* + * At this point we consider that the link has come up successfully. + */ + new_phase(pcb, PPP_PHASE_RUNNING); + +#if PPP_IDLETIMELIMIT +#if 0 /* UNUSED */ + if (idle_time_hook != 0) + tlim = (*idle_time_hook)(NULL); + else +#endif /* UNUSED */ + tlim = pcb->settings.idle_time_limit; + if (tlim > 0) + TIMEOUT(check_idle, (void*)pcb, tlim); +#endif /* PPP_IDLETIMELIMIT */ + +#if PPP_MAXCONNECT + /* + * Set a timeout to close the connection once the maximum + * connect time has expired. + */ + if (pcb->settings.maxconnect > 0) + TIMEOUT(connect_time_expired, (void*)pcb, pcb->settings.maxconnect); +#endif /* PPP_MAXCONNECT */ + +#ifdef MAXOCTETS + if (maxoctets > 0) + TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); +#endif + +#if 0 /* Unused */ + /* + * Detach now, if the updetach option was given. + */ + if (updetach && !nodetach) + detach(); +#endif /* Unused */ + } + ++pcb->num_np_up; +} + +/* + * np_down - a network protocol has gone down. + */ +void np_down(ppp_pcb *pcb, int proto) { + LWIP_UNUSED_ARG(proto); + if (--pcb->num_np_up == 0) { +#if PPP_IDLETIMELIMIT + UNTIMEOUT(check_idle, (void*)pcb); +#endif /* PPP_IDLETIMELIMIT */ +#if PPP_MAXCONNECT + UNTIMEOUT(connect_time_expired, NULL); +#endif /* PPP_MAXCONNECT */ +#ifdef MAXOCTETS + UNTIMEOUT(check_maxoctets, NULL); +#endif + new_phase(pcb, PPP_PHASE_NETWORK); + } +} + +/* + * np_finished - a network protocol has finished using the link. + */ +void np_finished(ppp_pcb *pcb, int proto) { + LWIP_UNUSED_ARG(proto); + if (--pcb->num_np_open <= 0) { + /* no further use for the link: shut up shop. */ + lcp_close(pcb, "No network protocols running"); + } +} + +#ifdef MAXOCTETS +static void +check_maxoctets(arg) + void *arg; +{ +#if PPP_STATS_SUPPORT + unsigned int used; + + update_link_stats(ifunit); + link_stats_valid=0; + + switch(maxoctets_dir) { + case PPP_OCTETS_DIRECTION_IN: + used = link_stats.bytes_in; + break; + case PPP_OCTETS_DIRECTION_OUT: + used = link_stats.bytes_out; + break; + case PPP_OCTETS_DIRECTION_MAXOVERAL: + case PPP_OCTETS_DIRECTION_MAXSESSION: + used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out; + break; + default: + used = link_stats.bytes_in+link_stats.bytes_out; + break; + } + if (used > maxoctets) { + ppp_notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); + status = EXIT_TRAFFIC_LIMIT; + lcp_close(pcb, "Traffic limit"); +#if 0 /* UNUSED */ + need_holdoff = 0; +#endif /* UNUSED */ + } else { + TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); + } +#endif /* PPP_STATS_SUPPORT */ +} +#endif /* MAXOCTETS */ + +#if PPP_IDLETIMELIMIT +/* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void check_idle(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + struct ppp_idle idle; + time_t itime; + int tlim; + + if (!get_idle_time(pcb, &idle)) + return; +#if 0 /* UNUSED */ + if (idle_time_hook != 0) { + tlim = idle_time_hook(&idle); + } else { +#endif /* UNUSED */ + itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); + tlim = pcb->settings.idle_time_limit - itime; +#if 0 /* UNUSED */ + } +#endif /* UNUSED */ + if (tlim <= 0) { + /* link is idle: shut it down. */ + ppp_notice("Terminating connection due to lack of activity."); + pcb->err_code = PPPERR_IDLETIMEOUT; + lcp_close(pcb, "Link inactive"); +#if 0 /* UNUSED */ + need_holdoff = 0; +#endif /* UNUSED */ + } else { + TIMEOUT(check_idle, (void*)pcb, tlim); + } +} +#endif /* PPP_IDLETIMELIMIT */ + +#if PPP_MAXCONNECT +/* + * connect_time_expired - log a message and close the connection. + */ +static void connect_time_expired(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + ppp_info("Connect time expired"); + pcb->err_code = PPPERR_CONNECTTIME; + lcp_close(pcb, "Connect time expired"); /* Close connection */ +} +#endif /* PPP_MAXCONNECT */ + +#if PPP_OPTIONS +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options() +{ + lcp_options *wo = &lcp_wantoptions[0]; + int can_auth; + int lacks_ip; + + /* Default our_name to hostname, and user to our_name */ + if (our_name[0] == 0 || usehostname) + strlcpy(our_name, hostname, sizeof(our_name)); + /* If a blank username was explicitly given as an option, trust + the user and don't use our_name */ + if (ppp_settings.user[0] == 0 && !explicit_user) + strlcpy(ppp_settings.user, our_name, sizeof(ppp_settings.user)); + + /* + * If we have a default route, require the peer to authenticate + * unless the noauth option was given or the real user is root. + */ + if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) { + auth_required = 1; + default_auth = 1; + } + +#if CHAP_SUPPORT + /* If we selected any CHAP flavors, we should probably negotiate it. :-) */ + if (wo->chap_mdtype) + wo->neg_chap = 1; +#endif /* CHAP_SUPPORT */ + + /* If authentication is required, ask peer for CHAP, PAP, or EAP. */ + if (auth_required) { + allow_any_ip = 0; + if (1 +#if CHAP_SUPPORT + && !wo->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + && !wo->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + && !wo->neg_eap +#endif /* EAP_SUPPORT */ + ) { +#if CHAP_SUPPORT + wo->neg_chap = CHAP_MDTYPE_SUPPORTED != MDTYPE_NONE; + wo->chap_mdtype = CHAP_MDTYPE_SUPPORTED; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + wo->neg_upap = 1; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + wo->neg_eap = 1; +#endif /* EAP_SUPPORT */ + } + } else { +#if CHAP_SUPPORT + wo->neg_chap = 0; + wo->chap_mdtype = MDTYPE_NONE; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + wo->neg_upap = 0; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + wo->neg_eap = 0; +#endif /* EAP_SUPPORT */ + } + + /* + * Check whether we have appropriate secrets to use + * to authenticate the peer. Note that EAP can authenticate by way + * of a CHAP-like exchanges as well as SRP. + */ + lacks_ip = 0; +#if PAP_SUPPORT + can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); +#else + can_auth = 0; +#endif /* PAP_SUPPORT */ + if (!can_auth && (0 +#if CHAP_SUPPORT + || wo->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || wo->neg_eap +#endif /* EAP_SUPPORT */ + )) { +#if CHAP_SUPPORT + can_auth = have_chap_secret((explicit_remote? remote_name: NULL), + our_name, 1, &lacks_ip); +#else + can_auth = 0; +#endif + } + if (!can_auth +#if EAP_SUPPORT + && wo->neg_eap +#endif /* EAP_SUPPORT */ + ) { + can_auth = have_srp_secret((explicit_remote? remote_name: NULL), + our_name, 1, &lacks_ip); + } + + if (auth_required && !can_auth && noauth_addrs == NULL) { + if (default_auth) { + option_error( +"By default the remote system is required to authenticate itself"); + option_error( +"(because this system has a default route to the internet)"); + } else if (explicit_remote) + option_error( +"The remote system (%s) is required to authenticate itself", + remote_name); + else + option_error( +"The remote system is required to authenticate itself"); + option_error( +"but I couldn't find any suitable secret (password) for it to use to do so."); + if (lacks_ip) + option_error( +"(None of the available passwords would let it use an IP address.)"); + + exit(1); + } + + /* + * Early check for remote number authorization. + */ + if (!auth_number()) { + ppp_warn("calling number %q is not authorized", remote_number); + exit(EXIT_CNID_AUTH_FAILED); + } +} +#endif /* PPP_OPTIONS */ + +#if 0 /* UNUSED */ +/* + * auth_reset - called when LCP is starting negotiations to recheck + * authentication options, i.e. whether we have appropriate secrets + * to use for authenticating ourselves and/or the peer. + */ +void +auth_reset(unit) + int unit; +{ + lcp_options *go = &lcp_gotoptions[unit]; + lcp_options *ao = &lcp_allowoptions[unit]; + int hadchap; + + hadchap = -1; + ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL)); + ao->neg_chap = (!refuse_chap || !refuse_mschap || !refuse_mschap_v2) + && (passwd[0] != 0 || + (hadchap = have_chap_secret(user, (explicit_remote? remote_name: + NULL), 0, NULL))); + ao->neg_eap = !refuse_eap && ( + passwd[0] != 0 || + (hadchap == 1 || (hadchap == -1 && have_chap_secret(user, + (explicit_remote? remote_name: NULL), 0, NULL))) || + have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)); + + hadchap = -1; + if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) + go->neg_upap = 0; + if (go->neg_chap) { + if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL), + our_name, 1, NULL))) + go->neg_chap = 0; + } + if (go->neg_eap && + (hadchap == 0 || (hadchap == -1 && + !have_chap_secret((explicit_remote? remote_name: NULL), our_name, + 1, NULL))) && + !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, + NULL)) + go->neg_eap = 0; +} + +/* + * check_passwd - Check the user name and passwd against the PAP secrets + * file. If requested, also check against the system password database, + * and login the user if OK. + * + * returns: + * UPAP_AUTHNAK: Authentication failed. + * UPAP_AUTHACK: Authentication succeeded. + * In either case, msg points to an appropriate message. + */ +int +check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) + int unit; + char *auser; + int userlen; + char *apasswd; + int passwdlen; + char **msg; +{ + return UPAP_AUTHNAK; + int ret; + char *filename; + FILE *f; + struct wordlist *addrs = NULL, *opts = NULL; + char passwd[256], user[256]; + char secret[MAXWORDLEN]; + static int attempts = 0; + + /* + * Make copies of apasswd and auser, then null-terminate them. + * If there are unprintable characters in the password, make + * them visible. + */ + slprintf(ppp_settings.passwd, sizeof(ppp_settings.passwd), "%.*v", passwdlen, apasswd); + slprintf(ppp_settings.user, sizeof(ppp_settings.user), "%.*v", userlen, auser); + *msg = ""; + + /* + * Check if a plugin wants to handle this. + */ + if (pap_auth_hook) { + ret = (*pap_auth_hook)(ppp_settings.user, ppp_settings.passwd, msg, &addrs, &opts); + if (ret >= 0) { + /* note: set_allowed_addrs() saves opts (but not addrs): + don't free it! */ + if (ret) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); + return ret? UPAP_AUTHACK: UPAP_AUTHNAK; + } + } + + /* + * Open the file of pap secrets and scan for a suitable secret + * for authenticating this user. + */ + filename = _PATH_UPAPFILE; + addrs = opts = NULL; + ret = UPAP_AUTHNAK; + f = fopen(filename, "r"); + if (f == NULL) { + ppp_error("Can't open PAP password file %s: %m", filename); + + } else { + check_access(f, filename); + if (scan_authfile(f, ppp_settings.user, our_name, secret, &addrs, &opts, filename, 0) < 0) { + ppp_warn("no PAP secret found for %s", user); + } else { + /* + * If the secret is "@login", it means to check + * the password against the login database. + */ + int login_secret = strcmp(secret, "@login") == 0; + ret = UPAP_AUTHACK; + if (uselogin || login_secret) { + /* login option or secret is @login */ + if (session_full(ppp_settings.user, ppp_settings.passwd, devnam, msg) == 0) { + ret = UPAP_AUTHNAK; + } + } else if (session_mgmt) { + if (session_check(ppp_settings.user, NULL, devnam, NULL) == 0) { + ppp_warn("Peer %q failed PAP Session verification", user); + ret = UPAP_AUTHNAK; + } + } + if (secret[0] != 0 && !login_secret) { + /* password given in pap-secrets - must match */ + if ((cryptpap || strcmp(ppp_settings.passwd, secret) != 0) + && strcmp(crypt(ppp_settings.passwd, secret), secret) != 0) + ret = UPAP_AUTHNAK; + } + } + fclose(f); + } + + if (ret == UPAP_AUTHNAK) { + if (**msg == 0) + *msg = "Login incorrect"; + /* + * XXX can we ever get here more than once?? + * Frustrate passwd stealer programs. + * Allow 10 tries, but start backing off after 3 (stolen from login). + * On 10'th, drop the connection. + */ + if (attempts++ >= 10) { + ppp_warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); + lcp_close(pcb, "login failed"); + } + if (attempts > 3) + sleep((u_int) (attempts - 3) * 5); + if (opts != NULL) + free_wordlist(opts); + + } else { + attempts = 0; /* Reset count */ + if (**msg == 0) + *msg = "Login ok"; + set_allowed_addrs(unit, addrs, opts); + } + + if (addrs != NULL) + free_wordlist(addrs); + BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); + BZERO(secret, sizeof(secret)); + + return ret; +} + +/* + * null_login - Check if a username of "" and a password of "" are + * acceptable, and iff so, set the list of acceptable IP addresses + * and return 1. + */ +static int +null_login(unit) + int unit; +{ + char *filename; + FILE *f; + int i, ret; + struct wordlist *addrs, *opts; + char secret[MAXWORDLEN]; + + /* + * Check if a plugin wants to handle this. + */ + ret = -1; + if (null_auth_hook) + ret = (*null_auth_hook)(&addrs, &opts); + + /* + * Open the file of pap secrets and scan for a suitable secret. + */ + if (ret <= 0) { + filename = _PATH_UPAPFILE; + addrs = NULL; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + check_access(f, filename); + + i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0); + ret = i >= 0 && secret[0] == 0; + BZERO(secret, sizeof(secret)); + fclose(f); + } + + if (ret) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + + return ret; +} + +/* + * get_pap_passwd - get a password for authenticating ourselves with + * our peer using PAP. Returns 1 on success, 0 if no suitable password + * could be found. + * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null). + */ +static int +get_pap_passwd(passwd) + char *passwd; +{ + char *filename; + FILE *f; + int ret; + char secret[MAXWORDLEN]; + + /* + * Check whether a plugin wants to supply this. + */ + if (pap_passwd_hook) { + ret = (*pap_passwd_hook)(ppp_settings,user, ppp_settings.passwd); + if (ret >= 0) + return ret; + } + + filename = _PATH_UPAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + check_access(f, filename); + ret = scan_authfile(f, user, + (remote_name[0]? remote_name: NULL), + secret, NULL, NULL, filename, 0); + fclose(f); + if (ret < 0) + return 0; + if (passwd != NULL) + strlcpy(passwd, secret, MAXSECRETLEN); + BZERO(secret, sizeof(secret)); + return 1; +} + +/* + * have_pap_secret - check whether we have a PAP file with any + * secrets that we could possibly use for authenticating the peer. + */ +static int +have_pap_secret(lacks_ipp) + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + /* let the plugin decide, if there is one */ + if (pap_check_hook) { + ret = (*pap_check_hook)(); + if (ret >= 0) + return ret; + } + + filename = _PATH_UPAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, + NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + +/* + * have_chap_secret - check whether we have a CHAP file with a + * secret that we could possibly use for authenticating `client' + * on `server'. Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_chap_secret(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + if (chap_check_hook) { + ret = (*chap_check_hook)(); + if (ret >= 0) { + return ret; + } + } + + filename = _PATH_CHAPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + +/* + * have_srp_secret - check whether we have a SRP file with a + * secret that we could possibly use for authenticating `client' + * on `server'. Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_srp_secret(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + filename = _PATH_SRPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} +#endif /* UNUSED */ + +#if PPP_AUTH_SUPPORT +/* + * get_secret - open the CHAP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server) { + int len; + LWIP_UNUSED_ARG(server); + LWIP_UNUSED_ARG(am_server); + + if (!client || !client[0] || !pcb->settings.user || !pcb->settings.passwd || strcmp(client, pcb->settings.user)) { + return 0; + } + + len = (int)strlen(pcb->settings.passwd); + if (len > MAXSECRETLEN) { + ppp_error("Secret for %s on %s is too long", client, server); + len = MAXSECRETLEN; + } + + MEMCPY(secret, pcb->settings.passwd, len); + *secret_len = len; + return 1; + +#if 0 /* UNUSED */ + FILE *f; + int ret, len; + char *filename; + struct wordlist *addrs, *opts; + char secbuf[MAXWORDLEN]; + struct wordlist *addrs; + addrs = NULL; + + if (!am_server && ppp_settings.passwd[0] != 0) { + strlcpy(secbuf, ppp_settings.passwd, sizeof(secbuf)); + } else if (!am_server && chap_passwd_hook) { + if ( (*chap_passwd_hook)(client, secbuf) < 0) { + ppp_error("Unable to obtain CHAP password for %s on %s from plugin", + client, server); + return 0; + } + } else { + filename = _PATH_CHAPFILE; + addrs = NULL; + secbuf[0] = 0; + + f = fopen(filename, "r"); + if (f == NULL) { + ppp_error("Can't open chap secret file %s: %m", filename); + return 0; + } + check_access(f, filename); + + ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename, 0); + fclose(f); + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != 0) + free_wordlist(opts); + if (addrs != 0) + free_wordlist(addrs); + } + + len = strlen(secbuf); + if (len > MAXSECRETLEN) { + ppp_error("Secret for %s on %s is too long", client, server); + len = MAXSECRETLEN; + } + MEMCPY(secret, secbuf, len); + BZERO(secbuf, sizeof(secbuf)); + *secret_len = len; + + return 1; +#endif /* UNUSED */ +} +#endif /* PPP_AUTH_SUPPORT */ + + +#if 0 /* UNUSED */ +/* + * get_srp_secret - open the SRP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int +get_srp_secret(unit, client, server, secret, am_server) + int unit; + char *client; + char *server; + char *secret; + int am_server; +{ + FILE *fp; + int ret; + char *filename; + struct wordlist *addrs, *opts; + + if (!am_server && ppp_settings.passwd[0] != '\0') { + strlcpy(secret, ppp_settings.passwd, MAXWORDLEN); + } else { + filename = _PATH_SRPFILE; + addrs = NULL; + + fp = fopen(filename, "r"); + if (fp == NULL) { + ppp_error("Can't open srp secret file %s: %m", filename); + return 0; + } + check_access(fp, filename); + + secret[0] = '\0'; + ret = scan_authfile(fp, client, server, secret, &addrs, &opts, + filename, am_server); + fclose(fp); + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != NULL) + free_wordlist(opts); + if (addrs != NULL) + free_wordlist(addrs); + } + + return 1; +} + +/* + * set_allowed_addrs() - set the list of allowed addresses. + * Also looks for `--' indicating options to apply for this peer + * and leaves the following words in extra_options. + */ +static void +set_allowed_addrs(unit, addrs, opts) + int unit; + struct wordlist *addrs; + struct wordlist *opts; +{ + int n; + struct wordlist *ap, **plink; + struct permitted_ip *ip; + char *ptr_word, *ptr_mask; + struct hostent *hp; + struct netent *np; + u32_t a, mask, ah, offset; + struct ipcp_options *wo = &ipcp_wantoptions[unit]; + u32_t suggested_ip = 0; + + if (addresses[unit] != NULL) + free(addresses[unit]); + addresses[unit] = NULL; + if (extra_options != NULL) + free_wordlist(extra_options); + extra_options = opts; + + /* + * Count the number of IP addresses given. + */ + n = wordlist_count(addrs) + wordlist_count(noauth_addrs); + if (n == 0) + return; + ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); + if (ip == 0) + return; + + /* temporarily append the noauth_addrs list to addrs */ + for (plink = &addrs; *plink != NULL; plink = &(*plink)->next) + ; + *plink = noauth_addrs; + + n = 0; + for (ap = addrs; ap != NULL; ap = ap->next) { + /* "-" means no addresses authorized, "*" means any address allowed */ + ptr_word = ap->word; + if (strcmp(ptr_word, "-") == 0) + break; + if (strcmp(ptr_word, "*") == 0) { + ip[n].permit = 1; + ip[n].base = ip[n].mask = 0; + ++n; + break; + } + + ip[n].permit = 1; + if (*ptr_word == '!') { + ip[n].permit = 0; + ++ptr_word; + } + + mask = ~ (u32_t) 0; + offset = 0; + ptr_mask = strchr (ptr_word, '/'); + if (ptr_mask != NULL) { + int bit_count; + char *endp; + + bit_count = (int) strtol (ptr_mask+1, &endp, 10); + if (bit_count <= 0 || bit_count > 32) { + ppp_warn("invalid address length %v in auth. address list", + ptr_mask+1); + continue; + } + bit_count = 32 - bit_count; /* # bits in host part */ + if (*endp == '+') { + offset = ifunit + 1; + ++endp; + } + if (*endp != 0) { + ppp_warn("invalid address length syntax: %v", ptr_mask+1); + continue; + } + *ptr_mask = '\0'; + mask <<= bit_count; + } + + hp = gethostbyname(ptr_word); + if (hp != NULL && hp->h_addrtype == AF_INET) { + a = *(u32_t *)hp->h_addr; + } else { + np = getnetbyname (ptr_word); + if (np != NULL && np->n_addrtype == AF_INET) { + a = lwip_htonl ((u32_t)np->n_net); + if (ptr_mask == NULL) { + /* calculate appropriate mask for net */ + ah = lwip_ntohl(a); + if (IN_CLASSA(ah)) + mask = IN_CLASSA_NET; + else if (IN_CLASSB(ah)) + mask = IN_CLASSB_NET; + else if (IN_CLASSC(ah)) + mask = IN_CLASSC_NET; + } + } else { + a = inet_addr (ptr_word); + } + } + + if (ptr_mask != NULL) + *ptr_mask = '/'; + + if (a == (u32_t)-1L) { + ppp_warn("unknown host %s in auth. address list", ap->word); + continue; + } + if (offset != 0) { + if (offset >= ~mask) { + ppp_warn("interface unit %d too large for subnet %v", + ifunit, ptr_word); + continue; + } + a = lwip_htonl((lwip_ntohl(a) & mask) + offset); + mask = ~(u32_t)0; + } + ip[n].mask = lwip_htonl(mask); + ip[n].base = a & ip[n].mask; + ++n; + if (~mask == 0 && suggested_ip == 0) + suggested_ip = a; + } + *plink = NULL; + + ip[n].permit = 0; /* make the last entry forbid all addresses */ + ip[n].base = 0; /* to terminate the list */ + ip[n].mask = 0; + + addresses[unit] = ip; + + /* + * If the address given for the peer isn't authorized, or if + * the user hasn't given one, AND there is an authorized address + * which is a single host, then use that if we find one. + */ + if (suggested_ip != 0 + && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) { + wo->hisaddr = suggested_ip; + /* + * Do we insist on this address? No, if there are other + * addresses authorized than the suggested one. + */ + if (n > 1) + wo->accept_remote = 1; + } +} + +/* + * auth_ip_addr - check whether the peer is authorized to use + * a given IP address. Returns 1 if authorized, 0 otherwise. + */ +int +auth_ip_addr(unit, addr) + int unit; + u32_t addr; +{ + int ok; + + /* don't allow loopback or multicast address */ + if (bad_ip_adrs(addr)) + return 0; + + if (allowed_address_hook) { + ok = allowed_address_hook(addr); + if (ok >= 0) return ok; + } + + if (addresses[unit] != NULL) { + ok = ip_addr_check(addr, addresses[unit]); + if (ok >= 0) + return ok; + } + + if (auth_required) + return 0; /* no addresses authorized */ + return allow_any_ip || privileged || !have_route_to(addr); +} + +static int +ip_addr_check(addr, addrs) + u32_t addr; + struct permitted_ip *addrs; +{ + for (; ; ++addrs) + if ((addr & addrs->mask) == addrs->base) + return addrs->permit; +} + +/* + * bad_ip_adrs - return 1 if the IP address is one we don't want + * to use, such as an address in the loopback net or a multicast address. + * addr is in network byte order. + */ +int +bad_ip_adrs(addr) + u32_t addr; +{ + addr = lwip_ntohl(addr); + return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET + || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + +/* + * some_ip_ok - check a wordlist to see if it authorizes any + * IP address(es). + */ +static int +some_ip_ok(addrs) + struct wordlist *addrs; +{ + for (; addrs != 0; addrs = addrs->next) { + if (addrs->word[0] == '-') + break; + if (addrs->word[0] != '!') + return 1; /* some IP address is allowed */ + } + return 0; +} + +/* + * auth_number - check whether the remote number is allowed to connect. + * Returns 1 if authorized, 0 otherwise. + */ +int +auth_number() +{ + struct wordlist *wp = permitted_numbers; + int l; + + /* Allow all if no authorization list. */ + if (!wp) + return 1; + + /* Allow if we have a match in the authorization list. */ + while (wp) { + /* trailing '*' wildcard */ + l = strlen(wp->word); + if ((wp->word)[l - 1] == '*') + l--; + if (!strncasecmp(wp->word, remote_number, l)) + return 1; + wp = wp->next; + } + + return 0; +} + +/* + * check_access - complain if a secret file has too-liberal permissions. + */ +static void +check_access(f, filename) + FILE *f; + char *filename; +{ + struct stat sbuf; + + if (fstat(fileno(f), &sbuf) < 0) { + ppp_warn("cannot stat secret file %s: %m", filename); + } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + ppp_warn("Warning - secret file %s has world and/or group access", + filename); + } +} + +/* + * scan_authfile - Scan an authorization file for a secret suitable + * for authenticating `client' on `server'. The return value is -1 + * if no secret is found, otherwise >= 0. The return value has + * NONWILD_CLIENT set if the secret didn't have "*" for the client, and + * NONWILD_SERVER set if the secret didn't have "*" for the server. + * Any following words on the line up to a "--" (i.e. address authorization + * info) are placed in a wordlist and returned in *addrs. Any + * following words (extra options) are placed in a wordlist and + * returned in *opts. + * We assume secret is NULL or points to MAXWORDLEN bytes of space. + * Flags are non-zero if we need two colons in the secret in order to + * match. + */ +static int +scan_authfile(f, client, server, secret, addrs, opts, filename, flags) + FILE *f; + char *client; + char *server; + char *secret; + struct wordlist **addrs; + struct wordlist **opts; + char *filename; + int flags; +{ + int newline, xxx; + int got_flag, best_flag; + FILE *sf; + struct wordlist *ap, *addr_list, *alist, **app; + char word[MAXWORDLEN]; + char atfile[MAXWORDLEN]; + char lsecret[MAXWORDLEN]; + char *cp; + + if (addrs != NULL) + *addrs = NULL; + if (opts != NULL) + *opts = NULL; + addr_list = NULL; + if (!getword(f, word, &newline, filename)) + return -1; /* file is empty??? */ + newline = 1; + best_flag = -1; + for (;;) { + /* + * Skip until we find a word at the start of a line. + */ + while (!newline && getword(f, word, &newline, filename)) + ; + if (!newline) + break; /* got to end of file */ + + /* + * Got a client - check if it's a match or a wildcard. + */ + got_flag = 0; + if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { + newline = 0; + continue; + } + if (!ISWILD(word)) + got_flag = NONWILD_CLIENT; + + /* + * Now get a server and check if it matches. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + if (!ISWILD(word)) { + if (server != NULL && strcmp(word, server) != 0) + continue; + got_flag |= NONWILD_SERVER; + } + + /* + * Got some sort of a match - see if it's better than what + * we have already. + */ + if (got_flag <= best_flag) + continue; + + /* + * Get the secret. + */ + if (!getword(f, word, &newline, filename)) + break; + if (newline) + continue; + + /* + * SRP-SHA1 authenticator should never be reading secrets from + * a file. (Authenticatee may, though.) + */ + if (flags && ((cp = strchr(word, ':')) == NULL || + strchr(cp + 1, ':') == NULL)) + continue; + + if (secret != NULL) { + /* + * Special syntax: @/pathname means read secret from file. + */ + if (word[0] == '@' && word[1] == '/') { + strlcpy(atfile, word+1, sizeof(atfile)); + if ((sf = fopen(atfile, "r")) == NULL) { + ppp_warn("can't open indirect secret file %s", atfile); + continue; + } + check_access(sf, atfile); + if (!getword(sf, word, &xxx, atfile)) { + ppp_warn("no secret in indirect secret file %s", atfile); + fclose(sf); + continue; + } + fclose(sf); + } + strlcpy(lsecret, word, sizeof(lsecret)); + } + + /* + * Now read address authorization info and make a wordlist. + */ + app = &alist; + for (;;) { + if (!getword(f, word, &newline, filename) || newline) + break; + ap = (struct wordlist *) + malloc(sizeof(struct wordlist) + strlen(word) + 1); + if (ap == NULL) + novm("authorized addresses"); + ap->word = (char *) (ap + 1); + strcpy(ap->word, word); + *app = ap; + app = &ap->next; + } + *app = NULL; + + /* + * This is the best so far; remember it. + */ + best_flag = got_flag; + if (addr_list) + free_wordlist(addr_list); + addr_list = alist; + if (secret != NULL) + strlcpy(secret, lsecret, MAXWORDLEN); + + if (!newline) + break; + } + + /* scan for a -- word indicating the start of options */ + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) + if (strcmp(ap->word, "--") == 0) + break; + /* ap = start of options */ + if (ap != NULL) { + ap = ap->next; /* first option */ + free(*app); /* free the "--" word */ + *app = NULL; /* terminate addr list */ + } + if (opts != NULL) + *opts = ap; + else if (ap != NULL) + free_wordlist(ap); + if (addrs != NULL) + *addrs = addr_list; + else if (addr_list != NULL) + free_wordlist(addr_list); + + return best_flag; +} + +/* + * wordlist_count - return the number of items in a wordlist + */ +static int +wordlist_count(wp) + struct wordlist *wp; +{ + int n; + + for (n = 0; wp != NULL; wp = wp->next) + ++n; + return n; +} + +/* + * free_wordlist - release memory allocated for a wordlist. + */ +static void +free_wordlist(wp) + struct wordlist *wp; +{ + struct wordlist *next; + + while (wp != NULL) { + next = wp->next; + free(wp); + wp = next; + } +} +#endif /* UNUSED */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ccp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ccp.c new file mode 100644 index 0000000000..f8519ebece --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ccp.c @@ -0,0 +1,1740 @@ +/* + * ccp.c - PPP Compression Control Protocol. + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ccp.h" + +#if MPPE_SUPPORT +#include "netif/ppp/lcp.h" /* lcp_close(), lcp_fsm */ +#include "netif/ppp/mppe.h" /* mppe_init() */ +#endif /* MPPE_SUPPORT */ + +/* + * Unfortunately there is a bug in zlib which means that using a + * size of 8 (window size = 256) for Deflate compression will cause + * buffer overruns and kernel crashes in the deflate module. + * Until this is fixed we only accept sizes in the range 9 .. 15. + * Thanks to James Carlson for pointing this out. + */ +#define DEFLATE_MIN_WORKS 9 + +/* + * Command-line options. + */ +#if PPP_OPTIONS +static int setbsdcomp (char **); +static int setdeflate (char **); +static char bsd_value[8]; +static char deflate_value[8]; + +/* + * Option variables. + */ +#if MPPE_SUPPORT +bool refuse_mppe_stateful = 1; /* Allow stateful mode? */ +#endif /* MPPE_SUPPORT */ + +static option_t ccp_option_list[] = { + { "noccp", o_bool, &ccp_protent.enabled_flag, + "Disable CCP negotiation" }, + { "-ccp", o_bool, &ccp_protent.enabled_flag, + "Disable CCP negotiation", OPT_ALIAS }, + + { "bsdcomp", o_special, (void *)setbsdcomp, + "Request BSD-Compress packet compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, + { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, + "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].bsd_compress }, + { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, + "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].bsd_compress }, + + { "deflate", o_special, (void *)setdeflate, + "request Deflate compression", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, + { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, + "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].deflate }, + { "-deflate", o_bool, &ccp_wantoptions[0].deflate, + "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].deflate }, + + { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, + "don't use draft deflate #", OPT_A2COPY, + &ccp_allowoptions[0].deflate_draft }, + + { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "request Predictor-1", OPT_PRIO | 1 }, + { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].predictor_1 }, + { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, + "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, + &ccp_allowoptions[0].predictor_1 }, + +#if MPPE_SUPPORT + /* MPPE options are symmetrical ... we only set wantoptions here */ + { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "+mppe", o_bool, &ccp_wantoptions[0].mppe, + "require MPPE encryption", + OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, + { "nomppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_PRIO }, + { "-mppe", o_bool, &ccp_wantoptions[0].mppe, + "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, + + /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ + { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, + { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 40-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, + &ccp_wantoptions[0].mppe }, + + { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "require MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, + { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, + "don't allow MPPE 128-bit encryption", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, + &ccp_wantoptions[0].mppe }, + + /* strange one; we always request stateless, but will we allow stateful? */ + { "mppe-stateful", o_bool, &refuse_mppe_stateful, + "allow MPPE stateful mode", OPT_PRIO }, + { "nomppe-stateful", o_bool, &refuse_mppe_stateful, + "disallow MPPE stateful mode", OPT_PRIO | 1 }, +#endif /* MPPE_SUPPORT */ + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ccp_init(ppp_pcb *pcb); +static void ccp_open(ppp_pcb *pcb); +static void ccp_close(ppp_pcb *pcb, const char *reason); +static void ccp_lowerup(ppp_pcb *pcb); +static void ccp_lowerdown(ppp_pcb *pcb); +static void ccp_input(ppp_pcb *pcb, u_char *pkt, int len); +static void ccp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT +static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len); +#endif /* PPP_DATAINPUT */ + +const struct protent ccp_protent = { + PPP_CCP, + ccp_init, + ccp_input, + ccp_protrej, + ccp_lowerup, + ccp_lowerdown, + ccp_open, + ccp_close, +#if PRINTPKT_SUPPORT + ccp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + ccp_datainput, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "CCP", + "Compressed", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ccp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +/* + * Callbacks for fsm code. + */ +static void ccp_resetci (fsm *); +static int ccp_cilen (fsm *); +static void ccp_addci (fsm *, u_char *, int *); +static int ccp_ackci (fsm *, u_char *, int); +static int ccp_nakci (fsm *, u_char *, int, int); +static int ccp_rejci (fsm *, u_char *, int); +static int ccp_reqci (fsm *, u_char *, int *, int); +static void ccp_up (fsm *); +static void ccp_down (fsm *); +static int ccp_extcode (fsm *, int, int, u_char *, int); +static void ccp_rack_timeout (void *); +static const char *method_name (ccp_options *, ccp_options *); + +static const fsm_callbacks ccp_callbacks = { + ccp_resetci, + ccp_cilen, + ccp_addci, + ccp_ackci, + ccp_nakci, + ccp_rejci, + ccp_reqci, + ccp_up, + ccp_down, + NULL, + NULL, + NULL, + NULL, + ccp_extcode, + "CCP" +}; + +/* + * Do we want / did we get any compression? + */ +static int ccp_anycompress(ccp_options *opt) { + return (0 +#if DEFLATE_SUPPORT + || (opt)->deflate +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + || (opt)->bsd_compress +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + || (opt)->predictor_1 || (opt)->predictor_2 +#endif /* PREDICTOR_SUPPORT */ +#if MPPE_SUPPORT + || (opt)->mppe +#endif /* MPPE_SUPPORT */ + ); +} + +/* + * Local state (mainly for handling reset-reqs and reset-acks). + */ +#define RACK_PENDING 1 /* waiting for reset-ack */ +#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ + +#define RACKTIMEOUT 1 /* second */ + +#if PPP_OPTIONS +/* + * Option parsing + */ +static int +setbsdcomp(argv) + char **argv; +{ + int rbits, abits; + char *str, *endp; + + str = *argv; + abits = rbits = strtol(str, &endp, 0); + if (endp != str && *endp == ',') { + str = endp + 1; + abits = strtol(str, &endp, 0); + } + if (*endp != 0 || endp == str) { + option_error("invalid parameter '%s' for bsdcomp option", *argv); + return 0; + } + if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) + || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { + option_error("bsdcomp option values must be 0 or %d .. %d", + BSD_MIN_BITS, BSD_MAX_BITS); + return 0; + } + if (rbits > 0) { + ccp_wantoptions[0].bsd_compress = 1; + ccp_wantoptions[0].bsd_bits = rbits; + } else + ccp_wantoptions[0].bsd_compress = 0; + if (abits > 0) { + ccp_allowoptions[0].bsd_compress = 1; + ccp_allowoptions[0].bsd_bits = abits; + } else + ccp_allowoptions[0].bsd_compress = 0; + ppp_slprintf(bsd_value, sizeof(bsd_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + + return 1; +} + +static int +setdeflate(argv) + char **argv; +{ + int rbits, abits; + char *str, *endp; + + str = *argv; + abits = rbits = strtol(str, &endp, 0); + if (endp != str && *endp == ',') { + str = endp + 1; + abits = strtol(str, &endp, 0); + } + if (*endp != 0 || endp == str) { + option_error("invalid parameter '%s' for deflate option", *argv); + return 0; + } + if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)) + || (abits != 0 && (abits < DEFLATE_MIN_SIZE + || abits > DEFLATE_MAX_SIZE))) { + option_error("deflate option values must be 0 or %d .. %d", + DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); + return 0; + } + if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { + if (rbits == DEFLATE_MIN_SIZE) + rbits = DEFLATE_MIN_WORKS; + if (abits == DEFLATE_MIN_SIZE) + abits = DEFLATE_MIN_WORKS; + warn("deflate option value of %d changed to %d to avoid zlib bug", + DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); + } + if (rbits > 0) { + ccp_wantoptions[0].deflate = 1; + ccp_wantoptions[0].deflate_size = rbits; + } else + ccp_wantoptions[0].deflate = 0; + if (abits > 0) { + ccp_allowoptions[0].deflate = 1; + ccp_allowoptions[0].deflate_size = abits; + } else + ccp_allowoptions[0].deflate = 0; + ppp_slprintf(deflate_value, sizeof(deflate_value), + rbits == abits? "%d": "%d,%d", rbits, abits); + + return 1; +} +#endif /* PPP_OPTIONS */ + +/* + * ccp_init - initialize CCP. + */ +static void ccp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + + f->pcb = pcb; + f->protocol = PPP_CCP; + f->callbacks = &ccp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(go, 0, sizeof(*go)); + memset(ao, 0, sizeof(*ao)); + memset(ho, 0, sizeof(*ho)); +#endif /* 0 */ + +#if DEFLATE_SUPPORT + wo->deflate = 1; + wo->deflate_size = DEFLATE_MAX_SIZE; + wo->deflate_correct = 1; + wo->deflate_draft = 1; + ao->deflate = 1; + ao->deflate_size = DEFLATE_MAX_SIZE; + ao->deflate_correct = 1; + ao->deflate_draft = 1; +#endif /* DEFLATE_SUPPORT */ + +#if BSDCOMPRESS_SUPPORT + wo->bsd_compress = 1; + wo->bsd_bits = BSD_MAX_BITS; + ao->bsd_compress = 1; + ao->bsd_bits = BSD_MAX_BITS; +#endif /* BSDCOMPRESS_SUPPORT */ + +#if PREDICTOR_SUPPORT + ao->predictor_1 = 1; +#endif /* PREDICTOR_SUPPORT */ +} + +/* + * ccp_open - CCP is allowed to come up. + */ +static void ccp_open(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + ccp_options *go = &pcb->ccp_gotoptions; + + if (f->state != PPP_FSM_OPENED) + ccp_set(pcb, 1, 0, 0, 0); + + /* + * Find out which compressors the kernel supports before + * deciding whether to open in silent mode. + */ + ccp_resetci(f); + if (!ccp_anycompress(go)) + f->flags |= OPT_SILENT; + + fsm_open(f); +} + +/* + * ccp_close - Terminate CCP. + */ +static void ccp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->ccp_fsm; + ccp_set(pcb, 0, 0, 0, 0); + fsm_close(f, reason); +} + +/* + * ccp_lowerup - we may now transmit CCP packets. + */ +static void ccp_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + fsm_lowerup(f); +} + +/* + * ccp_lowerdown - we may not transmit CCP packets. + */ +static void ccp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + fsm_lowerdown(f); +} + +/* + * ccp_input - process a received CCP packet. + */ +static void ccp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->ccp_fsm; + ccp_options *go = &pcb->ccp_gotoptions; + int oldstate; + + /* + * Check for a terminate-request so we can print a message. + */ + oldstate = f->state; + fsm_input(f, p, len); + if (oldstate == PPP_FSM_OPENED && p[0] == TERMREQ && f->state != PPP_FSM_OPENED) { + ppp_notice("Compression disabled by peer."); +#if MPPE_SUPPORT + if (go->mppe) { + ppp_error("MPPE disabled, closing LCP"); + lcp_close(pcb, "MPPE disabled by peer"); + } +#endif /* MPPE_SUPPORT */ + } + + /* + * If we get a terminate-ack and we're not asking for compression, + * close CCP. + */ + if (oldstate == PPP_FSM_REQSENT && p[0] == TERMACK + && !ccp_anycompress(go)) + ccp_close(pcb, "No compression negotiated"); +} + +/* + * Handle a CCP-specific code. + */ +static int ccp_extcode(fsm *f, int code, int id, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(len); + + switch (code) { + case CCP_RESETREQ: + if (f->state != PPP_FSM_OPENED) + break; + ccp_reset_comp(pcb); + /* send a reset-ack, which the transmitter will see and + reset its compression state. */ + fsm_sdata(f, CCP_RESETACK, id, NULL, 0); + break; + + case CCP_RESETACK: + if ((pcb->ccp_localstate & RACK_PENDING) && id == f->reqid) { + pcb->ccp_localstate &= ~(RACK_PENDING | RREQ_REPEAT); + UNTIMEOUT(ccp_rack_timeout, f); + ccp_reset_decomp(pcb); + } + break; + + default: + return 0; + } + + return 1; +} + +/* + * ccp_protrej - peer doesn't talk CCP. + */ +static void ccp_protrej(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + + ccp_set(pcb, 0, 0, 0, 0); + fsm_lowerdown(f); + +#if MPPE_SUPPORT + if (go->mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } +#endif /* MPPE_SUPPORT */ + +} + +/* + * ccp_resetci - initialize at start of negotiation. + */ +static void ccp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options *wo = &pcb->ccp_wantoptions; +#if MPPE_SUPPORT + ccp_options *ao = &pcb->ccp_allowoptions; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT + u_char opt_buf[CCP_MAX_OPTION_LENGTH]; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT + int res; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ + +#if MPPE_SUPPORT + if (pcb->settings.require_mppe) { + wo->mppe = ao->mppe = + (pcb->settings.refuse_mppe_40 ? 0 : MPPE_OPT_40) + | (pcb->settings.refuse_mppe_128 ? 0 : MPPE_OPT_128); + } +#endif /* MPPE_SUPPORT */ + + *go = *wo; + pcb->ccp_all_rejected = 0; + +#if MPPE_SUPPORT + if (go->mppe) { + int auth_mschap_bits = pcb->auth_done; + int numbits; + + /* + * Start with a basic sanity check: mschap[v2] auth must be in + * exactly one direction. RFC 3079 says that the keys are + * 'derived from the credentials of the peer that initiated the call', + * however the PPP protocol doesn't have such a concept, and pppd + * cannot get this info externally. Instead we do the best we can. + * NB: If MPPE is required, all other compression opts are invalid. + * So, we return right away if we can't do it. + */ + + /* Leave only the mschap auth bits set */ + auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | + CHAP_MS2_WITHPEER | CHAP_MS2_PEER); + /* Count the mschap auths */ + auth_mschap_bits >>= CHAP_MS_SHIFT; + numbits = 0; + do { + numbits += auth_mschap_bits & 1; + auth_mschap_bits >>= 1; + } while (auth_mschap_bits); + if (numbits > 1) { + ppp_error("MPPE required, but auth done in both directions."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + if (!numbits) { + ppp_error("MPPE required, but MS-CHAP[v2] auth not performed."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* A plugin (eg radius) may not have obtained key material. */ + if (!pcb->mppe_keys_set) { + ppp_error("MPPE required, but keys are not available. " + "Possible plugin problem?"); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* LM auth not supported for MPPE */ + if (pcb->auth_done & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { + /* This might be noise */ + if (go->mppe & MPPE_OPT_40) { + ppp_notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); + go->mppe &= ~MPPE_OPT_40; + wo->mppe &= ~MPPE_OPT_40; + } + } + + /* Last check: can we actually negotiate something? */ + if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { + /* Could be misconfig, could be 40-bit disabled above. */ + ppp_error("MPPE required, but both 40-bit and 128-bit disabled."); + lcp_close(pcb, "MPPE required but not available"); + return; + } + + /* sync options */ + ao->mppe = go->mppe; + /* MPPE is not compatible with other compression types */ +#if BSDCOMPRESS_SUPPORT + ao->bsd_compress = go->bsd_compress = 0; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + ao->predictor_1 = go->predictor_1 = 0; + ao->predictor_2 = go->predictor_2 = 0; +#endif /* PREDICTOR_SUPPORT */ +#if DEFLATE_SUPPORT + ao->deflate = go->deflate = 0; +#endif /* DEFLATE_SUPPORT */ + } +#endif /* MPPE_SUPPORT */ + + /* + * Check whether the kernel knows about the various + * compression methods we might request. + */ +#if BSDCOMPRESS_SUPPORT + /* FIXME: we don't need to test if BSD compress is available + * if BSDCOMPRESS_SUPPORT is set, it is. + */ + if (go->bsd_compress) { + opt_buf[0] = CI_BSD_COMPRESS; + opt_buf[1] = CILEN_BSD_COMPRESS; + for (;;) { + if (go->bsd_bits < BSD_MIN_BITS) { + go->bsd_compress = 0; + break; + } + opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + res = ccp_test(pcb, opt_buf, CILEN_BSD_COMPRESS, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->bsd_compress = 0; + break; + } + go->bsd_bits--; + } + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + /* FIXME: we don't need to test if deflate is available + * if DEFLATE_SUPPORT is set, it is. + */ + if (go->deflate) { + if (go->deflate_correct) { + opt_buf[0] = CI_DEFLATE; + opt_buf[1] = CILEN_DEFLATE; + opt_buf[3] = DEFLATE_CHK_SEQUENCE; + for (;;) { + if (go->deflate_size < DEFLATE_MIN_WORKS) { + go->deflate_correct = 0; + break; + } + opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); + res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->deflate_correct = 0; + break; + } + go->deflate_size--; + } + } + if (go->deflate_draft) { + opt_buf[0] = CI_DEFLATE_DRAFT; + opt_buf[1] = CILEN_DEFLATE; + opt_buf[3] = DEFLATE_CHK_SEQUENCE; + for (;;) { + if (go->deflate_size < DEFLATE_MIN_WORKS) { + go->deflate_draft = 0; + break; + } + opt_buf[2] = DEFLATE_MAKE_OPT(go->deflate_size); + res = ccp_test(pcb, opt_buf, CILEN_DEFLATE, 0); + if (res > 0) { + break; + } else if (res < 0) { + go->deflate_draft = 0; + break; + } + go->deflate_size--; + } + } + if (!go->deflate_correct && !go->deflate_draft) + go->deflate = 0; + } +#endif /* DEFLATE_SUPPORT */ +#if PREDICTOR_SUPPORT + /* FIXME: we don't need to test if predictor is available, + * if PREDICTOR_SUPPORT is set, it is. + */ + if (go->predictor_1) { + opt_buf[0] = CI_PREDICTOR_1; + opt_buf[1] = CILEN_PREDICTOR_1; + if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_1, 0) <= 0) + go->predictor_1 = 0; + } + if (go->predictor_2) { + opt_buf[0] = CI_PREDICTOR_2; + opt_buf[1] = CILEN_PREDICTOR_2; + if (ccp_test(pcb, opt_buf, CILEN_PREDICTOR_2, 0) <= 0) + go->predictor_2 = 0; + } +#endif /* PREDICTOR_SUPPORT */ +} + +/* + * ccp_cilen - Return total length of our configuration info. + */ +static int ccp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + + return 0 +#if BSDCOMPRESS_SUPPORT + + (go->bsd_compress? CILEN_BSD_COMPRESS: 0) +#endif /* BSDCOMPRESS_SUPPORT */ +#if DEFLATE_SUPPORT + + (go->deflate && go->deflate_correct? CILEN_DEFLATE: 0) + + (go->deflate && go->deflate_draft? CILEN_DEFLATE: 0) +#endif /* DEFLATE_SUPPORT */ +#if PREDICTOR_SUPPORT + + (go->predictor_1? CILEN_PREDICTOR_1: 0) + + (go->predictor_2? CILEN_PREDICTOR_2: 0) +#endif /* PREDICTOR_SUPPORT */ +#if MPPE_SUPPORT + + (go->mppe? CILEN_MPPE: 0) +#endif /* MPPE_SUPPORT */ + ; +} + +/* + * ccp_addci - put our requests in a packet. + */ +static void ccp_addci(fsm *f, u_char *p, int *lenp) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + u_char *p0 = p; + + /* + * Add the compression types that we can receive, in decreasing + * preference order. + */ +#if MPPE_SUPPORT + if (go->mppe) { + p[0] = CI_MPPE; + p[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &p[2]); + mppe_init(pcb, &pcb->mppe_decomp, go->mppe); + p += CILEN_MPPE; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate) { + if (go->deflate_correct) { + p[0] = CI_DEFLATE; + p[1] = CILEN_DEFLATE; + p[2] = DEFLATE_MAKE_OPT(go->deflate_size); + p[3] = DEFLATE_CHK_SEQUENCE; + p += CILEN_DEFLATE; + } + if (go->deflate_draft) { + p[0] = CI_DEFLATE_DRAFT; + p[1] = CILEN_DEFLATE; + p[2] = p[2 - CILEN_DEFLATE]; + p[3] = DEFLATE_CHK_SEQUENCE; + p += CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress) { + p[0] = CI_BSD_COMPRESS; + p[1] = CILEN_BSD_COMPRESS; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); + p += CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + /* XXX Should Predictor 2 be preferable to Predictor 1? */ + if (go->predictor_1) { + p[0] = CI_PREDICTOR_1; + p[1] = CILEN_PREDICTOR_1; + p += CILEN_PREDICTOR_1; + } + if (go->predictor_2) { + p[0] = CI_PREDICTOR_2; + p[1] = CILEN_PREDICTOR_2; + p += CILEN_PREDICTOR_2; + } +#endif /* PREDICTOR_SUPPORT */ + + go->method = (p > p0)? p0[0]: 0; + + *lenp = p - p0; +} + +/* + * ccp_ackci - process a received configure-ack, and return + * 1 iff the packet was OK. + */ +static int ccp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; +#if BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT + u_char *p0 = p; +#endif /* BSDCOMPRESS_SUPPORT || PREDICTOR_SUPPORT */ + +#if MPPE_SUPPORT + if (go->mppe) { + u_char opt_buf[CILEN_MPPE]; + + opt_buf[0] = CI_MPPE; + opt_buf[1] = CILEN_MPPE; + MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); + if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE)) + return 0; + p += CILEN_MPPE; + len -= CILEN_MPPE; + /* XXX Cope with first/fast ack */ + if (len == 0) + return 1; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate) { + if (len < CILEN_DEFLATE + || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) + || p[1] != CILEN_DEFLATE + || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + /* XXX Cope with first/fast ack */ + if (len == 0) + return 1; + if (go->deflate_correct && go->deflate_draft) { + if (len < CILEN_DEFLATE + || p[0] != CI_DEFLATE_DRAFT + || p[1] != CILEN_DEFLATE + || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress) { + if (len < CILEN_BSD_COMPRESS + || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS + || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) + return 0; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + if (go->predictor_1) { + if (len < CILEN_PREDICTOR_1 + || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1) + return 0; + p += CILEN_PREDICTOR_1; + len -= CILEN_PREDICTOR_1; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } + if (go->predictor_2) { + if (len < CILEN_PREDICTOR_2 + || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2) + return 0; + p += CILEN_PREDICTOR_2; + len -= CILEN_PREDICTOR_2; + /* XXX Cope with first/fast ack */ + if (p == p0 && len == 0) + return 1; + } +#endif /* PREDICTOR_SUPPORT */ + + if (len != 0) + return 0; + return 1; +} + +/* + * ccp_nakci - process received configure-nak. + * Returns 1 iff the nak was OK. + */ +static int ccp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options no; /* options we've seen already */ + ccp_options try_; /* options to ask for next time */ + LWIP_UNUSED_ARG(treat_as_reject); +#if !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(len); +#endif /* !MPPE_SUPPORT && !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ + + memset(&no, 0, sizeof(no)); + try_ = *go; + +#if MPPE_SUPPORT + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + no.mppe = 1; + /* + * Peer wants us to use a different strength or other setting. + * Fail if we aren't willing to use his suggestion. + */ + MPPE_CI_TO_OPTS(&p[2], try_.mppe); + if ((try_.mppe & MPPE_OPT_STATEFUL) && pcb->settings.refuse_mppe_stateful) { + ppp_error("Refusing MPPE stateful mode offered by peer"); + try_.mppe = 0; + } else if (((go->mppe | MPPE_OPT_STATEFUL) & try_.mppe) != try_.mppe) { + /* Peer must have set options we didn't request (suggest) */ + try_.mppe = 0; + } + + if (!try_.mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate && len >= CILEN_DEFLATE + && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) + && p[1] == CILEN_DEFLATE) { + no.deflate = 1; + /* + * Peer wants us to use a different code size or something. + * Stop asking for Deflate if we don't understand his suggestion. + */ + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL + || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS + || p[3] != DEFLATE_CHK_SEQUENCE) + try_.deflate = 0; + else if (DEFLATE_SIZE(p[2]) < go->deflate_size) + try_.deflate_size = DEFLATE_SIZE(p[2]); + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + if (go->deflate_correct && go->deflate_draft + && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT + && p[1] == CILEN_DEFLATE) { + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + } +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { + no.bsd_compress = 1; + /* + * Peer wants us to use a different number of bits + * or a different version. + */ + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) + try_.bsd_compress = 0; + else if (BSD_NBITS(p[2]) < go->bsd_bits) + try_.bsd_bits = BSD_NBITS(p[2]); + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ + + /* + * Predictor-1 and 2 have no options, so they can't be Naked. + * + * There may be remaining options but we ignore them. + */ + + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; +} + +/* + * ccp_rejci - reject some of our suggested compression methods. + */ +static int ccp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options try_; /* options to request next time */ + + try_ = *go; + + /* + * Cope with empty configure-rejects by ceasing to send + * configure-requests. + */ + if (len == 0 && pcb->ccp_all_rejected) + return -1; + +#if MPPE_SUPPORT + if (go->mppe && len >= CILEN_MPPE + && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { + ppp_error("MPPE required but peer refused"); + lcp_close(pcb, "MPPE required but peer refused"); + p += CILEN_MPPE; + len -= CILEN_MPPE; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + if (go->deflate_correct && len >= CILEN_DEFLATE + && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) { + if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; /* Rej is bad */ + try_.deflate_correct = 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + if (go->deflate_draft && len >= CILEN_DEFLATE + && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) { + if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) + || p[3] != DEFLATE_CHK_SEQUENCE) + return 0; /* Rej is bad */ + try_.deflate_draft = 0; + p += CILEN_DEFLATE; + len -= CILEN_DEFLATE; + } + if (!try_.deflate_correct && !try_.deflate_draft) + try_.deflate = 0; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + if (go->bsd_compress && len >= CILEN_BSD_COMPRESS + && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { + if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) + return 0; + try_.bsd_compress = 0; + p += CILEN_BSD_COMPRESS; + len -= CILEN_BSD_COMPRESS; + } +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + if (go->predictor_1 && len >= CILEN_PREDICTOR_1 + && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) { + try_.predictor_1 = 0; + p += CILEN_PREDICTOR_1; + len -= CILEN_PREDICTOR_1; + } + if (go->predictor_2 && len >= CILEN_PREDICTOR_2 + && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) { + try_.predictor_2 = 0; + p += CILEN_PREDICTOR_2; + len -= CILEN_PREDICTOR_2; + } +#endif /* PREDICTOR_SUPPORT */ + + if (len != 0) + return 0; + + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; +} + +/* + * ccp_reqci - processed a received configure-request. + * Returns CONFACK, CONFNAK or CONFREJ and the packet modified + * appropriately. + */ +static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) { + ppp_pcb *pcb = f->pcb; + ccp_options *ho = &pcb->ccp_hisoptions; + ccp_options *ao = &pcb->ccp_allowoptions; + int ret, newret; +#if DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT + int res; + int nb; +#endif /* DEFLATE_SUPPORT || BSDCOMPRESS_SUPPORT */ + u_char *p0, *retp; + int len, clen, type; +#if MPPE_SUPPORT + u8_t rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */ + /* CI_MPPE, or due to other options? */ +#endif /* MPPE_SUPPORT */ + + ret = CONFACK; + retp = p0 = p; + len = *lenp; + + memset(ho, 0, sizeof(ccp_options)); + ho->method = (len > 0)? p[0]: 0; + + while (len > 0) { + newret = CONFACK; + if (len < 2 || p[1] < 2 || p[1] > len) { + /* length is bad */ + clen = len; + newret = CONFREJ; + + } else { + type = p[0]; + clen = p[1]; + + switch (type) { +#if MPPE_SUPPORT + case CI_MPPE: + if (!ao->mppe || clen != CILEN_MPPE) { + newret = CONFREJ; + break; + } + MPPE_CI_TO_OPTS(&p[2], ho->mppe); + + /* Nak if anything unsupported or unknown are set. */ + if (ho->mppe & MPPE_OPT_UNSUPPORTED) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNSUPPORTED; + } + if (ho->mppe & MPPE_OPT_UNKNOWN) { + newret = CONFNAK; + ho->mppe &= ~MPPE_OPT_UNKNOWN; + } + + /* Check state opt */ + if (ho->mppe & MPPE_OPT_STATEFUL) { + /* + * We can Nak and request stateless, but it's a + * lot easier to just assume the peer will request + * it if he can do it; stateful mode is bad over + * the Internet -- which is where we expect MPPE. + */ + if (pcb->settings.refuse_mppe_stateful) { + ppp_error("Refusing MPPE stateful mode offered by peer"); + newret = CONFREJ; + break; + } + } + + /* Find out which of {S,L} are set. */ + if ((ho->mppe & MPPE_OPT_128) + && (ho->mppe & MPPE_OPT_40)) { + /* Both are set, negotiate the strongest. */ + newret = CONFNAK; + if (ao->mppe & MPPE_OPT_128) + ho->mppe &= ~MPPE_OPT_40; + else if (ao->mppe & MPPE_OPT_40) + ho->mppe &= ~MPPE_OPT_128; + else { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_128) { + if (!(ao->mppe & MPPE_OPT_128)) { + newret = CONFREJ; + break; + } + } else if (ho->mppe & MPPE_OPT_40) { + if (!(ao->mppe & MPPE_OPT_40)) { + newret = CONFREJ; + break; + } + } else { + /* Neither are set. */ + /* We cannot accept this. */ + newret = CONFNAK; + /* Give the peer our idea of what can be used, + so it can choose and confirm */ + ho->mppe = ao->mppe; + } + + /* rebuild the opts */ + MPPE_OPTS_TO_CI(ho->mppe, &p[2]); + if (newret == CONFACK) { + int mtu; + + mppe_init(pcb, &pcb->mppe_comp, ho->mppe); + /* + * We need to decrease the interface MTU by MPPE_PAD + * because MPPE frames **grow**. The kernel [must] + * allocate MPPE_PAD extra bytes in xmit buffers. + */ + mtu = netif_get_mtu(pcb); + if (mtu) + netif_set_mtu(pcb, mtu - MPPE_PAD); + else + newret = CONFREJ; + } + + /* + * We have accepted MPPE or are willing to negotiate + * MPPE parameters. A CONFREJ is due to subsequent + * (non-MPPE) processing. + */ + rej_for_ci_mppe = 0; + break; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (!ao->deflate || clen != CILEN_DEFLATE + || (!ao->deflate_correct && type == CI_DEFLATE) + || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) { + newret = CONFREJ; + break; + } + + ho->deflate = 1; + ho->deflate_size = nb = DEFLATE_SIZE(p[2]); + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL + || p[3] != DEFLATE_CHK_SEQUENCE + || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) { + newret = CONFNAK; + if (!dont_nak) { + p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); + p[3] = DEFLATE_CHK_SEQUENCE; + /* fall through to test this #bits below */ + } else + break; + } + + /* + * Check whether we can do Deflate with the window + * size they want. If the window is too big, reduce + * it until the kernel can cope and nak with that. + * We only check this for the first option. + */ + if (p == p0) { + for (;;) { + res = ccp_test(pcb, p, CILEN_DEFLATE, 1); + if (res > 0) + break; /* it's OK now */ + if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) { + newret = CONFREJ; + p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); + break; + } + newret = CONFNAK; + --nb; + p[2] = DEFLATE_MAKE_OPT(nb); + } + } + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { + newret = CONFREJ; + break; + } + + ho->bsd_compress = 1; + ho->bsd_bits = nb = BSD_NBITS(p[2]); + if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION + || nb > ao->bsd_bits || nb < BSD_MIN_BITS) { + newret = CONFNAK; + if (!dont_nak) { + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits); + /* fall through to test this #bits below */ + } else + break; + } + + /* + * Check whether we can do BSD-Compress with the code + * size they want. If the code size is too big, reduce + * it until the kernel can cope and nak with that. + * We only check this for the first option. + */ + if (p == p0) { + for (;;) { + res = ccp_test(pcb, p, CILEN_BSD_COMPRESS, 1); + if (res > 0) + break; + if (res < 0 || nb == BSD_MIN_BITS || dont_nak) { + newret = CONFREJ; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, + ho->bsd_bits); + break; + } + newret = CONFNAK; + --nb; + p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); + } + } + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) { + newret = CONFREJ; + break; + } + + ho->predictor_1 = 1; + if (p == p0 + && ccp_test(pcb, p, CILEN_PREDICTOR_1, 1) <= 0) { + newret = CONFREJ; + } + break; + + case CI_PREDICTOR_2: + if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) { + newret = CONFREJ; + break; + } + + ho->predictor_2 = 1; + if (p == p0 + && ccp_test(pcb, p, CILEN_PREDICTOR_2, 1) <= 0) { + newret = CONFREJ; + } + break; +#endif /* PREDICTOR_SUPPORT */ + + default: + newret = CONFREJ; + } + } + + if (newret == CONFNAK && dont_nak) + newret = CONFREJ; + if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) { + /* we're returning this option */ + if (newret == CONFREJ && ret == CONFNAK) + retp = p0; + ret = newret; + if (p != retp) + MEMCPY(retp, p, clen); + retp += clen; + } + + p += clen; + len -= clen; + } + + if (ret != CONFACK) { + if (ret == CONFREJ && *lenp == retp - p0) + pcb->ccp_all_rejected = 1; + else + *lenp = retp - p0; + } +#if MPPE_SUPPORT + if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) { + ppp_error("MPPE required but peer negotiation failed"); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + } +#endif /* MPPE_SUPPORT */ + return ret; +} + +/* + * Make a string name for a compression method (or 2). + */ +static const char *method_name(ccp_options *opt, ccp_options *opt2) { + static char result[64]; +#if !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT + LWIP_UNUSED_ARG(opt2); +#endif /* !DEFLATE_SUPPORT && !BSDCOMPRESS_SUPPORT */ + + if (!ccp_anycompress(opt)) + return "(none)"; + switch (opt->method) { +#if MPPE_SUPPORT + case CI_MPPE: + { + char *p = result; + char *q = result + sizeof(result); /* 1 past result */ + + ppp_slprintf(p, q - p, "MPPE "); + p += 5; + if (opt->mppe & MPPE_OPT_128) { + ppp_slprintf(p, q - p, "128-bit "); + p += 8; + } + if (opt->mppe & MPPE_OPT_40) { + ppp_slprintf(p, q - p, "40-bit "); + p += 7; + } + if (opt->mppe & MPPE_OPT_STATEFUL) + ppp_slprintf(p, q - p, "stateful"); + else + ppp_slprintf(p, q - p, "stateless"); + + break; + } +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) + ppp_slprintf(result, sizeof(result), "Deflate%s (%d/%d)", + (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), + opt->deflate_size, opt2->deflate_size); + else + ppp_slprintf(result, sizeof(result), "Deflate%s (%d)", + (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), + opt->deflate_size); + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits) + ppp_slprintf(result, sizeof(result), "BSD-Compress (%d/%d)", + opt->bsd_bits, opt2->bsd_bits); + else + ppp_slprintf(result, sizeof(result), "BSD-Compress (%d)", + opt->bsd_bits); + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + return "Predictor 1"; + case CI_PREDICTOR_2: + return "Predictor 2"; +#endif /* PREDICTOR_SUPPORT */ + default: + ppp_slprintf(result, sizeof(result), "Method %d", opt->method); + } + return result; +} + +/* + * CCP has come up - inform the kernel driver and log a message. + */ +static void ccp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + ccp_options *go = &pcb->ccp_gotoptions; + ccp_options *ho = &pcb->ccp_hisoptions; + char method1[64]; + + ccp_set(pcb, 1, 1, go->method, ho->method); + if (ccp_anycompress(go)) { + if (ccp_anycompress(ho)) { + if (go->method == ho->method) { + ppp_notice("%s compression enabled", method_name(go, ho)); + } else { + ppp_strlcpy(method1, method_name(go, NULL), sizeof(method1)); + ppp_notice("%s / %s compression enabled", + method1, method_name(ho, NULL)); + } + } else + ppp_notice("%s receive compression enabled", method_name(go, NULL)); + } else if (ccp_anycompress(ho)) + ppp_notice("%s transmit compression enabled", method_name(ho, NULL)); +#if MPPE_SUPPORT + if (go->mppe) { + continue_networks(pcb); /* Bring up IP et al */ + } +#endif /* MPPE_SUPPORT */ +} + +/* + * CCP has gone down - inform the kernel driver. + */ +static void ccp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + + if (pcb->ccp_localstate & RACK_PENDING) + UNTIMEOUT(ccp_rack_timeout, f); + pcb->ccp_localstate = 0; + ccp_set(pcb, 1, 0, 0, 0); +#if MPPE_SUPPORT + if (go->mppe) { + go->mppe = 0; + if (pcb->lcp_fsm.state == PPP_FSM_OPENED) { + /* If LCP is not already going down, make sure it does. */ + ppp_error("MPPE disabled"); + lcp_close(pcb, "MPPE disabled"); + } + } +#endif /* MPPE_SUPPORT */ +} + +#if PRINTPKT_SUPPORT +/* + * Print the contents of a CCP packet. + */ +static const char* const ccp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej", + NULL, NULL, NULL, NULL, NULL, NULL, + "ResetReq", "ResetAck", +}; + +static int ccp_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { + const u_char *p0, *optend; + int code, id, len; + int optlen; + + p0 = p; + if (plen < HEADERLEN) + return 0; + code = p[0]; + id = p[1]; + len = (p[2] << 8) + p[3]; + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ccp_codenames) && ccp_codenames[code-1] != NULL) + printer(arg, " %s", ccp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + p += HEADERLEN; + + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print list of possible compression methods */ + while (len >= 2) { + code = p[0]; + optlen = p[1]; + if (optlen < 2 || optlen > len) + break; + printer(arg, " <"); + len -= optlen; + optend = p + optlen; + switch (code) { +#if MPPE_SUPPORT + case CI_MPPE: + if (optlen >= CILEN_MPPE) { + u_char mppe_opts; + + MPPE_CI_TO_OPTS(&p[2], mppe_opts); + printer(arg, "mppe %s %s %s %s %s %s%s", + (p[2] & MPPE_H_BIT)? "+H": "-H", + (p[5] & MPPE_M_BIT)? "+M": "-M", + (p[5] & MPPE_S_BIT)? "+S": "-S", + (p[5] & MPPE_L_BIT)? "+L": "-L", + (p[5] & MPPE_D_BIT)? "+D": "-D", + (p[5] & MPPE_C_BIT)? "+C": "-C", + (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": ""); + if (mppe_opts & MPPE_OPT_UNKNOWN) + printer(arg, " (%.2x %.2x %.2x %.2x)", + p[2], p[3], p[4], p[5]); + p += CILEN_MPPE; + } + break; +#endif /* MPPE_SUPPORT */ +#if DEFLATE_SUPPORT + case CI_DEFLATE: + case CI_DEFLATE_DRAFT: + if (optlen >= CILEN_DEFLATE) { + printer(arg, "deflate%s %d", + (code == CI_DEFLATE_DRAFT? "(old#)": ""), + DEFLATE_SIZE(p[2])); + if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL) + printer(arg, " method %d", DEFLATE_METHOD(p[2])); + if (p[3] != DEFLATE_CHK_SEQUENCE) + printer(arg, " check %d", p[3]); + p += CILEN_DEFLATE; + } + break; +#endif /* DEFLATE_SUPPORT */ +#if BSDCOMPRESS_SUPPORT + case CI_BSD_COMPRESS: + if (optlen >= CILEN_BSD_COMPRESS) { + printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), + BSD_NBITS(p[2])); + p += CILEN_BSD_COMPRESS; + } + break; +#endif /* BSDCOMPRESS_SUPPORT */ +#if PREDICTOR_SUPPORT + case CI_PREDICTOR_1: + if (optlen >= CILEN_PREDICTOR_1) { + printer(arg, "predictor 1"); + p += CILEN_PREDICTOR_1; + } + break; + case CI_PREDICTOR_2: + if (optlen >= CILEN_PREDICTOR_2) { + printer(arg, "predictor 2"); + p += CILEN_PREDICTOR_2; + } + break; +#endif /* PREDICTOR_SUPPORT */ + default: + break; + } + while (p < optend) + printer(arg, " %.2x", *p++); + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* dump out the rest of the packet in hex */ + while (--len >= 0) + printer(arg, " %.2x", *p++); + + return p - p0; +} +#endif /* PRINTPKT_SUPPORT */ + +#if PPP_DATAINPUT +/* + * We have received a packet that the decompressor failed to + * decompress. Here we would expect to issue a reset-request, but + * Motorola has a patent on resetting the compressor as a result of + * detecting an error in the decompressed data after decompression. + * (See US patent 5,130,993; international patent publication number + * WO 91/10289; Australian patent 73296/91.) + * + * So we ask the kernel whether the error was detected after + * decompression; if it was, we take CCP down, thus disabling + * compression :-(, otherwise we issue the reset-request. + */ +static void ccp_datainput(ppp_pcb *pcb, u_char *pkt, int len) { + fsm *f; +#if MPPE_SUPPORT + ccp_options *go = &pcb->ccp_gotoptions; +#endif /* MPPE_SUPPORT */ + LWIP_UNUSED_ARG(pkt); + LWIP_UNUSED_ARG(len); + + f = &pcb->ccp_fsm; + if (f->state == PPP_FSM_OPENED) { + if (ccp_fatal_error(pcb)) { + /* + * Disable compression by taking CCP down. + */ + ppp_error("Lost compression sync: disabling compression"); + ccp_close(pcb, "Lost compression sync"); +#if MPPE_SUPPORT + /* + * If we were doing MPPE, we must also take the link down. + */ + if (go->mppe) { + ppp_error("Too many MPPE errors, closing LCP"); + lcp_close(pcb, "Too many MPPE errors"); + } +#endif /* MPPE_SUPPORT */ + } else { + /* + * Send a reset-request to reset the peer's compressor. + * We don't do that if we are still waiting for an + * acknowledgement to a previous reset-request. + */ + if (!(pcb->ccp_localstate & RACK_PENDING)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate |= RACK_PENDING; + } else + pcb->ccp_localstate |= RREQ_REPEAT; + } + } +} +#endif /* PPP_DATAINPUT */ + +/* + * We have received a packet that the decompressor failed to + * decompress. Issue a reset-request. + */ +void ccp_resetrequest(ppp_pcb *pcb) { + fsm *f = &pcb->ccp_fsm; + + if (f->state != PPP_FSM_OPENED) + return; + + /* + * Send a reset-request to reset the peer's compressor. + * We don't do that if we are still waiting for an + * acknowledgement to a previous reset-request. + */ + if (!(pcb->ccp_localstate & RACK_PENDING)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate |= RACK_PENDING; + } else + pcb->ccp_localstate |= RREQ_REPEAT; +} + +/* + * Timeout waiting for reset-ack. + */ +static void ccp_rack_timeout(void *arg) { + fsm *f = (fsm*)arg; + ppp_pcb *pcb = f->pcb; + + if (f->state == PPP_FSM_OPENED && (pcb->ccp_localstate & RREQ_REPEAT)) { + fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); + TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); + pcb->ccp_localstate &= ~RREQ_REPEAT; + } else + pcb->ccp_localstate &= ~RACK_PENDING; +} + +#endif /* PPP_SUPPORT && CCP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-md5.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-md5.c new file mode 100644 index 0000000000..88f069f032 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-md5.c @@ -0,0 +1,126 @@ +/* + * chap-md5.c - New CHAP/MD5 implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap-md5.h" +#include "netif/ppp/magic.h" +#include "netif/ppp/pppcrypt.h" + +#define MD5_HASH_SIZE 16 +#define MD5_MIN_CHALLENGE 17 +#define MD5_MAX_CHALLENGE 24 +#define MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE 3 /* 2^3-1 = 7, 17+7 = 24 */ + +#if PPP_SERVER +static void chap_md5_generate_challenge(ppp_pcb *pcb, unsigned char *cp) { + int clen; + LWIP_UNUSED_ARG(pcb); + + clen = MD5_MIN_CHALLENGE + magic_pow(MD5_MIN_MAX_POWER_OF_TWO_CHALLENGE); + *cp++ = clen; + magic_random_bytes(cp, clen); +} + +static int chap_md5_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + lwip_md5_context ctx; + unsigned char idbyte = id; + unsigned char hash[MD5_HASH_SIZE]; + int challenge_len, response_len; + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(pcb); + + challenge_len = *challenge++; + response_len = *response++; + if (response_len == MD5_HASH_SIZE) { + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&ctx); + lwip_md5_starts(&ctx); + lwip_md5_update(&ctx, &idbyte, 1); + lwip_md5_update(&ctx, secret, secret_len); + lwip_md5_update(&ctx, challenge, challenge_len); + lwip_md5_finish(&ctx, hash); + lwip_md5_free(&ctx); + + /* Test if our hash matches the peer's response */ + if (memcmp(hash, response, MD5_HASH_SIZE) == 0) { + ppp_slprintf(message, message_space, "Access granted"); + return 1; + } + } + ppp_slprintf(message, message_space, "Access denied"); + return 0; +} +#endif /* PPP_SERVER */ + +static void chap_md5_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + lwip_md5_context ctx; + unsigned char idbyte = id; + int challenge_len = *challenge++; + LWIP_UNUSED_ARG(our_name); + LWIP_UNUSED_ARG(private_); + LWIP_UNUSED_ARG(pcb); + + lwip_md5_init(&ctx); + lwip_md5_starts(&ctx); + lwip_md5_update(&ctx, &idbyte, 1); + lwip_md5_update(&ctx, (const u_char *)secret, secret_len); + lwip_md5_update(&ctx, challenge, challenge_len); + lwip_md5_finish(&ctx, &response[1]); + lwip_md5_free(&ctx); + response[0] = MD5_HASH_SIZE; +} + +const struct chap_digest_type md5_digest = { + CHAP_MD5, /* code */ +#if PPP_SERVER + chap_md5_generate_challenge, + chap_md5_verify_response, +#endif /* PPP_SERVER */ + chap_md5_make_response, + NULL, /* check_success */ + NULL, /* handle_failure */ +}; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-new.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-new.c new file mode 100644 index 0000000000..485122d272 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap-new.c @@ -0,0 +1,677 @@ +/* + * chap-new.c - New CHAP implementation. + * + * Copyright (c) 2003 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#if 0 /* UNUSED */ +#include "session.h" +#endif /* UNUSED */ + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap-md5.h" +#if MSCHAP_SUPPORT +#include "netif/ppp/chap_ms.h" +#endif +#include "netif/ppp/magic.h" + +#if 0 /* UNUSED */ +/* Hook for a plugin to validate CHAP challenge */ +int (*chap_verify_hook)(const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) = NULL; +#endif /* UNUSED */ + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t chap_option_list[] = { + { "chap-restart", o_int, &chap_timeout_time, + "Set timeout for CHAP", OPT_PRIO }, + { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits, + "Set max #xmits for challenge", OPT_PRIO }, + { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time, + "Set interval for rechallenge", OPT_PRIO }, + { NULL } +}; +#endif /* PPP_OPTIONS */ + + +/* Values for flags in chap_client_state and chap_server_state */ +#define LOWERUP 1 +#define AUTH_STARTED 2 +#define AUTH_DONE 4 +#define AUTH_FAILED 8 +#define TIMEOUT_PENDING 0x10 +#define CHALLENGE_VALID 0x20 + +/* + * Prototypes. + */ +static void chap_init(ppp_pcb *pcb); +static void chap_lowerup(ppp_pcb *pcb); +static void chap_lowerdown(ppp_pcb *pcb); +#if PPP_SERVER +static void chap_timeout(void *arg); +static void chap_generate_challenge(ppp_pcb *pcb); +static void chap_handle_response(ppp_pcb *pcb, int code, + unsigned char *pkt, int len); +static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space); +#endif /* PPP_SERVER */ +static void chap_respond(ppp_pcb *pcb, int id, + unsigned char *pkt, int len); +static void chap_handle_status(ppp_pcb *pcb, int code, int id, + unsigned char *pkt, int len); +static void chap_protrej(ppp_pcb *pcb); +static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen); +#if PRINTPKT_SUPPORT +static int chap_print_pkt(const unsigned char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +/* List of digest types that we know about */ +static const struct chap_digest_type* const chap_digests[] = { + &md5_digest, +#if MSCHAP_SUPPORT + &chapms_digest, + &chapms2_digest, +#endif /* MSCHAP_SUPPORT */ + NULL +}; + +/* + * chap_init - reset to initial state. + */ +static void chap_init(ppp_pcb *pcb) { + LWIP_UNUSED_ARG(pcb); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(&pcb->chap_client, 0, sizeof(chap_client_state)); +#if PPP_SERVER + memset(&pcb->chap_server, 0, sizeof(chap_server_state)); +#endif /* PPP_SERVER */ +#endif /* 0 */ +} + +/* + * chap_lowerup - we can start doing stuff now. + */ +static void chap_lowerup(ppp_pcb *pcb) { + + pcb->chap_client.flags |= LOWERUP; +#if PPP_SERVER + pcb->chap_server.flags |= LOWERUP; + if (pcb->chap_server.flags & AUTH_STARTED) + chap_timeout(pcb); +#endif /* PPP_SERVER */ +} + +static void chap_lowerdown(ppp_pcb *pcb) { + + pcb->chap_client.flags = 0; +#if PPP_SERVER + if (pcb->chap_server.flags & TIMEOUT_PENDING) + UNTIMEOUT(chap_timeout, pcb); + pcb->chap_server.flags = 0; +#endif /* PPP_SERVER */ +} + +#if PPP_SERVER +/* + * chap_auth_peer - Start authenticating the peer. + * If the lower layer is already up, we start sending challenges, + * otherwise we wait for the lower layer to come up. + */ +void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { + const struct chap_digest_type *dp; + int i; + + if (pcb->chap_server.flags & AUTH_STARTED) { + ppp_error("CHAP: peer authentication already started!"); + return; + } + for (i = 0; (dp = chap_digests[i]) != NULL; ++i) + if (dp->code == digest_code) + break; + if (dp == NULL) + ppp_fatal("CHAP digest 0x%x requested but not available", + digest_code); + + pcb->chap_server.digest = dp; + pcb->chap_server.name = our_name; + /* Start with a random ID value */ + pcb->chap_server.id = magic(); + pcb->chap_server.flags |= AUTH_STARTED; + if (pcb->chap_server.flags & LOWERUP) + chap_timeout(pcb); +} +#endif /* PPP_SERVER */ + +/* + * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. + * There isn't much to do until we receive a challenge. + */ +void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { + const struct chap_digest_type *dp; + int i; + + if(NULL == our_name) + return; + + if (pcb->chap_client.flags & AUTH_STARTED) { + ppp_error("CHAP: authentication with peer already started!"); + return; + } + for (i = 0; (dp = chap_digests[i]) != NULL; ++i) + if (dp->code == digest_code) + break; + + if (dp == NULL) + ppp_fatal("CHAP digest 0x%x requested but not available", + digest_code); + + pcb->chap_client.digest = dp; + pcb->chap_client.name = our_name; + pcb->chap_client.flags |= AUTH_STARTED; +} + +#if PPP_SERVER +/* + * chap_timeout - It's time to send another challenge to the peer. + * This could be either a retransmission of a previous challenge, + * or a new challenge to start re-authentication. + */ +static void chap_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + struct pbuf *p; + + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) { + pcb->chap_server.challenge_xmits = 0; + chap_generate_challenge(pcb); + pcb->chap_server.flags |= CHALLENGE_VALID; + } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) { + pcb->chap_server.flags &= ~CHALLENGE_VALID; + pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED; + auth_peer_fail(pcb, PPP_CHAP); + return; + } + + p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen); + ppp_write(pcb, p); + ++pcb->chap_server.challenge_xmits; + pcb->chap_server.flags |= TIMEOUT_PENDING; + TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time); +} + +/* + * chap_generate_challenge - generate a challenge string and format + * the challenge packet in pcb->chap_server.challenge_pkt. + */ +static void chap_generate_challenge(ppp_pcb *pcb) { + int clen = 1, nlen, len; + unsigned char *p; + + p = pcb->chap_server.challenge; + MAKEHEADER(p, PPP_CHAP); + p += CHAP_HDRLEN; + pcb->chap_server.digest->generate_challenge(pcb, p); + clen = *p; + nlen = strlen(pcb->chap_server.name); + memcpy(p + 1 + clen, pcb->chap_server.name, nlen); + + len = CHAP_HDRLEN + 1 + clen + nlen; + pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len; + + p = pcb->chap_server.challenge + PPP_HDRLEN; + p[0] = CHAP_CHALLENGE; + p[1] = ++pcb->chap_server.id; + p[2] = len >> 8; + p[3] = len; +} + +/* + * chap_handle_response - check the response to our challenge. + */ +static void chap_handle_response(ppp_pcb *pcb, int id, + unsigned char *pkt, int len) { + int response_len, ok, mlen; + const unsigned char *response; + unsigned char *outp; + struct pbuf *p; + const char *name = NULL; /* initialized to shut gcc up */ +#if 0 /* UNUSED */ + int (*verifier)(const char *, const char *, int, const struct chap_digest_type *, + const unsigned char *, const unsigned char *, char *, int); +#endif /* UNUSED */ + char rname[MAXNAMELEN+1]; + char message[256]; + + if ((pcb->chap_server.flags & LOWERUP) == 0) + return; + if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2) + return; + if (pcb->chap_server.flags & CHALLENGE_VALID) { + response = pkt; + GETCHAR(response_len, pkt); + len -= response_len + 1; /* length of name */ + name = (char *)pkt + response_len; + if (len < 0) + return; + + if (pcb->chap_server.flags & TIMEOUT_PENDING) { + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + UNTIMEOUT(chap_timeout, pcb); + } +#if PPP_REMOTENAME + if (pcb->settings.explicit_remote) { + name = pcb->remote_name; + } else +#endif /* PPP_REMOTENAME */ + { + /* Null terminate and clean remote name. */ + ppp_slprintf(rname, sizeof(rname), "%.*v", len, name); + name = rname; + } + +#if 0 /* UNUSED */ + if (chap_verify_hook) + verifier = chap_verify_hook; + else + verifier = chap_verify_response; + ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest, + pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, + response, pcb->chap_server.message, sizeof(pcb->chap_server.message)); +#endif /* UNUSED */ + ok = chap_verify_response(pcb, name, pcb->chap_server.name, id, pcb->chap_server.digest, + pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, + response, message, sizeof(message)); +#if 0 /* UNUSED */ + if (!ok || !auth_number()) { +#endif /* UNUSED */ + if (!ok) { + pcb->chap_server.flags |= AUTH_FAILED; + ppp_warn("Peer %q failed CHAP authentication", name); + } + } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) + return; + + /* send the response */ + mlen = strlen(message); + len = CHAP_HDRLEN + mlen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (unsigned char *)p->payload; + MAKEHEADER(outp, PPP_CHAP); + + outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; + outp[1] = id; + outp[2] = len >> 8; + outp[3] = len; + if (mlen > 0) + memcpy(outp + CHAP_HDRLEN, message, mlen); + ppp_write(pcb, p); + + if (pcb->chap_server.flags & CHALLENGE_VALID) { + pcb->chap_server.flags &= ~CHALLENGE_VALID; + if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) { + +#if 0 /* UNUSED */ + /* + * Auth is OK, so now we need to check session restrictions + * to ensure everything is OK, but only if we used a + * plugin, and only if we're configured to check. This + * allows us to do PAM checks on PPP servers that + * authenticate against ActiveDirectory, and use AD for + * account info (like when using Winbind integrated with + * PAM). + */ + if (session_mgmt && + session_check(name, NULL, devnam, NULL) == 0) { + pcb->chap_server.flags |= AUTH_FAILED; + ppp_warn("Peer %q failed CHAP Session verification", name); + } +#endif /* UNUSED */ + + } + if (pcb->chap_server.flags & AUTH_FAILED) { + auth_peer_fail(pcb, PPP_CHAP); + } else { + if ((pcb->chap_server.flags & AUTH_DONE) == 0) + auth_peer_success(pcb, PPP_CHAP, + pcb->chap_server.digest->code, + name, strlen(name)); + if (pcb->settings.chap_rechallenge_time) { + pcb->chap_server.flags |= TIMEOUT_PENDING; + TIMEOUT(chap_timeout, pcb, + pcb->settings.chap_rechallenge_time); + } + } + pcb->chap_server.flags |= AUTH_DONE; + } +} + +/* + * chap_verify_response - check whether the peer's response matches + * what we think it should be. Returns 1 if it does (authentication + * succeeded), or 0 if it doesn't. + */ +static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, + const struct chap_digest_type *digest, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + int ok; + unsigned char secret[MAXSECRETLEN]; + int secret_len; + + /* Get the secret that the peer is supposed to know */ + if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { + ppp_error("No CHAP secret found for authenticating %q", name); + return 0; + } + ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, + response, message, message_space); + memset(secret, 0, sizeof(secret)); + + return ok; +} +#endif /* PPP_SERVER */ + +/* + * chap_respond - Generate and send a response to a challenge. + */ +static void chap_respond(ppp_pcb *pcb, int id, + unsigned char *pkt, int len) { + int clen, nlen; + int secret_len; + struct pbuf *p; + u_char *outp; + char rname[MAXNAMELEN+1]; + char secret[MAXSECRETLEN+1]; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) + return; /* not ready */ + if (len < 2 || len < pkt[0] + 1) + return; /* too short */ + clen = pkt[0]; + nlen = len - (clen + 1); + + /* Null terminate and clean remote name. */ + ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); + +#if PPP_REMOTENAME + /* Microsoft doesn't send their name back in the PPP packet */ + if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0)) + strlcpy(rname, pcb->settings.remote_name, sizeof(rname)); +#endif /* PPP_REMOTENAME */ + + /* get secret for authenticating ourselves with the specified host */ + if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { + secret_len = 0; /* assume null secret if can't find one */ + ppp_warn("No CHAP secret found for authenticating us to %q", rname); + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_CHAP); + outp += CHAP_HDRLEN; + + pcb->chap_client.digest->make_response(pcb, outp, id, pcb->chap_client.name, pkt, + secret, secret_len, pcb->chap_client.priv); + memset(secret, 0, secret_len); + + clen = *outp; + nlen = strlen(pcb->chap_client.name); + memcpy(outp + clen + 1, pcb->chap_client.name, nlen); + + outp = (u_char*)p->payload + PPP_HDRLEN; + len = CHAP_HDRLEN + clen + 1 + nlen; + outp[0] = CHAP_RESPONSE; + outp[1] = id; + outp[2] = len >> 8; + outp[3] = len; + + pbuf_realloc(p, PPP_HDRLEN + len); + ppp_write(pcb, p); +} + +static void chap_handle_status(ppp_pcb *pcb, int code, int id, + unsigned char *pkt, int len) { + const char *msg = NULL; + LWIP_UNUSED_ARG(id); + + if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) + != (AUTH_STARTED|LOWERUP)) + return; + pcb->chap_client.flags |= AUTH_DONE; + + if (code == CHAP_SUCCESS) { + /* used for MS-CHAP v2 mutual auth, yuck */ + if (pcb->chap_client.digest->check_success != NULL) { + if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv)) + code = CHAP_FAILURE; + } else + msg = "CHAP authentication succeeded"; + } else { + if (pcb->chap_client.digest->handle_failure != NULL) + (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len); + else + msg = "CHAP authentication failed"; + } + if (msg) { + if (len > 0) + ppp_info("%s: %.*v", msg, len, pkt); + else + ppp_info("%s", msg); + } + if (code == CHAP_SUCCESS) + auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); + else { + pcb->chap_client.flags |= AUTH_FAILED; + ppp_error("CHAP authentication failed"); + auth_withpeer_fail(pcb, PPP_CHAP); + } +} + +static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) { + unsigned char code, id; + int len; + + if (pktlen < CHAP_HDRLEN) + return; + GETCHAR(code, pkt); + GETCHAR(id, pkt); + GETSHORT(len, pkt); + if (len < CHAP_HDRLEN || len > pktlen) + return; + len -= CHAP_HDRLEN; + + switch (code) { + case CHAP_CHALLENGE: + chap_respond(pcb, id, pkt, len); + break; +#if PPP_SERVER + case CHAP_RESPONSE: + chap_handle_response(pcb, id, pkt, len); + break; +#endif /* PPP_SERVER */ + case CHAP_FAILURE: + case CHAP_SUCCESS: + chap_handle_status(pcb, code, id, pkt, len); + break; + default: + break; + } +} + +static void chap_protrej(ppp_pcb *pcb) { + +#if PPP_SERVER + if (pcb->chap_server.flags & TIMEOUT_PENDING) { + pcb->chap_server.flags &= ~TIMEOUT_PENDING; + UNTIMEOUT(chap_timeout, pcb); + } + if (pcb->chap_server.flags & AUTH_STARTED) { + pcb->chap_server.flags = 0; + auth_peer_fail(pcb, PPP_CHAP); + } +#endif /* PPP_SERVER */ + if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { + pcb->chap_client.flags &= ~AUTH_STARTED; + ppp_error("CHAP authentication failed due to protocol-reject"); + auth_withpeer_fail(pcb, PPP_CHAP); + } +} + +#if PRINTPKT_SUPPORT +/* + * chap_print_pkt - print the contents of a CHAP packet. + */ +static const char* const chap_code_names[] = { + "Challenge", "Response", "Success", "Failure" +}; + +static int chap_print_pkt(const unsigned char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len; + int clen, nlen; + unsigned char x; + + if (plen < CHAP_HDRLEN) + return 0; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < CHAP_HDRLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(chap_code_names)) + printer(arg, " %s", chap_code_names[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= CHAP_HDRLEN; + switch (code) { + case CHAP_CHALLENGE: + case CHAP_RESPONSE: + if (len < 1) + break; + clen = p[0]; + if (len < clen + 1) + break; + ++p; + nlen = len - clen - 1; + printer(arg, " <"); + for (; clen > 0; --clen) { + GETCHAR(x, p); + printer(arg, "%.2x", x); + } + printer(arg, ">, name = "); + ppp_print_string(p, nlen, printer, arg); + break; + case CHAP_FAILURE: + case CHAP_SUCCESS: + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + break; + default: + for (clen = len; clen > 0; --clen) { + GETCHAR(x, p); + printer(arg, " %.2x", x); + } + /* no break */ + } + + return len + CHAP_HDRLEN; +} +#endif /* PRINTPKT_SUPPORT */ + +const struct protent chap_protent = { + PPP_CHAP, + chap_init, + chap_input, + chap_protrej, + chap_lowerup, + chap_lowerdown, + NULL, /* open */ + NULL, /* close */ +#if PRINTPKT_SUPPORT + chap_print_pkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* datainput */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "CHAP", /* name */ + NULL, /* data_name */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + chap_option_list, + NULL, /* check_options */ +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +#endif /* PPP_SUPPORT && CHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap_ms.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap_ms.c new file mode 100644 index 0000000000..5a989c9b7e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/chap_ms.c @@ -0,0 +1,962 @@ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 + * + * Implemented LANManager type password response to MS-CHAP challenges. + * Now pppd provides both NT style and LANMan style blocks, and the + * prefered is set by option "ms-lanman". Default is to use NT. + * The hash text (StdText) was taken from Win95 RASAPI32.DLL. + * + * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 + */ + +/* + * Modifications by Frank Cusack, frank@google.com, March 2002. + * + * Implemented MS-CHAPv2 functionality, heavily based on sample + * implementation in RFC 2759. Implemented MPPE functionality, + * heavily based on sample implementation in RFC 3079. + * + * Copyright (c) 2002 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/chap-new.h" +#include "netif/ppp/chap_ms.h" +#include "netif/ppp/pppcrypt.h" +#include "netif/ppp/magic.h" +#if MPPE_SUPPORT +#include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */ +#endif /* MPPE_SUPPORT */ + +#define SHA1_SIGNATURE_SIZE 20 +#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */ +#define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */ + +#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ +#define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ +#define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */ + /* as ASCII */ + +/* Error codes for MS-CHAP failure messages. */ +#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646 +#define MS_CHAP_ERROR_ACCT_DISABLED 647 +#define MS_CHAP_ERROR_PASSWD_EXPIRED 648 +#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649 +#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691 +#define MS_CHAP_ERROR_CHANGING_PASSWORD 709 + +/* + * Offsets within the response field for MS-CHAP + */ +#define MS_CHAP_LANMANRESP 0 +#define MS_CHAP_LANMANRESP_LEN 24 +#define MS_CHAP_NTRESP 24 +#define MS_CHAP_NTRESP_LEN 24 +#define MS_CHAP_USENT 48 + +/* + * Offsets within the response field for MS-CHAP2 + */ +#define MS_CHAP2_PEER_CHALLENGE 0 +#define MS_CHAP2_PEER_CHAL_LEN 16 +#define MS_CHAP2_RESERVED_LEN 8 +#define MS_CHAP2_NTRESP 24 +#define MS_CHAP2_NTRESP_LEN 24 +#define MS_CHAP2_FLAGS 48 + +#if MPPE_SUPPORT +#if 0 /* UNUSED */ +/* These values are the RADIUS attribute values--see RFC 2548. */ +#define MPPE_ENC_POL_ENC_ALLOWED 1 +#define MPPE_ENC_POL_ENC_REQUIRED 2 +#define MPPE_ENC_TYPES_RC4_40 2 +#define MPPE_ENC_TYPES_RC4_128 4 + +/* used by plugins (using above values) */ +extern void set_mppe_enc_types(int, int); +#endif /* UNUSED */ +#endif /* MPPE_SUPPORT */ + +/* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ +#define MS_CHAP2_AUTHENTICATEE 0 +#define MS_CHAP2_AUTHENTICATOR 1 + +static void ascii2unicode (const char[], int, u_char[]); +static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); +static void ChallengeResponse (const u_char *, const u_char *, u_char[24]); +static void ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]); +static void ChapMS_NT (const u_char *, const char *, int, u_char[24]); +static void ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int, + u_char[24]); +static void GenerateAuthenticatorResponsePlain + (const char*, int, u_char[24], const u_char[16], const u_char *, + const char *, u_char[41]); +#ifdef MSLANMAN +static void ChapMS_LANMan (u_char *, char *, int, u_char *); +#endif + +static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]); + +#if MPPE_SUPPORT +static void Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int); +static void SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int); +#endif /* MPPE_SUPPORT */ + +static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *); +static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int, + u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int); + +#ifdef MSLANMAN +bool ms_lanman = 0; /* Use LanMan password instead of NT */ + /* Has meaning only with MS-CHAP challenges */ +#endif + +#if MPPE_SUPPORT +#ifdef DEBUGMPPEKEY +/* For MPPE debug */ +/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ +static char *mschap_challenge = NULL; +/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ +static char *mschap2_peer_challenge = NULL; +#endif + +#include "netif/ppp/fsm.h" /* Need to poke MPPE options */ +#include "netif/ppp/ccp.h" +#endif /* MPPE_SUPPORT */ + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t chapms_option_list[] = { +#ifdef MSLANMAN + { "ms-lanman", o_bool, &ms_lanman, + "Use LanMan passwd when using MS-CHAP", 1 }, +#endif +#ifdef DEBUGMPPEKEY + { "mschap-challenge", o_string, &mschap_challenge, + "specify CHAP challenge" }, + { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, + "specify CHAP peer challenge" }, +#endif + { NULL } +}; +#endif /* PPP_OPTIONS */ + +#if PPP_SERVER +/* + * chapms_generate_challenge - generate a challenge for MS-CHAP. + * For MS-CHAP the challenge length is fixed at 8 bytes. + * The length goes in challenge[0] and the actual challenge starts + * at challenge[1]. + */ +static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { + LWIP_UNUSED_ARG(pcb); + + *challenge++ = 8; +#ifdef DEBUGMPPEKEY + if (mschap_challenge && strlen(mschap_challenge) == 8) + memcpy(challenge, mschap_challenge, 8); + else +#endif + magic_random_bytes(challenge, 8); +} + +static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) { + LWIP_UNUSED_ARG(pcb); + + *challenge++ = 16; +#ifdef DEBUGMPPEKEY + if (mschap_challenge && strlen(mschap_challenge) == 16) + memcpy(challenge, mschap_challenge, 16); + else +#endif + magic_random_bytes(challenge, 16); +} + +static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + unsigned char md[MS_CHAP_RESPONSE_LEN]; + int diff; + int challenge_len, response_len; + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(name); + + challenge_len = *challenge++; /* skip length, is 8 */ + response_len = *response++; + if (response_len != MS_CHAP_RESPONSE_LEN) + goto bad; + +#ifndef MSLANMAN + if (!response[MS_CHAP_USENT]) { + /* Should really propagate this into the error packet. */ + ppp_notice("Peer request for LANMAN auth not supported"); + goto bad; + } +#endif + + /* Generate the expected response. */ + ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md); + +#ifdef MSLANMAN + /* Determine which part of response to verify against */ + if (!response[MS_CHAP_USENT]) + diff = memcmp(&response[MS_CHAP_LANMANRESP], + &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN); + else +#endif + diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP], + MS_CHAP_NTRESP_LEN); + + if (diff == 0) { + ppp_slprintf(message, message_space, "Access granted"); + return 1; + } + + bad: + /* See comments below for MS-CHAP V2 */ + ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", + challenge_len, challenge); + return 0; +} + +static int chapms2_verify_response(ppp_pcb *pcb, int id, const char *name, + const unsigned char *secret, int secret_len, + const unsigned char *challenge, const unsigned char *response, + char *message, int message_space) { + unsigned char md[MS_CHAP2_RESPONSE_LEN]; + char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; + int challenge_len, response_len; + LWIP_UNUSED_ARG(id); + + challenge_len = *challenge++; /* skip length, is 16 */ + response_len = *response++; + if (response_len != MS_CHAP2_RESPONSE_LEN) + goto bad; /* not even the right length */ + + /* Generate the expected response and our mutual auth. */ + ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name, + (const char *)secret, secret_len, md, + (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); + + /* compare MDs and send the appropriate status */ + /* + * Per RFC 2759, success message must be formatted as + * "S= M=" + * where + * is the Authenticator Response (mutual auth) + * is a text message + * + * However, some versions of Windows (win98 tested) do not know + * about the M= part (required per RFC 2759) and flag + * it as an error (reported incorrectly as an encryption error + * to the user). Since the RFC requires it, and it can be + * useful information, we supply it if the peer is a conforming + * system. Luckily (?), win98 sets the Flags field to 0x04 + * (contrary to RFC requirements) so we can use that to + * distinguish between conforming and non-conforming systems. + * + * Special thanks to Alex Swiridov for + * help debugging this. + */ + if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP], + MS_CHAP2_NTRESP_LEN) == 0) { + if (response[MS_CHAP2_FLAGS]) + ppp_slprintf(message, message_space, "S=%s", saresponse); + else + ppp_slprintf(message, message_space, "S=%s M=%s", + saresponse, "Access granted"); + return 1; + } + + bad: + /* + * Failure message must be formatted as + * "E=e R=r C=c V=v M=m" + * where + * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) + * r = retry (we use 1, ok to retry) + * c = challenge to use for next response, we reuse previous + * v = Change Password version supported, we use 0 + * m = text message + * + * The M=m part is only for MS-CHAPv2. Neither win2k nor + * win98 (others untested) display the message to the user anyway. + * They also both ignore the E=e code. + * + * Note that it's safe to reuse the same challenge as we don't + * actually accept another response based on the error message + * (and no clients try to resend a response anyway). + * + * Basically, this whole bit is useless code, even the small + * implementation here is only because of overspecification. + */ + ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", + challenge_len, challenge, "Access denied"); + return 0; +} +#endif /* PPP_SERVER */ + +static void chapms_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(our_name); + LWIP_UNUSED_ARG(private_); + challenge++; /* skip length, should be 8 */ + *response++ = MS_CHAP_RESPONSE_LEN; + ChapMS(pcb, challenge, secret, secret_len, response); +} + +static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name, + const unsigned char *challenge, const char *secret, int secret_len, + unsigned char *private_) { + LWIP_UNUSED_ARG(id); + challenge++; /* skip length, should be 16 */ + *response++ = MS_CHAP2_RESPONSE_LEN; + ChapMS2(pcb, challenge, +#ifdef DEBUGMPPEKEY + mschap2_peer_challenge, +#else + NULL, +#endif + our_name, secret, secret_len, response, private_, + MS_CHAP2_AUTHENTICATEE); +} + +static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) { + LWIP_UNUSED_ARG(pcb); + + if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || + strncmp((char *)msg, "S=", 2) != 0) { + /* Packet does not start with "S=" */ + ppp_error("MS-CHAPv2 Success packet is badly formed."); + return 0; + } + msg += 2; + len -= 2; + if (len < MS_AUTH_RESPONSE_LENGTH + || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) { + /* Authenticator Response did not match expected. */ + ppp_error("MS-CHAPv2 mutual authentication failed."); + return 0; + } + /* Authenticator Response matches. */ + msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ + len -= MS_AUTH_RESPONSE_LENGTH; + if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { + msg += 3; /* Eat the delimiter */ + } else if (len) { + /* Packet has extra text which does not begin " M=" */ + ppp_error("MS-CHAPv2 Success packet is badly formed."); + return 0; + } + return 1; +} + +static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) { + int err; + const char *p; + char msg[64]; + LWIP_UNUSED_ARG(pcb); + + /* We want a null-terminated string for strxxx(). */ + len = LWIP_MIN(len, 63); + MEMCPY(msg, inp, len); + msg[len] = 0; + p = msg; + + /* + * Deal with MS-CHAP formatted failure messages; just print the + * M= part (if any). For MS-CHAP we're not really supposed + * to use M=, but it shouldn't hurt. See + * chapms[2]_verify_response. + */ + if (!strncmp(p, "E=", 2)) + err = strtol(p+2, NULL, 10); /* Remember the error code. */ + else + goto print_msg; /* Message is badly formatted. */ + + if (len && ((p = strstr(p, " M=")) != NULL)) { + /* M= field found. */ + p += 3; + } else { + /* No M=; use the error code. */ + switch (err) { + case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: + p = "E=646 Restricted logon hours"; + break; + + case MS_CHAP_ERROR_ACCT_DISABLED: + p = "E=647 Account disabled"; + break; + + case MS_CHAP_ERROR_PASSWD_EXPIRED: + p = "E=648 Password expired"; + break; + + case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: + p = "E=649 No dialin permission"; + break; + + case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: + p = "E=691 Authentication failure"; + break; + + case MS_CHAP_ERROR_CHANGING_PASSWORD: + /* Should never see this, we don't support Change Password. */ + p = "E=709 Error changing password"; + break; + + default: + ppp_error("Unknown MS-CHAP authentication failure: %.*v", + len, inp); + return; + } + } +print_msg: + if (p != NULL) + ppp_error("MS-CHAP authentication failed: %v", p); +} + +static void ChallengeResponse(const u_char *challenge, + const u_char PasswordHash[MD4_SIGNATURE_SIZE], + u_char response[24]) { + u_char ZPasswordHash[21]; + lwip_des_context des; + u_char des_key[8]; + + BZERO(ZPasswordHash, sizeof(ZPasswordHash)); + MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE); + +#if 0 + dbglog("ChallengeResponse - ZPasswordHash %.*B", + sizeof(ZPasswordHash), ZPasswordHash); +#endif + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +0); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +8); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, challenge, response +16); + lwip_des_free(&des); + +#if 0 + dbglog("ChallengeResponse - response %.24B", response); +#endif +} + +static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge, + const char *username, u_char Challenge[8]) { + lwip_sha1_context sha1Context; + u_char sha1Hash[SHA1_SIGNATURE_SIZE]; + const char *user; + + /* remove domain from "domain\username" */ + if ((user = strrchr(username, '\\')) != NULL) + ++user; + else + user = username; + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PeerChallenge, 16); + lwip_sha1_update(&sha1Context, rchallenge, 16); + lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user)); + lwip_sha1_finish(&sha1Context, sha1Hash); + lwip_sha1_free(&sha1Context); + + MEMCPY(Challenge, sha1Hash, 8); +} + +/* + * Convert the ASCII version of the password to Unicode. + * This implicitly supports 8-bit ISO8859/1 characters. + * This gives us the little-endian representation, which + * is assumed by all M$ CHAP RFCs. (Unicode byte ordering + * is machine-dependent.) + */ +static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) { + int i; + + BZERO(unicode, ascii_len * 2); + for (i = 0; i < ascii_len; i++) + unicode[i * 2] = (u_char) ascii[i]; +} + +static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) { + lwip_md4_context md4Context; + + lwip_md4_init(&md4Context); + lwip_md4_starts(&md4Context); + lwip_md4_update(&md4Context, secret, secret_len); + lwip_md4_finish(&md4Context, hash); + lwip_md4_free(&md4Context); +} + +static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len, + u_char NTResponse[24]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(rchallenge, PasswordHash, NTResponse); +} + +static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username, + const char *secret, int secret_len, u_char NTResponse[24]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char Challenge[8]; + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(Challenge, PasswordHash, NTResponse); +} + +#ifdef MSLANMAN +static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ + +static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, + unsigned char *response) { + int i; + u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + lwip_des_context des; + u_char des_key[8]; + + /* LANMan password is case insensitive */ + BZERO(UcasePassword, sizeof(UcasePassword)); + for (i = 0; i < secret_len; i++) + UcasePassword[i] = (u_char)toupper(secret[i]); + + pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, StdText, PasswordHash +0); + lwip_des_free(&des); + + pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key); + lwip_des_init(&des); + lwip_des_setkey_enc(&des, des_key); + lwip_des_crypt_ecb(&des, StdText, PasswordHash +8); + lwip_des_free(&des); + + ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); +} +#endif + + +static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE], + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { + /* + * "Magic" constants used in response generation, from RFC 2759. + */ + static const u_char Magic1[39] = /* "Magic server to client signing constant" */ + { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; + static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ + { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E }; + + int i; + lwip_sha1_context sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; + u_char Challenge[8]; + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, NTResponse, 24); + lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, Digest, sizeof(Digest)); + lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge)); + lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2)); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + /* Convert to ASCII hex string. */ + for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++) + sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); +} + + +static void GenerateAuthenticatorResponsePlain( + const char *secret, int secret_len, + u_char NTResponse[24], const u_char PeerChallenge[16], + const u_char *rchallenge, const char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), + PasswordHashHash); + + GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, + rchallenge, username, authResponse); +} + + +#if MPPE_SUPPORT +/* + * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) + */ +static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + lwip_sha1_context sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, rchallenge, 8); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + /* Same key in both directions. */ + mppe_set_key(pcb, &pcb->mppe_comp, Digest); + mppe_set_key(pcb, &pcb->mppe_decomp, Digest); + + pcb->mppe_keys_set = 1; +} + +/* + * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) + */ +static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) { + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + lwip_sha1_context sha1Context; + u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + const u_char *s; + + /* "This is the MPPE Master Key" */ + static const u_char Magic1[27] = + { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; + /* "On the client side, this is the send key; " + "on the server side, it is the receive key." */ + static const u_char Magic2[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + /* "On the client side, this is the receive key; " + "on the server side, it is the send key." */ + static const u_char Magic3[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + lwip_sha1_update(&sha1Context, NTResponse, 24); + lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1)); + lwip_sha1_finish(&sha1Context, MasterKey); + lwip_sha1_free(&sha1Context); + + /* + * generate send key + */ + if (IsServer) + s = Magic3; + else + s = Magic2; + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, MasterKey, 16); + lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1Context, s, 84); + lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + mppe_set_key(pcb, &pcb->mppe_comp, Digest); + + /* + * generate recv key + */ + if (IsServer) + s = Magic2; + else + s = Magic3; + lwip_sha1_init(&sha1Context); + lwip_sha1_starts(&sha1Context); + lwip_sha1_update(&sha1Context, MasterKey, 16); + lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1Context, s, 84); + lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1Context, Digest); + lwip_sha1_free(&sha1Context); + + mppe_set_key(pcb, &pcb->mppe_decomp, Digest); + + pcb->mppe_keys_set = 1; +} + +#endif /* MPPE_SUPPORT */ + + +static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len, + unsigned char *response) { +#if !MPPE_SUPPORT + LWIP_UNUSED_ARG(pcb); +#endif /* !MPPE_SUPPORT */ + BZERO(response, MS_CHAP_RESPONSE_LEN); + + ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); + +#ifdef MSLANMAN + ChapMS_LANMan(rchallenge, secret, secret_len, + &response[MS_CHAP_LANMANRESP]); + + /* preferred method is set by option */ + response[MS_CHAP_USENT] = !ms_lanman; +#else + response[MS_CHAP_USENT] = 1; +#endif + +#if MPPE_SUPPORT + Set_Start_Key(pcb, rchallenge, secret, secret_len); +#endif /* MPPE_SUPPORT */ +} + + +/* + * If PeerChallenge is NULL, one is generated and the PeerChallenge + * field of response is filled in. Call this way when generating a response. + * If PeerChallenge is supplied, it is copied into the PeerChallenge field. + * Call this way when verifying a response (or debugging). + * Do not call with PeerChallenge = response. + * + * The PeerChallenge field of response is then used for calculation of the + * Authenticator Response. + */ +static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge, + const char *user, const char *secret, int secret_len, unsigned char *response, + u_char authResponse[], int authenticator) { + /* ARGSUSED */ + LWIP_UNUSED_ARG(authenticator); +#if !MPPE_SUPPORT + LWIP_UNUSED_ARG(pcb); +#endif /* !MPPE_SUPPORT */ + + BZERO(response, MS_CHAP2_RESPONSE_LEN); + + /* Generate the Peer-Challenge if requested, or copy it if supplied. */ + if (!PeerChallenge) + magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN); + else + MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge, + MS_CHAP2_PEER_CHAL_LEN); + + /* Generate the NT-Response */ + ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, + secret, secret_len, &response[MS_CHAP2_NTRESP]); + + /* Generate the Authenticator Response. */ + GenerateAuthenticatorResponsePlain(secret, secret_len, + &response[MS_CHAP2_NTRESP], + &response[MS_CHAP2_PEER_CHALLENGE], + rchallenge, user, authResponse); + +#if MPPE_SUPPORT + SetMasterKeys(pcb, secret, secret_len, + &response[MS_CHAP2_NTRESP], authenticator); +#endif /* MPPE_SUPPORT */ +} + +#if 0 /* UNUSED */ +#if MPPE_SUPPORT +/* + * Set MPPE options from plugins. + */ +void set_mppe_enc_types(int policy, int types) { + /* Early exit for unknown policies. */ + if (policy != MPPE_ENC_POL_ENC_ALLOWED || + policy != MPPE_ENC_POL_ENC_REQUIRED) + return; + + /* Don't modify MPPE if it's optional and wasn't already configured. */ + if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) + return; + + /* + * Disable undesirable encryption types. Note that we don't ENABLE + * any encryption types, to avoid overriding manual configuration. + */ + switch(types) { + case MPPE_ENC_TYPES_RC4_40: + ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ + break; + case MPPE_ENC_TYPES_RC4_128: + ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ + break; + default: + break; + } +} +#endif /* MPPE_SUPPORT */ +#endif /* UNUSED */ + +const struct chap_digest_type chapms_digest = { + CHAP_MICROSOFT, /* code */ +#if PPP_SERVER + chapms_generate_challenge, + chapms_verify_response, +#endif /* PPP_SERVER */ + chapms_make_response, + NULL, /* check_success */ + chapms_handle_failure, +}; + +const struct chap_digest_type chapms2_digest = { + CHAP_MICROSOFT_V2, /* code */ +#if PPP_SERVER + chapms2_generate_challenge, + chapms2_verify_response, +#endif /* PPP_SERVER */ + chapms2_make_response, + chapms2_check_success, + chapms_handle_failure, +}; + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/demand.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/demand.c new file mode 100644 index 0000000000..26c6c30db1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/demand.c @@ -0,0 +1,465 @@ +/* + * demand.c - Support routines for demand-dialling. + * + * Copyright (c) 1996-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && DEMAND_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef PPP_FILTER +#include +#endif + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/lcp.h" + +char *frame; +int framelen; +int framemax; +int escape_flag; +int flush_flag; +int fcs; + +struct packet { + int length; + struct packet *next; + unsigned char data[1]; +}; + +struct packet *pend_q; +struct packet *pend_qtail; + +static int active_packet (unsigned char *, int); + +/* + * demand_conf - configure the interface for doing dial-on-demand. + */ +void +demand_conf() +{ + int i; + const struct protent *protp; + +/* framemax = lcp_allowoptions[0].mru; + if (framemax < PPP_MRU) */ + framemax = PPP_MRU; + framemax += PPP_HDRLEN + PPP_FCSLEN; + frame = malloc(framemax); + if (frame == NULL) + novm("demand frame"); + framelen = 0; + pend_q = NULL; + escape_flag = 0; + flush_flag = 0; + fcs = PPP_INITFCS; + + netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU)); + if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0) + fatal("Couldn't set up demand-dialled PPP interface: %m"); + +#ifdef PPP_FILTER + set_filters(&pass_filter, &active_filter); +#endif + + /* + * Call the demand_conf procedure for each protocol that's got one. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + ((*protp->demand_conf)(pcb)); +/* FIXME: find a way to die() here */ +#if 0 + if (!((*protp->demand_conf)(pcb))) + die(1); +#endif +} + + +/* + * demand_block - set each network protocol to block further packets. + */ +void +demand_block() +{ + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE); + get_loop_output(); +} + +/* + * demand_discard - set each network protocol to discard packets + * with an error. + */ +void +demand_discard() +{ + struct packet *pkt, *nextpkt; + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR); + get_loop_output(); + + /* discard all saved packets */ + for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { + nextpkt = pkt->next; + free(pkt); + } + pend_q = NULL; + framelen = 0; + flush_flag = 0; + escape_flag = 0; + fcs = PPP_INITFCS; +} + +/* + * demand_unblock - set each enabled network protocol to pass packets. + */ +void +demand_unblock() +{ + int i; + const struct protent *protp; + + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->demand_conf != NULL) + sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS); +} + +/* + * FCS lookup table as calculated by genfcstab. + */ +static u_short fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* + * loop_chars - process characters received from the loopback. + * Calls loop_frame when a complete frame has been accumulated. + * Return value is 1 if we need to bring up the link, 0 otherwise. + */ +int +loop_chars(p, n) + unsigned char *p; + int n; +{ + int c, rv; + + rv = 0; + +/* check for synchronous connection... */ + + if ( (p[0] == 0xFF) && (p[1] == 0x03) ) { + rv = loop_frame(p,n); + return rv; + } + + for (; n > 0; --n) { + c = *p++; + if (c == PPP_FLAG) { + if (!escape_flag && !flush_flag + && framelen > 2 && fcs == PPP_GOODFCS) { + framelen -= 2; + if (loop_frame((unsigned char *)frame, framelen)) + rv = 1; + } + framelen = 0; + flush_flag = 0; + escape_flag = 0; + fcs = PPP_INITFCS; + continue; + } + if (flush_flag) + continue; + if (escape_flag) { + c ^= PPP_TRANS; + escape_flag = 0; + } else if (c == PPP_ESCAPE) { + escape_flag = 1; + continue; + } + if (framelen >= framemax) { + flush_flag = 1; + continue; + } + frame[framelen++] = c; + fcs = PPP_FCS(fcs, c); + } + return rv; +} + +/* + * loop_frame - given a frame obtained from the loopback, + * decide whether to bring up the link or not, and, if we want + * to transmit this frame later, put it on the pending queue. + * Return value is 1 if we need to bring up the link, 0 otherwise. + * We assume that the kernel driver has already applied the + * pass_filter, so we won't get packets it rejected. + * We apply the active_filter to see if we want this packet to + * bring up the link. + */ +int +loop_frame(frame, len) + unsigned char *frame; + int len; +{ + struct packet *pkt; + + /* dbglog("from loop: %P", frame, len); */ + if (len < PPP_HDRLEN) + return 0; + if ((PPP_PROTOCOL(frame) & 0x8000) != 0) + return 0; /* shouldn't get any of these anyway */ + if (!active_packet(frame, len)) + return 0; + + pkt = (struct packet *) malloc(sizeof(struct packet) + len); + if (pkt != NULL) { + pkt->length = len; + pkt->next = NULL; + memcpy(pkt->data, frame, len); + if (pend_q == NULL) + pend_q = pkt; + else + pend_qtail->next = pkt; + pend_qtail = pkt; + } + return 1; +} + +/* + * demand_rexmit - Resend all those frames which we got via the + * loopback, now that the real serial link is up. + */ +void +demand_rexmit(proto, newip) + int proto; + u32_t newip; +{ + struct packet *pkt, *prev, *nextpkt; + unsigned short checksum; + unsigned short pkt_checksum = 0; + unsigned iphdr; + struct timeval tv; + char cv = 0; + char ipstr[16]; + + prev = NULL; + pkt = pend_q; + pend_q = NULL; + tv.tv_sec = 1; + tv.tv_usec = 0; + select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */ + for (; pkt != NULL; pkt = nextpkt) { + nextpkt = pkt->next; + if (PPP_PROTOCOL(pkt->data) == proto) { + if ( (proto == PPP_IP) && newip ) { + /* Get old checksum */ + + iphdr = (pkt->data[4] & 15) << 2; + checksum = *((unsigned short *) (pkt->data+14)); + if (checksum == 0xFFFF) { + checksum = 0; + } + + + if (pkt->data[13] == 17) { + pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr)); + if (pkt_checksum) { + cv = 1; + if (pkt_checksum == 0xFFFF) { + pkt_checksum = 0; + } + } + else { + cv = 0; + } + } + + if (pkt->data[13] == 6) { + pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr)); + cv = 1; + if (pkt_checksum == 0xFFFF) { + pkt_checksum = 0; + } + } + + /* Delete old Source-IP-Address */ + checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + /* Change Source-IP-Address */ + * ((u32_t *) (pkt->data + 16)) = newip; + + /* Add new Source-IP-Address */ + checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; + pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; + + /* Write new checksum */ + if (!checksum) { + checksum = 0xFFFF; + } + *((unsigned short *) (pkt->data+14)) = checksum; + if (pkt->data[13] == 6) { + *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum; + } + if (cv && (pkt->data[13] == 17) ) { + *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum; + } + + /* Log Packet */ + strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16)))); + if (pkt->data[13] == 1) { + syslog(LOG_INFO,"Open ICMP %s -> %s\n", + ipstr, + inet_ntoa(*( (struct in_addr *) (pkt->data+20)))); + } else { + syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n", + pkt->data[13] == 6 ? "TCP" : "UDP", + ipstr, + ntohs(*( (short *) (pkt->data+iphdr+4))), + inet_ntoa(*( (struct in_addr *) (pkt->data+20))), + ntohs(*( (short *) (pkt->data+iphdr+6)))); + } + } + output(pcb, pkt->data, pkt->length); + free(pkt); + } else { + if (prev == NULL) + pend_q = pkt; + else + prev->next = pkt; + prev = pkt; + } + } + pend_qtail = prev; + if (prev != NULL) + prev->next = NULL; +} + +/* + * Scan a packet to decide whether it is an "active" packet, + * that is, whether it is worth bringing up the link for. + */ +static int +active_packet(p, len) + unsigned char *p; + int len; +{ + int proto, i; + const struct protent *protp; + + if (len < PPP_HDRLEN) + return 0; + proto = PPP_PROTOCOL(p); +#ifdef PPP_FILTER + p[0] = 1; /* outbound packet indicator */ + if ((pass_filter.bf_len != 0 + && bpf_filter(pass_filter.bf_insns, p, len, len) == 0) + || (active_filter.bf_len != 0 + && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) { + p[0] = 0xff; + return 0; + } + p[0] = 0xff; +#endif + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { + if (protp->active_pkt == NULL) + return 1; + return (*protp->active_pkt)(p, len); + } + } + return 0; /* not a supported protocol !!?? */ +} + +#endif /* PPP_SUPPORT && DEMAND_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eap.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eap.c new file mode 100644 index 0000000000..8fb56368e7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eap.c @@ -0,0 +1,2423 @@ +/* + * eap.c - Extensible Authentication Protocol for PPP (RFC 2284) + * + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Non-exclusive rights to redistribute, modify, translate, and use + * this software in source and binary forms, in whole or in part, is + * hereby granted, provided that the above copyright notice is + * duplicated in any source form, and that neither the name of the + * copyright holder nor the author is used to endorse or promote + * products derived from this software. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Original version by James Carlson + * + * This implementation of EAP supports MD5-Challenge and SRP-SHA1 + * authentication styles. Note that support of MD5-Challenge is a + * requirement of RFC 2284, and that it's essentially just a + * reimplementation of regular RFC 1994 CHAP using EAP messages. + * + * As an authenticator ("server"), there are multiple phases for each + * style. In the first phase of each style, the unauthenticated peer + * name is queried using the EAP Identity request type. If the + * "remotename" option is used, then this phase is skipped, because + * the peer's name is presumed to be known. + * + * For MD5-Challenge, there are two phases, and the second phase + * consists of sending the challenge itself and handling the + * associated response. + * + * For SRP-SHA1, there are four phases. The second sends 's', 'N', + * and 'g'. The reply contains 'A'. The third sends 'B', and the + * reply contains 'M1'. The forth sends the 'M2' value. + * + * As an authenticatee ("client"), there's just a single phase -- + * responding to the queries generated by the peer. EAP is an + * authenticator-driven protocol. + * + * Based on draft-ietf-pppext-eap-srp-03.txt. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/eap.h" +#include "netif/ppp/magic.h" +#include "netif/ppp/pppcrypt.h" + +#ifdef USE_SRP +#include +#include +#include +#endif /* USE_SRP */ + +#ifndef SHA_DIGESTSIZE +#define SHA_DIGESTSIZE 20 +#endif + +#ifdef USE_SRP +static char *pn_secret = NULL; /* Pseudonym generating secret */ +#endif + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t eap_option_list[] = { + { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, + "Set retransmit timeout for EAP Requests (server)" }, + { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, + "Set max number of EAP Requests sent (server)" }, + { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, + "Set time limit for peer EAP authentication" }, + { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, + "Set max number of EAP Requests allows (client)" }, + { "eap-interval", o_int, &eap_states[0].es_rechallenge, + "Set interval for EAP rechallenge" }, +#ifdef USE_SRP + { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, + "Set interval for SRP lightweight rechallenge" }, + { "srp-pn-secret", o_string, &pn_secret, + "Long term pseudonym generation secret" }, + { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, + "Use pseudonym if offered one by server", 1 }, +#endif + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points. + */ +static void eap_init(ppp_pcb *pcb); +static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen); +static void eap_protrej(ppp_pcb *pcb); +static void eap_lowerup(ppp_pcb *pcb); +static void eap_lowerdown(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int eap_printpkt(const u_char *inp, int inlen, + void (*)(void *arg, const char *fmt, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent eap_protent = { + PPP_EAP, /* protocol number */ + eap_init, /* initialization procedure */ + eap_input, /* process a received packet */ + eap_protrej, /* process a received protocol-reject */ + eap_lowerup, /* lower layer has gone up */ + eap_lowerdown, /* lower layer has gone down */ + NULL, /* open the protocol */ + NULL, /* close the protocol */ +#if PRINTPKT_SUPPORT + eap_printpkt, /* print a packet in readable form */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* process a received data packet */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "EAP", /* text name of protocol */ + NULL, /* text name of corresponding data protocol */ +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + eap_option_list, /* list of command-line options */ + NULL, /* check requested options; assign defaults */ +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, /* configure interface for demand-dial */ + NULL /* say whether to bring up link for this pkt */ +#endif /* DEMAND_SUPPORT */ +}; + +#ifdef USE_SRP +/* + * A well-known 2048 bit modulus. + */ +static const u_char wkmodulus[] = { + 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, + 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, + 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, + 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, + 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, + 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, + 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, + 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, + 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, + 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, + 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, + 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, + 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, + 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, + 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, + 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, + 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, + 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, + 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, + 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, + 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, + 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, + 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, + 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, + 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, + 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, + 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, + 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, + 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, + 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, + 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, + 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 +}; +#endif + +#if PPP_SERVER +/* Local forward declarations. */ +static void eap_server_timeout(void *arg); +#endif /* PPP_SERVER */ + +/* + * Convert EAP state code to printable string for debug. + */ +static const char * eap_state_name(enum eap_state_code esc) +{ + static const char *state_names[] = { EAP_STATES }; + + return (state_names[(int)esc]); +} + +/* + * eap_init - Initialize state for an EAP user. This is currently + * called once by main() during start-up. + */ +static void eap_init(ppp_pcb *pcb) { + + BZERO(&pcb->eap, sizeof(eap_state)); +#if PPP_SERVER + pcb->eap.es_server.ea_id = magic(); +#endif /* PPP_SERVER */ +} + +/* + * eap_client_timeout - Give up waiting for the peer to send any + * Request messages. + */ +static void eap_client_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (!eap_client_active(pcb)) + return; + + ppp_error("EAP: timeout waiting for Request from peer"); + auth_withpeer_fail(pcb, PPP_EAP); + pcb->eap.es_client.ea_state = eapBadAuth; +} + +/* + * eap_authwithpeer - Authenticate to our peer (behave as client). + * + * Start client state and wait for requests. This is called only + * after eap_lowerup. + */ +void eap_authwithpeer(ppp_pcb *pcb, const char *localname) { + + if(NULL == localname) + return; + + /* Save the peer name we're given */ + pcb->eap.es_client.ea_name = localname; + pcb->eap.es_client.ea_namelen = strlen(localname); + + pcb->eap.es_client.ea_state = eapListen; + + /* + * Start a timer so that if the other end just goes + * silent, we don't sit here waiting forever. + */ + if (pcb->settings.eap_req_time > 0) + TIMEOUT(eap_client_timeout, pcb, + pcb->settings.eap_req_time); +} + +#if PPP_SERVER +/* + * Format a standard EAP Failure message and send it to the peer. + * (Server operation) + */ +static void eap_send_failure(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_FAILURE, outp); + pcb->eap.es_server.ea_id++; + PUTCHAR(pcb->eap.es_server.ea_id, outp); + PUTSHORT(EAP_HEADERLEN, outp); + + ppp_write(pcb, p); + + pcb->eap.es_server.ea_state = eapBadAuth; + auth_peer_fail(pcb, PPP_EAP); +} + +/* + * Format a standard EAP Success message and send it to the peer. + * (Server operation) + */ +static void eap_send_success(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_SUCCESS, outp); + pcb->eap.es_server.ea_id++; + PUTCHAR(pcb->eap.es_server.ea_id, outp); + PUTSHORT(EAP_HEADERLEN, outp); + + ppp_write(pcb, p); + + auth_peer_success(pcb, PPP_EAP, 0, + pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); +} +#endif /* PPP_SERVER */ + +#ifdef USE_SRP +/* + * Set DES key according to pseudonym-generating secret and current + * date. + */ +static bool +pncrypt_setkey(int timeoffs) +{ + struct tm *tp; + char tbuf[9]; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + time_t reftime; + + if (pn_secret == NULL) + return (0); + reftime = time(NULL) + timeoffs; + tp = localtime(&reftime); + SHA1Init(&ctxt); + SHA1Update(&ctxt, pn_secret, strlen(pn_secret)); + strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); + SHA1Update(&ctxt, tbuf, strlen(tbuf)); + SHA1Final(dig, &ctxt); + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + return (DesSetkey(dig)); +} + +static char base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +struct b64state { + u32_t bs_bits; + int bs_offs; +}; + +static int +b64enc(bs, inp, inlen, outp) +struct b64state *bs; +u_char *inp; +int inlen; +u_char *outp; +{ + int outlen = 0; + + while (inlen > 0) { + bs->bs_bits = (bs->bs_bits << 8) | *inp++; + inlen--; + bs->bs_offs += 8; + if (bs->bs_offs >= 24) { + *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; + *outp++ = base64[bs->bs_bits & 0x3F]; + outlen += 4; + bs->bs_offs = 0; + bs->bs_bits = 0; + } + } + return (outlen); +} + +static int +b64flush(bs, outp) +struct b64state *bs; +u_char *outp; +{ + int outlen = 0; + + if (bs->bs_offs == 8) { + *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; + *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; + outlen = 2; + } else if (bs->bs_offs == 16) { + *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; + *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; + *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; + outlen = 3; + } + bs->bs_offs = 0; + bs->bs_bits = 0; + return (outlen); +} + +static int +b64dec(bs, inp, inlen, outp) +struct b64state *bs; +u_char *inp; +int inlen; +u_char *outp; +{ + int outlen = 0; + char *cp; + + while (inlen > 0) { + if ((cp = strchr(base64, *inp++)) == NULL) + break; + bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); + inlen--; + bs->bs_offs += 6; + if (bs->bs_offs >= 8) { + *outp++ = bs->bs_bits >> (bs->bs_offs - 8); + outlen++; + bs->bs_offs -= 8; + } + } + return (outlen); +} +#endif /* USE_SRP */ + +#if PPP_SERVER +/* + * Assume that current waiting server state is complete and figure + * next state to use based on available authentication data. 'status' + * indicates if there was an error in handling the last query. It is + * 0 for success and non-zero for failure. + */ +static void eap_figure_next_state(ppp_pcb *pcb, int status) { +#ifdef USE_SRP + unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp; + struct t_pw tpw; + struct t_confent *tce, mytce; + char *cp, *cp2; + struct t_server *ts; + int id, i, plen, toffs; + u_char vals[2]; + struct b64state bs; +#endif /* USE_SRP */ + + pcb->settings.eap_timeout_time = pcb->eap.es_savedtime; + switch (pcb->eap.es_server.ea_state) { + case eapBadAuth: + return; + + case eapIdentify: +#ifdef USE_SRP + /* Discard any previous session. */ + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0) { + pcb->eap.es_server.ea_state = eapBadAuth; + break; + } +#ifdef USE_SRP + /* If we've got a pseudonym, try to decode to real name. */ + if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN && + strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID, + SRP_PSEUDO_LEN) == 0 && + (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < + sizeof (secbuf)) { + BZERO(&bs, sizeof (bs)); + plen = b64dec(&bs, + pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN, + pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN, + secbuf); + toffs = 0; + for (i = 0; i < 5; i++) { + pncrypt_setkey(toffs); + toffs -= 86400; + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + if (!DesDecrypt(secbuf, clear)) { + ppp_dbglog("no DES here; cannot decode " + "pseudonym"); + return; + } + id = *(unsigned char *)clear; + if (id + 1 <= plen && id + 9 > plen) + break; + } + if (plen % 8 == 0 && i < 5) { + /* + * Note that this is always shorter than the + * original stored string, so there's no need + * to realloc. + */ + if ((i = plen = *(unsigned char *)clear) > 7) + i = 7; + pcb->eap.es_server.ea_peerlen = plen; + dp = (unsigned char *)pcb->eap.es_server.ea_peer; + MEMCPY(dp, clear + 1, i); + plen -= i; + dp += i; + sp = secbuf + 8; + while (plen > 0) { + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesDecrypt(sp, dp); + sp += 8; + dp += 8; + plen -= 8; + } + pcb->eap.es_server.ea_peer[ + pcb->eap.es_server.ea_peerlen] = '\0'; + ppp_dbglog("decoded pseudonym to \"%.*q\"", + pcb->eap.es_server.ea_peerlen, + pcb->eap.es_server.ea_peer); + } else { + ppp_dbglog("failed to decode real name"); + /* Stay in eapIdentfy state; requery */ + break; + } + } + /* Look up user in secrets database. */ + if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) { + /* Set up default in case SRP entry is bad */ + pcb->eap.es_server.ea_state = eapMD5Chall; + /* Get t_confent based on index in srp-secrets */ + id = strtol((char *)secbuf, &cp, 10); + if (*cp++ != ':' || id < 0) + break; + if (id == 0) { + mytce.index = 0; + mytce.modulus.data = (u_char *)wkmodulus; + mytce.modulus.len = sizeof (wkmodulus); + mytce.generator.data = (u_char *)"\002"; + mytce.generator.len = 1; + tce = &mytce; + } else if ((tce = gettcid(id)) != NULL) { + /* + * Client will have to verify this modulus/ + * generator combination, and that will take + * a while. Lengthen the timeout here. + */ + if (pcb->settings.eap_timeout_time > 0 && + pcb->settings.eap_timeout_time < 30) + pcb->settings.eap_timeout_time = 30; + } else { + break; + } + if ((cp2 = strchr(cp, ':')) == NULL) + break; + *cp2++ = '\0'; + tpw.pebuf.name = pcb->eap.es_server.ea_peer; + tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, + cp); + tpw.pebuf.password.data = tpw.pwbuf; + tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, + cp2); + tpw.pebuf.salt.data = tpw.saltbuf; + if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) + break; + pcb->eap.es_server.ea_session = (void *)ts; + pcb->eap.es_server.ea_state = eapSRP1; + vals[0] = pcb->eap.es_server.ea_id + 1; + vals[1] = EAPT_SRP; + t_serveraddexdata(ts, vals, 2); + /* Generate B; must call before t_servergetkey() */ + t_servergenexp(ts); + break; + } +#endif /* USE_SRP */ + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + + case eapSRP1: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status == 1) { + pcb->eap.es_server.ea_state = eapMD5Chall; + } else if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapSRP2; + } + break; + + case eapSRP2: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapSRP3; + } + break; + + case eapSRP3: + case eapSRP4: +#ifdef USE_SRP + ts = (struct t_server *)pcb->eap.es_server.ea_session; + if (ts != NULL && status != 0) { + t_serverclose(ts); + pcb->eap.es_server.ea_session = NULL; + pcb->eap.es_server.ea_skey = NULL; + } +#endif /* USE_SRP */ + if (status != 0 || pcb->eap.es_server.ea_session == NULL) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapOpen; + } + break; + + case eapMD5Chall: + if (status != 0) { + pcb->eap.es_server.ea_state = eapBadAuth; + } else { + pcb->eap.es_server.ea_state = eapOpen; + } + break; + + default: + pcb->eap.es_server.ea_state = eapBadAuth; + break; + } + if (pcb->eap.es_server.ea_state == eapBadAuth) + eap_send_failure(pcb); +} + +/* + * Format an EAP Request message and send it to the peer. Message + * type depends on current state. (Server operation) + */ +static void eap_send_request(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + u_char *lenloc; + int outlen; + int len; + const char *str; +#ifdef USE_SRP + struct t_server *ts; + u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; + int i, j; + struct b64state b64; + SHA1_CTX ctxt; +#endif /* USE_SRP */ + + /* Handle both initial auth and restart */ + if (pcb->eap.es_server.ea_state < eapIdentify && + pcb->eap.es_server.ea_state != eapInitial) { + pcb->eap.es_server.ea_state = eapIdentify; +#if PPP_REMOTENAME + if (pcb->settings.explicit_remote && pcb->remote_name) { + /* + * If we already know the peer's + * unauthenticated name, then there's no + * reason to ask. Go to next state instead. + */ + int len = (int)strlen(pcb->remote_name); + if (len > MAXNAMELEN) { + len = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_server.ea_peer, pcb->remote_name, len); + pcb->eap.es_server.ea_peer[len] = '\0'; + pcb->eap.es_server.ea_peerlen = len; + eap_figure_next_state(pcb, 0); + } +#endif /* PPP_REMOTENAME */ + } + + if (pcb->settings.eap_max_transmits > 0 && + pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) { + if (pcb->eap.es_server.ea_responses > 0) + ppp_error("EAP: too many Requests sent"); + else + ppp_error("EAP: no response to Requests"); + eap_send_failure(pcb); + return; + } + + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_REQUEST, outp); + PUTCHAR(pcb->eap.es_server.ea_id, outp); + lenloc = outp; + INCPTR(2, outp); + + switch (pcb->eap.es_server.ea_state) { + case eapIdentify: + PUTCHAR(EAPT_IDENTITY, outp); + str = "Name"; + len = strlen(str); + MEMCPY(outp, str, len); + INCPTR(len, outp); + break; + + case eapMD5Chall: + PUTCHAR(EAPT_MD5CHAP, outp); + /* + * pick a random challenge length between + * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH + */ + pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + + magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); + PUTCHAR(pcb->eap.es_challen, outp); + magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); + MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); + INCPTR(pcb->eap.es_challen, outp); + MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); + INCPTR(pcb->eap.es_server.ea_namelen, outp); + break; + +#ifdef USE_SRP + case eapSRP1: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_CHALLENGE, outp); + + PUTCHAR(pcb->eap.es_server.ea_namelen, outp); + MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); + INCPTR(pcb->eap.es_server.ea_namelen, outp); + + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + PUTCHAR(ts->s.len, outp); + MEMCPY(outp, ts->s.data, ts->s.len); + INCPTR(ts->s.len, outp); + + if (ts->g.len == 1 && ts->g.data[0] == 2) { + PUTCHAR(0, outp); + } else { + PUTCHAR(ts->g.len, outp); + MEMCPY(outp, ts->g.data, ts->g.len); + INCPTR(ts->g.len, outp); + } + + if (ts->n.len != sizeof (wkmodulus) || + BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) { + MEMCPY(outp, ts->n.data, ts->n.len); + INCPTR(ts->n.len, outp); + } + break; + + case eapSRP2: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_SKEY, outp); + + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + MEMCPY(outp, ts->B.data, ts->B.len); + INCPTR(ts->B.len, outp); + break; + + case eapSRP3: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_SVALIDATOR, outp); + PUTLONG(SRPVAL_EBIT, outp); + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE); + INCPTR(SHA_DIGESTSIZE, outp); + + if (pncrypt_setkey(0)) { + /* Generate pseudonym */ + optr = outp; + cp = (unsigned char *)pcb->eap.es_server.ea_peer; + if ((j = i = pcb->eap.es_server.ea_peerlen) > 7) + j = 7; + clear[0] = i; + MEMCPY(clear + 1, cp, j); + i -= j; + cp += j; + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + if (!DesEncrypt(clear, cipher)) { + ppp_dbglog("no DES here; not generating pseudonym"); + break; + } + BZERO(&b64, sizeof (b64)); + outp++; /* space for pseudonym length */ + outp += b64enc(&b64, cipher, 8, outp); + while (i >= 8) { + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesEncrypt(cp, cipher); + outp += b64enc(&b64, cipher, 8, outp); + cp += 8; + i -= 8; + } + if (i > 0) { + MEMCPY(clear, cp, i); + cp += i; + magic_random_bytes(cp, 8-i); + /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ + (void) DesEncrypt(clear, cipher); + outp += b64enc(&b64, cipher, 8, outp); + } + outp += b64flush(&b64, outp); + + /* Set length and pad out to next 20 octet boundary */ + i = outp - optr - 1; + *optr = i; + i %= SHA_DIGESTSIZE; + if (i != 0) { + magic_random_bytes(outp, SHA_DIGESTSIZE-i); + INCPTR(SHA_DIGESTSIZE-i, outp); + } + + /* Obscure the pseudonym with SHA1 hash */ + SHA1Init(&ctxt); + SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_peerlen); + while (optr < outp) { + SHA1Final(dig, &ctxt); + cp = dig; + while (cp < dig + SHA_DIGESTSIZE) + *optr++ ^= *cp++; + SHA1Init(&ctxt); + SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, optr - SHA_DIGESTSIZE, + SHA_DIGESTSIZE); + } + } + break; + + case eapSRP4: + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_LWRECHALLENGE, outp); + pcb->eap.es_challen = EAP_MIN_CHALLENGE_LENGTH + + magic_pow(EAP_MIN_MAX_POWER_OF_TWO_CHALLENGE_LENGTH); + magic_random_bytes(pcb->eap.es_challenge, pcb->eap.es_challen); + MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); + INCPTR(pcb->eap.es_challen, outp); + break; +#endif /* USE_SRP */ + + default: + return; + } + + outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN; + PUTSHORT(outlen, lenloc); + + pbuf_realloc(p, outlen + PPP_HDRLEN); + ppp_write(pcb, p); + + pcb->eap.es_server.ea_requests++; + + if (pcb->settings.eap_timeout_time > 0) + TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time); +} + +/* + * eap_authpeer - Authenticate our peer (behave as server). + * + * Start server state and send first request. This is called only + * after eap_lowerup. + */ +void eap_authpeer(ppp_pcb *pcb, const char *localname) { + + /* Save the name we're given. */ + pcb->eap.es_server.ea_name = localname; + pcb->eap.es_server.ea_namelen = strlen(localname); + + pcb->eap.es_savedtime = pcb->settings.eap_timeout_time; + + /* Lower layer up yet? */ + if (pcb->eap.es_server.ea_state == eapInitial || + pcb->eap.es_server.ea_state == eapPending) { + pcb->eap.es_server.ea_state = eapPending; + return; + } + + pcb->eap.es_server.ea_state = eapPending; + + /* ID number not updated here intentionally; hashed into M1 */ + eap_send_request(pcb); +} + +/* + * eap_server_timeout - Retransmission timer for sending Requests + * expired. + */ +static void eap_server_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (!eap_server_active(pcb)) + return; + + /* EAP ID number must not change on timeout. */ + eap_send_request(pcb); +} + +/* + * When it's time to send rechallenge the peer, this timeout is + * called. Once the rechallenge is successful, the response handler + * will restart the timer. If it fails, then the link is dropped. + */ +static void eap_rechallenge(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->eap.es_server.ea_state != eapOpen && + pcb->eap.es_server.ea_state != eapSRP4) + return; + + pcb->eap.es_server.ea_requests = 0; + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); +} + +static void srp_lwrechallenge(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->eap.es_server.ea_state != eapOpen || + pcb->eap.es_server.ea_type != EAPT_SRP) + return; + + pcb->eap.es_server.ea_requests = 0; + pcb->eap.es_server.ea_state = eapSRP4; + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); +} +#endif /* PPP_SERVER */ + +/* + * eap_lowerup - The lower layer is now up. + * + * This is called before either eap_authpeer or eap_authwithpeer. See + * link_established() in auth.c. All that's necessary here is to + * return to closed state so that those two routines will do the right + * thing. + */ +static void eap_lowerup(ppp_pcb *pcb) { + pcb->eap.es_client.ea_state = eapClosed; +#if PPP_SERVER + pcb->eap.es_server.ea_state = eapClosed; +#endif /* PPP_SERVER */ +} + +/* + * eap_lowerdown - The lower layer is now down. + * + * Cancel all timeouts and return to initial state. + */ +static void eap_lowerdown(ppp_pcb *pcb) { + + if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } +#if PPP_SERVER + if (eap_server_active(pcb)) { + if (pcb->settings.eap_timeout_time > 0) { + UNTIMEOUT(eap_server_timeout, pcb); + } + } else { + if ((pcb->eap.es_server.ea_state == eapOpen || + pcb->eap.es_server.ea_state == eapSRP4) && + pcb->eap.es_rechallenge > 0) { + UNTIMEOUT(eap_rechallenge, (void *)pcb); + } + if (pcb->eap.es_server.ea_state == eapOpen && + pcb->eap.es_lwrechallenge > 0) { + UNTIMEOUT(srp_lwrechallenge, (void *)pcb); + } + } + + pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial; + pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0; +#endif /* PPP_SERVER */ +} + +/* + * eap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen. If it does, it represents authentication + * failure. + */ +static void eap_protrej(ppp_pcb *pcb) { + + if (eap_client_active(pcb)) { + ppp_error("EAP authentication failed due to Protocol-Reject"); + auth_withpeer_fail(pcb, PPP_EAP); + } +#if PPP_SERVER + if (eap_server_active(pcb)) { + ppp_error("EAP authentication of peer failed on Protocol-Reject"); + auth_peer_fail(pcb, PPP_EAP); + } +#endif /* PPP_SERVER */ + eap_lowerdown(pcb); +} + +/* + * Format and send a regular EAP Response message. + */ +static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_char *str, int lenstr) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(typenum, outp); + if (lenstr > 0) { + MEMCPY(outp, str, lenstr); + } + + ppp_write(pcb, p); +} + +/* + * Format and send an MD5-Challenge EAP Response message. + */ +static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char *name, int namelen) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE + + namelen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_MD5CHAP, outp); + PUTCHAR(MD5_SIGNATURE_SIZE, outp); + MEMCPY(outp, hash, MD5_SIGNATURE_SIZE); + INCPTR(MD5_SIGNATURE_SIZE, outp); + if (namelen > 0) { + MEMCPY(outp, name, namelen); + } + + ppp_write(pcb, p); +} + +#ifdef USE_SRP +/* + * Format and send a SRP EAP Response message. + */ +static void +eap_srp_response(esp, id, subtypenum, str, lenstr) +eap_state *esp; +u_char id; +u_char subtypenum; +u_char *str; +int lenstr; +{ + ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(subtypenum, outp); + if (lenstr > 0) { + MEMCPY(outp, str, lenstr); + } + + ppp_write(pcb, p); +} + +/* + * Format and send a SRP EAP Client Validator Response message. + */ +static void +eap_srpval_response(esp, id, flags, str) +eap_state *esp; +u_char id; +u32_t flags; +u_char *str; +{ + ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) + + SHA_DIGESTSIZE; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_SRP, outp); + PUTCHAR(EAPSRP_CVALIDATOR, outp); + PUTLONG(flags, outp); + MEMCPY(outp, str, SHA_DIGESTSIZE); + + ppp_write(pcb, p); +} +#endif /* USE_SRP */ + +static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) { + struct pbuf *p; + u_char *outp; + int msglen; + + msglen = EAP_HEADERLEN + 2 * sizeof (u_char); + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + + MAKEHEADER(outp, PPP_EAP); + + PUTCHAR(EAP_RESPONSE, outp); + PUTCHAR(id, outp); + pcb->eap.es_client.ea_id = id; + PUTSHORT(msglen, outp); + PUTCHAR(EAPT_NAK, outp); + PUTCHAR(type, outp); + + ppp_write(pcb, p); +} + +#ifdef USE_SRP +static char * +name_of_pn_file() +{ + char *user, *path, *file; + struct passwd *pw; + size_t pl; + static bool pnlogged = 0; + + pw = getpwuid(getuid()); + if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) { + errno = EINVAL; + return (NULL); + } + file = _PATH_PSEUDONYM; + pl = strlen(user) + strlen(file) + 2; + path = malloc(pl); + if (path == NULL) + return (NULL); + (void) slprintf(path, pl, "%s/%s", user, file); + if (!pnlogged) { + ppp_dbglog("pseudonym file: %s", path); + pnlogged = 1; + } + return (path); +} + +static int +open_pn_file(modebits) +mode_t modebits; +{ + char *path; + int fd, err; + + if ((path = name_of_pn_file()) == NULL) + return (-1); + fd = open(path, modebits, S_IRUSR | S_IWUSR); + err = errno; + free(path); + errno = err; + return (fd); +} + +static void +remove_pn_file() +{ + char *path; + + if ((path = name_of_pn_file()) != NULL) { + (void) unlink(path); + (void) free(path); + } +} + +static void +write_pseudonym(esp, inp, len, id) +eap_state *esp; +u_char *inp; +int len, id; +{ + u_char val; + u_char *datp, *digp; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + int dsize, fd, olen = len; + + /* + * Do the decoding by working backwards. This eliminates the need + * to save the decoded output in a separate buffer. + */ + val = id; + while (len > 0) { + if ((dsize = len % SHA_DIGESTSIZE) == 0) + dsize = SHA_DIGESTSIZE; + len -= dsize; + datp = inp + len; + SHA1Init(&ctxt); + SHA1Update(&ctxt, &val, 1); + SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN); + if (len > 0) { + SHA1Update(&ctxt, datp, SHA_DIGESTSIZE); + } else { + SHA1Update(&ctxt, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + } + SHA1Final(dig, &ctxt); + for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++) + *datp++ ^= *digp; + } + + /* Now check that the result is sane */ + if (olen <= 0 || *inp + 1 > olen) { + ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); + return; + } + + /* Save it away */ + fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + ppp_dbglog("EAP: error saving pseudonym: %m"); + return; + } + len = write(fd, inp + 1, *inp); + if (close(fd) != -1 && len == *inp) { + ppp_dbglog("EAP: saved pseudonym"); + pcb->eap.es_usedpseudo = 0; + } else { + ppp_dbglog("EAP: failed to save pseudonym"); + remove_pn_file(); + } +} +#endif /* USE_SRP */ + +/* + * eap_request - Receive EAP Request message (client mode). + */ +static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char typenum; + u_char vallen; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[MAXNAMELEN]; + lwip_md5_context mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_SRP + struct t_client *tc; + struct t_num sval, gval, Nval, *Ap, Bval; + u_char vals[2]; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; + int fd; +#endif /* USE_SRP */ + + /* + * Note: we update es_client.ea_id *only if* a Response + * message is being generated. Otherwise, we leave it the + * same for duplicate detection purposes. + */ + + pcb->eap.es_client.ea_requests++; + if (pcb->settings.eap_allow_req != 0 && + pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) { + ppp_info("EAP: received too many Request messages"); + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + auth_withpeer_fail(pcb, PPP_EAP); + return; + } + + if (len <= 0) { + ppp_error("EAP: empty Request message discarded"); + return; + } + + GETCHAR(typenum, inp); + len--; + + switch (typenum) { + case EAPT_IDENTITY: + if (len > 0) + ppp_info("EAP: Identity prompt \"%.*q\"", len, inp); +#ifdef USE_SRP + if (pcb->eap.es_usepseudo && + (pcb->eap.es_usedpseudo == 0 || + (pcb->eap.es_usedpseudo == 1 && + id == pcb->eap.es_client.ea_id))) { + pcb->eap.es_usedpseudo = 1; + /* Try to get a pseudonym */ + if ((fd = open_pn_file(O_RDONLY)) >= 0) { + strcpy(rhostname, SRP_PSEUDO_ID); + len = read(fd, rhostname + SRP_PSEUDO_LEN, + sizeof (rhostname) - SRP_PSEUDO_LEN); + /* XXX NAI unsupported */ + if (len > 0) { + eap_send_response(pcb, id, typenum, + rhostname, len + SRP_PSEUDO_LEN); + } + (void) close(fd); + if (len > 0) + break; + } + } + /* Stop using pseudonym now. */ + if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) { + remove_pn_file(); + pcb->eap.es_usedpseudo = 2; + } +#endif /* USE_SRP */ + eap_send_response(pcb, id, typenum, (const u_char*)pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + break; + + case EAPT_NOTIFICATION: + if (len > 0) + ppp_info("EAP: Notification \"%.*q\"", len, inp); + eap_send_response(pcb, id, typenum, NULL, 0); + break; + + case EAPT_NAK: + /* + * Avoid the temptation to send Response Nak in reply + * to Request Nak here. It can only lead to trouble. + */ + ppp_warn("EAP: unexpected Nak in Request; ignored"); + /* Return because we're waiting for something real. */ + return; + + case EAPT_MD5CHAP: + if (len < 1) { + ppp_error("EAP: received MD5-Challenge with no data"); + /* Bogus request; wait for something real. */ + return; + } + GETCHAR(vallen, inp); + len--; + if (vallen < 8 || vallen > len) { + ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)", + vallen, len); + /* Try something better. */ + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + + /* Not so likely to happen. */ + if (vallen >= len + sizeof (rhostname)) { + ppp_dbglog("EAP: trimming really long peer name down"); + MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); + rhostname[sizeof (rhostname) - 1] = '\0'; + } else { + MEMCPY(rhostname, inp + vallen, len - vallen); + rhostname[len - vallen] = '\0'; + } + +#if PPP_REMOTENAME + /* In case the remote doesn't give us his name. */ + if (pcb->settings.explicit_remote || + (pcb->settings.remote_name[0] != '\0' && vallen == len)) + strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname)); +#endif /* PPP_REMOTENAME */ + + /* + * Get the secret for authenticating ourselves with + * the specified host. + */ + if (!get_secret(pcb, pcb->eap.es_client.ea_name, + rhostname, secret, &secret_len, 0)) { + ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname); + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + lwip_md5_init(&mdContext); + lwip_md5_starts(&mdContext); + typenum = id; + lwip_md5_update(&mdContext, &typenum, 1); + lwip_md5_update(&mdContext, (u_char *)secret, secret_len); + BZERO(secret, sizeof (secret)); + lwip_md5_update(&mdContext, inp, vallen); + lwip_md5_finish(&mdContext, hash); + lwip_md5_free(&mdContext); + eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + break; + +#ifdef USE_SRP + case EAPT_SRP: + if (len < 1) { + ppp_error("EAP: received empty SRP Request"); + /* Bogus request; wait for something real. */ + return; + } + + /* Get subtype */ + GETCHAR(vallen, inp); + len--; + switch (vallen) { + case EAPSRP_CHALLENGE: + tc = NULL; + if (pcb->eap.es_client.ea_session != NULL) { + tc = (struct t_client *)pcb->eap.es_client. + ea_session; + /* + * If this is a new challenge, then start + * over with a new client session context. + * Otherwise, just resend last response. + */ + if (id != pcb->eap.es_client.ea_id) { + t_clientclose(tc); + pcb->eap.es_client.ea_session = NULL; + tc = NULL; + } + } + /* No session key just yet */ + pcb->eap.es_client.ea_skey = NULL; + if (tc == NULL) { + int rhostnamelen; + + GETCHAR(vallen, inp); + len--; + if (vallen >= len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (name)"); + /* Ignore badly-formed messages */ + return; + } + MEMCPY(rhostname, inp, vallen); + rhostname[vallen] = '\0'; + INCPTR(vallen, inp); + len -= vallen; + + /* + * In case the remote doesn't give us his name, + * use configured name. + */ + if (explicit_remote || + (remote_name[0] != '\0' && vallen == 0)) { + strlcpy(rhostname, remote_name, + sizeof (rhostname)); + } + + rhostnamelen = (int)strlen(rhostname); + if (rhostnamelen > MAXNAMELEN) { + rhostnamelen = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_client.ea_peer, rhostname, rhostnamelen); + pcb->eap.es_client.ea_peer[rhostnamelen] = '\0'; + pcb->eap.es_client.ea_peerlen = rhostnamelen; + + GETCHAR(vallen, inp); + len--; + if (vallen >= len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (s)"); + /* Ignore badly-formed messages */ + return; + } + sval.data = inp; + sval.len = vallen; + INCPTR(vallen, inp); + len -= vallen; + + GETCHAR(vallen, inp); + len--; + if (vallen > len) { + ppp_error("EAP: badly-formed SRP Challenge" + " (g)"); + /* Ignore badly-formed messages */ + return; + } + /* If no generator present, then use value 2 */ + if (vallen == 0) { + gval.data = (u_char *)"\002"; + gval.len = 1; + } else { + gval.data = inp; + gval.len = vallen; + } + INCPTR(vallen, inp); + len -= vallen; + + /* + * If no modulus present, then use well-known + * value. + */ + if (len == 0) { + Nval.data = (u_char *)wkmodulus; + Nval.len = sizeof (wkmodulus); + } else { + Nval.data = inp; + Nval.len = len; + } + tc = t_clientopen(pcb->eap.es_client.ea_name, + &Nval, &gval, &sval); + if (tc == NULL) { + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + pcb->eap.es_client.ea_session = (void *)tc; + + /* Add Challenge ID & type to verifier */ + vals[0] = id; + vals[1] = EAPT_SRP; + t_clientaddexdata(tc, vals, 2); + } + Ap = t_clientgenexp(tc); + eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data, + Ap->len); + break; + + case EAPSRP_SKEY: + tc = (struct t_client *)pcb->eap.es_client.ea_session; + if (tc == NULL) { + ppp_warn("EAP: peer sent Subtype 2 without 1"); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + if (pcb->eap.es_client.ea_skey != NULL) { + /* + * ID number should not change here. Warn + * if it does (but otherwise ignore). + */ + if (id != pcb->eap.es_client.ea_id) { + ppp_warn("EAP: ID changed from %d to %d " + "in SRP Subtype 2 rexmit", + pcb->eap.es_client.ea_id, id); + } + } else { + if (get_srp_secret(pcb->eap.es_unit, + pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_peer, secret, 0) == 0) { + /* + * Can't work with this peer because + * the secret is missing. Just give + * up. + */ + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + Bval.data = inp; + Bval.len = len; + t_clientpasswd(tc, secret); + BZERO(secret, sizeof (secret)); + pcb->eap.es_client.ea_skey = + t_clientgetkey(tc, &Bval); + if (pcb->eap.es_client.ea_skey == NULL) { + /* Server is rogue; stop now */ + ppp_error("EAP: SRP server is rogue"); + goto client_failure; + } + } + eap_srpval_response(esp, id, SRPVAL_EBIT, + t_clientresponse(tc)); + break; + + case EAPSRP_SVALIDATOR: + tc = (struct t_client *)pcb->eap.es_client.ea_session; + if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) { + ppp_warn("EAP: peer sent Subtype 3 without 1/2"); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + /* + * If we're already open, then this ought to be a + * duplicate. Otherwise, check that the server is + * who we think it is. + */ + if (pcb->eap.es_client.ea_state == eapOpen) { + if (id != pcb->eap.es_client.ea_id) { + ppp_warn("EAP: ID changed from %d to %d " + "in SRP Subtype 3 rexmit", + pcb->eap.es_client.ea_id, id); + } + } else { + len -= sizeof (u32_t) + SHA_DIGESTSIZE; + if (len < 0 || t_clientverify(tc, inp + + sizeof (u32_t)) != 0) { + ppp_error("EAP: SRP server verification " + "failed"); + goto client_failure; + } + GETLONG(pcb->eap.es_client.ea_keyflags, inp); + /* Save pseudonym if user wants it. */ + if (len > 0 && pcb->eap.es_usepseudo) { + INCPTR(SHA_DIGESTSIZE, inp); + write_pseudonym(esp, inp, len, id); + } + } + /* + * We've verified our peer. We're now mostly done, + * except for waiting on the regular EAP Success + * message. + */ + eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0); + break; + + case EAPSRP_LWRECHALLENGE: + if (len < 4) { + ppp_warn("EAP: malformed Lightweight rechallenge"); + return; + } + SHA1Init(&ctxt); + vals[0] = id; + SHA1Update(&ctxt, vals, 1); + SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, inp, len); + SHA1Update(&ctxt, pcb->eap.es_client.ea_name, + pcb->eap.es_client.ea_namelen); + SHA1Final(dig, &ctxt); + eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, + SHA_DIGESTSIZE); + break; + + default: + ppp_error("EAP: unknown SRP Subtype %d", vallen); + eap_send_nak(pcb, id, EAPT_MD5CHAP); + break; + } + break; +#endif /* USE_SRP */ + + default: + ppp_info("EAP: unknown authentication type %d; Naking", typenum); + eap_send_nak(pcb, id, EAPT_SRP); + break; + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + TIMEOUT(eap_client_timeout, pcb, + pcb->settings.eap_req_time); + } + return; + +#ifdef USE_SRP +client_failure: + pcb->eap.es_client.ea_state = eapBadAuth; + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, (void *)esp); + } + pcb->eap.es_client.ea_session = NULL; + t_clientclose(tc); + auth_withpeer_fail(pcb, PPP_EAP); +#endif /* USE_SRP */ +} + +#if PPP_SERVER +/* + * eap_response - Receive EAP Response message (server mode). + */ +static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char typenum; + u_char vallen; + int secret_len; + char secret[MAXSECRETLEN]; + char rhostname[MAXNAMELEN]; + lwip_md5_context mdContext; + u_char hash[MD5_SIGNATURE_SIZE]; +#ifdef USE_SRP + struct t_server *ts; + struct t_num A; + SHA1_CTX ctxt; + u_char dig[SHA_DIGESTSIZE]; +#endif /* USE_SRP */ + + if (pcb->eap.es_server.ea_id != id) { + ppp_dbglog("EAP: discarding Response %d; expected ID %d", id, + pcb->eap.es_server.ea_id); + return; + } + + pcb->eap.es_server.ea_responses++; + + if (len <= 0) { + ppp_error("EAP: empty Response message discarded"); + return; + } + + GETCHAR(typenum, inp); + len--; + + switch (typenum) { + case EAPT_IDENTITY: + if (pcb->eap.es_server.ea_state != eapIdentify) { + ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len, + inp); + break; + } + ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp); + if (len > MAXNAMELEN) { + len = MAXNAMELEN; + } + MEMCPY(pcb->eap.es_server.ea_peer, inp, len); + pcb->eap.es_server.ea_peer[len] = '\0'; + pcb->eap.es_server.ea_peerlen = len; + eap_figure_next_state(pcb, 0); + break; + + case EAPT_NOTIFICATION: + ppp_dbglog("EAP unexpected Notification; response discarded"); + break; + + case EAPT_NAK: + if (len < 1) { + ppp_info("EAP: Nak Response with no suggested protocol"); + eap_figure_next_state(pcb, 1); + break; + } + + GETCHAR(vallen, inp); + len--; + + if ( +#if PPP_REMOTENAME + !pcb->explicit_remote && +#endif /* PPP_REMOTENAME */ + pcb->eap.es_server.ea_state == eapIdentify){ + /* Peer cannot Nak Identify Request */ + eap_figure_next_state(pcb, 1); + break; + } + + switch (vallen) { + case EAPT_SRP: + /* Run through SRP validator selection again. */ + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + break; + + case EAPT_MD5CHAP: + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + + default: + ppp_dbglog("EAP: peer requesting unknown Type %d", vallen); + switch (pcb->eap.es_server.ea_state) { + case eapSRP1: + case eapSRP2: + case eapSRP3: + pcb->eap.es_server.ea_state = eapMD5Chall; + break; + case eapMD5Chall: + case eapSRP4: + pcb->eap.es_server.ea_state = eapIdentify; + eap_figure_next_state(pcb, 0); + break; + default: + break; + } + break; + } + break; + + case EAPT_MD5CHAP: + if (pcb->eap.es_server.ea_state != eapMD5Chall) { + ppp_error("EAP: unexpected MD5-Response"); + eap_figure_next_state(pcb, 1); + break; + } + if (len < 1) { + ppp_error("EAP: received MD5-Response with no data"); + eap_figure_next_state(pcb, 1); + break; + } + GETCHAR(vallen, inp); + len--; + if (vallen != 16 || vallen > len) { + ppp_error("EAP: MD5-Response with bad length %d", vallen); + eap_figure_next_state(pcb, 1); + break; + } + + /* Not so likely to happen. */ + if (vallen >= len + sizeof (rhostname)) { + ppp_dbglog("EAP: trimming really long peer name down"); + MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); + rhostname[sizeof (rhostname) - 1] = '\0'; + } else { + MEMCPY(rhostname, inp + vallen, len - vallen); + rhostname[len - vallen] = '\0'; + } + +#if PPP_REMOTENAME + /* In case the remote doesn't give us his name. */ + if (explicit_remote || + (remote_name[0] != '\0' && vallen == len)) + strlcpy(rhostname, remote_name, sizeof (rhostname)); +#endif /* PPP_REMOTENAME */ + + /* + * Get the secret for authenticating the specified + * host. + */ + if (!get_secret(pcb, rhostname, + pcb->eap.es_server.ea_name, secret, &secret_len, 1)) { + ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname); + eap_send_failure(pcb); + break; + } + lwip_md5_init(&mdContext); + lwip_md5_starts(&mdContext); + lwip_md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1); + lwip_md5_update(&mdContext, (u_char *)secret, secret_len); + BZERO(secret, sizeof (secret)); + lwip_md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen); + lwip_md5_finish(&mdContext, hash); + lwip_md5_free(&mdContext); + if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) { + eap_send_failure(pcb); + break; + } + pcb->eap.es_server.ea_type = EAPT_MD5CHAP; + eap_send_success(pcb); + eap_figure_next_state(pcb, 0); + if (pcb->eap.es_rechallenge != 0) + TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge); + break; + +#ifdef USE_SRP + case EAPT_SRP: + if (len < 1) { + ppp_error("EAP: empty SRP Response"); + eap_figure_next_state(pcb, 1); + break; + } + GETCHAR(typenum, inp); + len--; + switch (typenum) { + case EAPSRP_CKEY: + if (pcb->eap.es_server.ea_state != eapSRP1) { + ppp_error("EAP: unexpected SRP Subtype 1 Response"); + eap_figure_next_state(pcb, 1); + break; + } + A.data = inp; + A.len = len; + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A); + if (pcb->eap.es_server.ea_skey == NULL) { + /* Client's A value is bogus; terminate now */ + ppp_error("EAP: bogus A value from client"); + eap_send_failure(pcb); + } else { + eap_figure_next_state(pcb, 0); + } + break; + + case EAPSRP_CVALIDATOR: + if (pcb->eap.es_server.ea_state != eapSRP2) { + ppp_error("EAP: unexpected SRP Subtype 2 Response"); + eap_figure_next_state(pcb, 1); + break; + } + if (len < sizeof (u32_t) + SHA_DIGESTSIZE) { + ppp_error("EAP: M1 length %d < %d", len, + sizeof (u32_t) + SHA_DIGESTSIZE); + eap_figure_next_state(pcb, 1); + break; + } + GETLONG(pcb->eap.es_server.ea_keyflags, inp); + ts = (struct t_server *)pcb->eap.es_server.ea_session; + assert(ts != NULL); + if (t_serververify(ts, inp)) { + ppp_info("EAP: unable to validate client identity"); + eap_send_failure(pcb); + break; + } + eap_figure_next_state(pcb, 0); + break; + + case EAPSRP_ACK: + if (pcb->eap.es_server.ea_state != eapSRP3) { + ppp_error("EAP: unexpected SRP Subtype 3 Response"); + eap_send_failure(esp); + break; + } + pcb->eap.es_server.ea_type = EAPT_SRP; + eap_send_success(pcb, esp); + eap_figure_next_state(pcb, 0); + if (pcb->eap.es_rechallenge != 0) + TIMEOUT(eap_rechallenge, pcb, + pcb->eap.es_rechallenge); + if (pcb->eap.es_lwrechallenge != 0) + TIMEOUT(srp_lwrechallenge, pcb, + pcb->eap.es_lwrechallenge); + break; + + case EAPSRP_LWRECHALLENGE: + if (pcb->eap.es_server.ea_state != eapSRP4) { + ppp_info("EAP: unexpected SRP Subtype 4 Response"); + return; + } + if (len != SHA_DIGESTSIZE) { + ppp_error("EAP: bad Lightweight rechallenge " + "response"); + return; + } + SHA1Init(&ctxt); + vallen = id; + SHA1Update(&ctxt, &vallen, 1); + SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, + SESSION_KEY_LEN); + SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen); + SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, + pcb->eap.es_server.ea_peerlen); + SHA1Final(dig, &ctxt); + if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { + ppp_error("EAP: failed Lightweight rechallenge"); + eap_send_failure(pcb); + break; + } + pcb->eap.es_server.ea_state = eapOpen; + if (pcb->eap.es_lwrechallenge != 0) + TIMEOUT(srp_lwrechallenge, esp, + pcb->eap.es_lwrechallenge); + break; + } + break; +#endif /* USE_SRP */ + + default: + /* This can't happen. */ + ppp_error("EAP: unknown Response type %d; ignored", typenum); + return; + } + + if (pcb->settings.eap_timeout_time > 0) { + UNTIMEOUT(eap_server_timeout, pcb); + } + + if (pcb->eap.es_server.ea_state != eapBadAuth && + pcb->eap.es_server.ea_state != eapOpen) { + pcb->eap.es_server.ea_id++; + eap_send_request(pcb); + } +} +#endif /* PPP_SERVER */ + +/* + * eap_success - Receive EAP Success message (client mode). + */ +static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { + LWIP_UNUSED_ARG(id); + + if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) { + ppp_dbglog("EAP unexpected success message in state %s (%d)", + eap_state_name(pcb->eap.es_client.ea_state), + pcb->eap.es_client.ea_state); + return; + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + + if (len > 0) { + /* This is odd. The spec doesn't allow for this. */ + PRINTMSG(inp, len); + } + + pcb->eap.es_client.ea_state = eapOpen; + auth_withpeer_success(pcb, PPP_EAP, 0); +} + +/* + * eap_failure - Receive EAP Failure message (client mode). + */ +static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { + LWIP_UNUSED_ARG(id); + + if (!eap_client_active(pcb)) { + ppp_dbglog("EAP unexpected failure message in state %s (%d)", + eap_state_name(pcb->eap.es_client.ea_state), + pcb->eap.es_client.ea_state); + } + + if (pcb->settings.eap_req_time > 0) { + UNTIMEOUT(eap_client_timeout, pcb); + } + + if (len > 0) { + /* This is odd. The spec doesn't allow for this. */ + PRINTMSG(inp, len); + } + + pcb->eap.es_client.ea_state = eapBadAuth; + + ppp_error("EAP: peer reports authentication failure"); + auth_withpeer_fail(pcb, PPP_EAP); +} + +/* + * eap_input - Handle received EAP message. + */ +static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { + u_char code, id; + int len; + + /* + * Parse header (code, id and length). If packet too short, + * drop it. + */ + if (inlen < EAP_HEADERLEN) { + ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < EAP_HEADERLEN || len > inlen) { + ppp_error("EAP: packet has illegal length field %d (%d..%d)", len, + EAP_HEADERLEN, inlen); + return; + } + len -= EAP_HEADERLEN; + + /* Dispatch based on message code */ + switch (code) { + case EAP_REQUEST: + eap_request(pcb, inp, id, len); + break; + +#if PPP_SERVER + case EAP_RESPONSE: + eap_response(pcb, inp, id, len); + break; +#endif /* PPP_SERVER */ + + case EAP_SUCCESS: + eap_success(pcb, inp, id, len); + break; + + case EAP_FAILURE: + eap_failure(pcb, inp, id, len); + break; + + default: /* XXX Need code reject */ + /* Note: it's not legal to send EAP Nak here. */ + ppp_warn("EAP: unknown code %d received", code); + break; + } +} + +#if PRINTPKT_SUPPORT +/* + * eap_printpkt - print the contents of an EAP packet. + */ +static const char* const eap_codenames[] = { + "Request", "Response", "Success", "Failure" +}; + +static const char* const eap_typenames[] = { + "Identity", "Notification", "Nak", "MD5-Challenge", + "OTP", "Generic-Token", NULL, NULL, + "RSA", "DSS", "KEA", "KEA-Validate", + "TLS", "Defender", "Windows 2000", "Arcot", + "Cisco", "Nokia", "SRP" +}; + +static int eap_printpkt(const u_char *inp, int inlen, void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, rtype, vallen; + const u_char *pstart; + u32_t uval; + + if (inlen < EAP_HEADERLEN) + return (0); + pstart = inp; + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < EAP_HEADERLEN || len > inlen) + return (0); + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(eap_codenames)) + printer(arg, " %s", eap_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= EAP_HEADERLEN; + switch (code) { + case EAP_REQUEST: + if (len < 1) { + printer(arg, " "); + break; + } + GETCHAR(rtype, inp); + len--; + if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " %s", eap_typenames[rtype-1]); + else + printer(arg, " type=0x%x", rtype); + switch (rtype) { + case EAPT_IDENTITY: + case EAPT_NOTIFICATION: + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_MD5CHAP: + if (len <= 0) + break; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_SRP: + if (len < 3) + goto truncated; + GETCHAR(vallen, inp); + len--; + printer(arg, "-%d", vallen); + switch (vallen) { + case EAPSRP_CHALLENGE: + GETCHAR(vallen, inp); + len--; + if (vallen >= len) + goto truncated; + if (vallen > 0) { + printer(arg, " "); + } else { + printer(arg, " "); + } + INCPTR(vallen, inp); + len -= vallen; + GETCHAR(vallen, inp); + len--; + if (vallen >= len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + if (vallen == 0) { + printer(arg, " "); + } else { + printer(arg, " ", vallen, inp); + } + INCPTR(vallen, inp); + len -= vallen; + if (len == 0) { + printer(arg, " "); + } else { + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPSRP_SKEY: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_SVALIDATOR: + if (len < (int)sizeof (u32_t)) + break; + GETLONG(uval, inp); + len -= sizeof (u32_t); + if (uval & SRPVAL_EBIT) { + printer(arg, " E"); + uval &= ~SRPVAL_EBIT; + } + if (uval != 0) { + printer(arg, " f<%X>", uval); + } + if ((vallen = len) > SHA_DIGESTSIZE) + vallen = SHA_DIGESTSIZE; + printer(arg, " ", len, inp, + len < SHA_DIGESTSIZE ? "?" : ""); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPSRP_LWRECHALLENGE: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + default: + break; + } + break; + default: + break; + } + break; + + case EAP_RESPONSE: + if (len < 1) + break; + GETCHAR(rtype, inp); + len--; + if (rtype >= 1 && rtype <= (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " %s", eap_typenames[rtype-1]); + else + printer(arg, " type=0x%x", rtype); + switch (rtype) { + case EAPT_IDENTITY: + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } + break; + + case EAPT_NAK: + if (len <= 0) { + printer(arg, " "); + break; + } + GETCHAR(rtype, inp); + len--; + printer(arg, " = 1 && rtype < (int)LWIP_ARRAYSIZE(eap_typenames)) + printer(arg, " (%s)", eap_typenames[rtype-1]); + printer(arg, ">"); + break; + + case EAPT_MD5CHAP: + if (len <= 0) { + printer(arg, " "); + break; + } + GETCHAR(vallen, inp); + len--; + if (vallen > len) + goto truncated; + printer(arg, " ", vallen, inp); + INCPTR(vallen, inp); + len -= vallen; + if (len > 0) { + printer(arg, " "); + INCPTR(len, inp); + len = 0; + } else { + printer(arg, " "); + } + break; + + case EAPT_SRP: + if (len < 1) + goto truncated; + GETCHAR(vallen, inp); + len--; + printer(arg, "-%d", vallen); + switch (vallen) { + case EAPSRP_CKEY: + printer(arg, " ", len, inp); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_CVALIDATOR: + if (len < (int)sizeof (u32_t)) + break; + GETLONG(uval, inp); + len -= sizeof (u32_t); + if (uval & SRPVAL_EBIT) { + printer(arg, " E"); + uval &= ~SRPVAL_EBIT; + } + if (uval != 0) { + printer(arg, " f<%X>", uval); + } + printer(arg, " ", len, inp, + len == SHA_DIGESTSIZE ? "" : "?"); + INCPTR(len, inp); + len = 0; + break; + + case EAPSRP_ACK: + break; + + case EAPSRP_LWRECHALLENGE: + printer(arg, " ", len, inp, + len == SHA_DIGESTSIZE ? "" : "?"); + if ((vallen = len) > SHA_DIGESTSIZE) + vallen = SHA_DIGESTSIZE; + INCPTR(vallen, inp); + len -= vallen; + break; + default: + break; + } + break; + default: + break; + } + break; + + case EAP_SUCCESS: /* No payload expected for these! */ + case EAP_FAILURE: + default: + break; + + truncated: + printer(arg, " "); + break; + } + + if (len > 8) + printer(arg, "%8B...", inp); + else if (len > 0) + printer(arg, "%.*B", len, inp); + INCPTR(len, inp); + + return (inp - pstart); +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && EAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ecp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ecp.c new file mode 100644 index 0000000000..4d84f60931 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ecp.c @@ -0,0 +1,191 @@ +/* + * ecp.c - PPP Encryption Control Protocol. + * + * Copyright (c) 2002 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from ccp.c, which is: + * + * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ecp.h" + +#if PPP_OPTIONS +static option_t ecp_option_list[] = { + { "noecp", o_bool, &ecp_protent.enabled_flag, + "Disable ECP negotiation" }, + { "-ecp", o_bool, &ecp_protent.enabled_flag, + "Disable ECP negotiation", OPT_ALIAS }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ecp_init (int unit); +/* +static void ecp_open (int unit); +static void ecp_close (int unit, char *); +static void ecp_lowerup (int unit); +static void ecp_lowerdown (int); +static void ecp_input (int unit, u_char *pkt, int len); +static void ecp_protrej (int unit); +*/ +#if PRINTPKT_SUPPORT +static int ecp_printpkt (const u_char *pkt, int len, + void (*printer) (void *, char *, ...), + void *arg); +#endif /* PRINTPKT_SUPPORT */ +/* +static void ecp_datainput (int unit, u_char *pkt, int len); +*/ + +const struct protent ecp_protent = { + PPP_ECP, + ecp_init, + NULL, /* ecp_input, */ + NULL, /* ecp_protrej, */ + NULL, /* ecp_lowerup, */ + NULL, /* ecp_lowerdown, */ + NULL, /* ecp_open, */ + NULL, /* ecp_close, */ +#if PRINTPKT_SUPPORT + ecp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, /* ecp_datainput, */ +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "ECP", + "Encrypted", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ecp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +fsm ecp_fsm[NUM_PPP]; +ecp_options ecp_wantoptions[NUM_PPP]; /* what to request the peer to use */ +ecp_options ecp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ +ecp_options ecp_allowoptions[NUM_PPP]; /* what we'll agree to do */ +ecp_options ecp_hisoptions[NUM_PPP]; /* what we agreed to do */ + +static const fsm_callbacks ecp_callbacks = { + NULL, /* ecp_resetci, */ + NULL, /* ecp_cilen, */ + NULL, /* ecp_addci, */ + NULL, /* ecp_ackci, */ + NULL, /* ecp_nakci, */ + NULL, /* ecp_rejci, */ + NULL, /* ecp_reqci, */ + NULL, /* ecp_up, */ + NULL, /* ecp_down, */ + NULL, + NULL, + NULL, + NULL, + NULL, /* ecp_extcode, */ + "ECP" +}; + +/* + * ecp_init - initialize ECP. + */ +static void +ecp_init(unit) + int unit; +{ + fsm *f = &ecp_fsm[unit]; + + f->unit = unit; + f->protocol = PPP_ECP; + f->callbacks = &ecp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(&ecp_wantoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_gotoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_allowoptions[unit], 0, sizeof(ecp_options)); + memset(&ecp_hisoptions[unit], 0, sizeof(ecp_options)); +#endif /* 0 */ + +} + + +#if PRINTPKT_SUPPORT +static int +ecp_printpkt(p, plen, printer, arg) + const u_char *p; + int plen; + void (*printer) (void *, char *, ...); + void *arg; +{ + return 0; +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && ECP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eui64.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eui64.c new file mode 100644 index 0000000000..01493bc1f8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/eui64.c @@ -0,0 +1,56 @@ +/* + * eui64.c - EUI64 routines for IPv6CP. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: eui64.c,v 1.6 2002/12/04 23:03:32 paulus Exp $ + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/eui64.h" + +/* + * eui64_ntoa - Make an ascii representation of an interface identifier + */ +char *eui64_ntoa(eui64_t e) { + static char buf[20]; + + sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x", + e.e8[0], e.e8[1], e.e8[2], e.e8[3], + e.e8[4], e.e8[5], e.e8[6], e.e8[7]); + return buf; +} + +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/fsm.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/fsm.c new file mode 100644 index 0000000000..81eba11602 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/fsm.c @@ -0,0 +1,799 @@ +/* + * fsm.c - {Link, IP} Control Protocol Finite State Machine. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + * Randomize fsm id on link/init. + * Deal with variable outgoing MTU. + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" + +static void fsm_timeout (void *); +static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len); +static void fsm_rconfack(fsm *f, int id, u_char *inp, int len); +static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len); +static void fsm_rtermreq(fsm *f, int id, u_char *p, int len); +static void fsm_rtermack(fsm *f); +static void fsm_rcoderej(fsm *f, u_char *inp, int len); +static void fsm_sconfreq(fsm *f, int retransmit); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + +/* + * fsm_init - Initialize fsm. + * + * Initialize fsm state. + */ +void fsm_init(fsm *f) { + ppp_pcb *pcb = f->pcb; + f->state = PPP_FSM_INITIAL; + f->flags = 0; + f->id = 0; /* XXX Start with random id? */ + f->maxnakloops = pcb->settings.fsm_max_nak_loops; + f->term_reason_len = 0; +} + + +/* + * fsm_lowerup - The lower layer is up. + */ +void fsm_lowerup(fsm *f) { + switch( f->state ){ + case PPP_FSM_INITIAL: + f->state = PPP_FSM_CLOSED; + break; + + case PPP_FSM_STARTING: + if( f->flags & OPT_SILENT ) + f->state = PPP_FSM_STOPPED; + else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + } + break; + + default: + FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_lowerdown - The lower layer is down. + * + * Cancel all timeouts and inform upper layers. + */ +void fsm_lowerdown(fsm *f) { + switch( f->state ){ + case PPP_FSM_CLOSED: + f->state = PPP_FSM_INITIAL; + break; + + case PPP_FSM_STOPPED: + f->state = PPP_FSM_STARTING; + if( f->callbacks->starting ) + (*f->callbacks->starting)(f); + break; + + case PPP_FSM_CLOSING: + f->state = PPP_FSM_INITIAL; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case PPP_FSM_STOPPING: + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + f->state = PPP_FSM_STARTING; + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + break; + + case PPP_FSM_OPENED: + if( f->callbacks->down ) + (*f->callbacks->down)(f); + f->state = PPP_FSM_STARTING; + break; + + default: + FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_open - Link is allowed to come up. + */ +void fsm_open(fsm *f) { + switch( f->state ){ + case PPP_FSM_INITIAL: + f->state = PPP_FSM_STARTING; + if( f->callbacks->starting ) + (*f->callbacks->starting)(f); + break; + + case PPP_FSM_CLOSED: + if( f->flags & OPT_SILENT ) + f->state = PPP_FSM_STOPPED; + else { + /* Send an initial configure-request */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + } + break; + + case PPP_FSM_CLOSING: + f->state = PPP_FSM_STOPPING; + /* fall through */ + /* no break */ + case PPP_FSM_STOPPED: + case PPP_FSM_OPENED: + if( f->flags & OPT_RESTART ){ + fsm_lowerdown(f); + fsm_lowerup(f); + } + break; + default: + break; + } +} + +/* + * terminate_layer - Start process of shutting down the FSM + * + * Cancel any timeout running, notify upper layers we're done, and + * send a terminate-request message as configured. + */ +static void terminate_layer(fsm *f, int nextstate) { + ppp_pcb *pcb = f->pcb; + + if( f->state != PPP_FSM_OPENED ) + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + else if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers we're down */ + + /* Init restart counter and send Terminate-Request */ + f->retransmits = pcb->settings.fsm_max_term_transmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (const u_char *) f->term_reason, f->term_reason_len); + + if (f->retransmits == 0) { + /* + * User asked for no terminate requests at all; just close it. + * We've already fired off one Terminate-Request just to be nice + * to the peer, but we're not going to wait for a reply. + */ + f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + return; + } + + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + --f->retransmits; + + f->state = nextstate; +} + +/* + * fsm_close - Start closing connection. + * + * Cancel timeouts and either initiate close or possibly go directly to + * the PPP_FSM_CLOSED state. + */ +void fsm_close(fsm *f, const char *reason) { + f->term_reason = reason; + f->term_reason_len = (reason == NULL? 0: LWIP_MIN(strlen(reason), 0xFF) ); + switch( f->state ){ + case PPP_FSM_STARTING: + f->state = PPP_FSM_INITIAL; + break; + case PPP_FSM_STOPPED: + f->state = PPP_FSM_CLOSED; + break; + case PPP_FSM_STOPPING: + f->state = PPP_FSM_CLOSING; + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + case PPP_FSM_OPENED: + terminate_layer(f, PPP_FSM_CLOSING); + break; + default: + break; + } +} + + +/* + * fsm_timeout - Timeout expired. + */ +static void fsm_timeout(void *arg) { + fsm *f = (fsm *) arg; + ppp_pcb *pcb = f->pcb; + + switch (f->state) { + case PPP_FSM_CLOSING: + case PPP_FSM_STOPPING: + if( f->retransmits <= 0 ){ + /* + * We've waited for an ack long enough. Peer probably heard us. + */ + f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + } else { + /* Send Terminate-Request */ + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (const u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + --f->retransmits; + } + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + if (f->retransmits <= 0) { + ppp_warn("%s: timeout sending Config-Requests", PROTO_NAME(f)); + f->state = PPP_FSM_STOPPED; + if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) + (*f->callbacks->finished)(f); + + } else { + /* Retransmit the configure-request */ + if (f->callbacks->retransmit) + (*f->callbacks->retransmit)(f); + fsm_sconfreq(f, 1); /* Re-send Configure-Request */ + if( f->state == PPP_FSM_ACKRCVD ) + f->state = PPP_FSM_REQSENT; + } + break; + + default: + FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_input - Input packet. + */ +void fsm_input(fsm *f, u_char *inpacket, int l) { + u_char *inp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (l < HEADERLEN) { + FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < HEADERLEN) { + FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); + return; + } + if (len > l) { + FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); + return; + } + len -= HEADERLEN; /* subtract header length */ + + if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ + FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", + f->protocol, f->state)); + return; + } + + /* + * Action depends on code. + */ + switch (code) { + case CONFREQ: + fsm_rconfreq(f, id, inp, len); + break; + + case CONFACK: + fsm_rconfack(f, id, inp, len); + break; + + case CONFNAK: + case CONFREJ: + fsm_rconfnakrej(f, code, id, inp, len); + break; + + case TERMREQ: + fsm_rtermreq(f, id, inp, len); + break; + + case TERMACK: + fsm_rtermack(f); + break; + + case CODEREJ: + fsm_rcoderej(f, inp, len); + break; + + default: + if( !f->callbacks->extcode + || !(*f->callbacks->extcode)(f, code, id, inp, len) ) + fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); + break; + } +} + + +/* + * fsm_rconfreq - Receive Configure-Request. + */ +static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { + int code, reject_if_disagree; + + switch( f->state ){ + case PPP_FSM_CLOSED: + /* Go away, we're closed */ + fsm_sdata(f, TERMACK, id, NULL, 0); + return; + case PPP_FSM_CLOSING: + case PPP_FSM_STOPPING: + return; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if( f->callbacks->down ) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_STOPPED: + /* Negotiation started by our peer */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } + + /* + * Pass the requested configuration options + * to protocol-specific code for checking. + */ + if (f->callbacks->reqci){ /* Check CI */ + reject_if_disagree = (f->nakloops >= f->maxnakloops); + code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); + } else if (len) + code = CONFREJ; /* Reject all CI */ + else + code = CONFACK; + + /* send the Ack, Nak or Rej to the peer */ + fsm_sdata(f, code, id, inp, len); + + if (code == CONFACK) { + if (f->state == PPP_FSM_ACKRCVD) { + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = PPP_FSM_OPENED; + if (f->callbacks->up) + (*f->callbacks->up)(f); /* Inform upper layers */ + } else + f->state = PPP_FSM_ACKSENT; + f->nakloops = 0; + + } else { + /* we sent CONFACK or CONFREJ */ + if (f->state != PPP_FSM_ACKRCVD) + f->state = PPP_FSM_REQSENT; + if( code == CONFNAK ) + ++f->nakloops; + } +} + + +/* + * fsm_rconfack - Receive Configure-Ack. + */ +static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + + if (id != f->reqid || f->seen_ack) /* Expected id? */ + return; /* Nope, toss... */ + if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): + (len == 0)) ){ + /* Ack is bad - ignore it */ + ppp_error("Received bad configure-ack: %P", inp, len); + return; + } + f->seen_ack = 1; + f->rnakloops = 0; + + switch (f->state) { + case PPP_FSM_CLOSED: + case PPP_FSM_STOPPED: + fsm_sdata(f, TERMACK, id, NULL, 0); + break; + + case PPP_FSM_REQSENT: + f->state = PPP_FSM_ACKRCVD; + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + break; + + case PPP_FSM_ACKRCVD: + /* Huh? an extra valid Ack? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + f->state = PPP_FSM_OPENED; + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + if (f->callbacks->up) + (*f->callbacks->up)(f); /* Inform upper layers */ + break; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + */ +static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { + int ret; + int treat_as_reject; + + if (id != f->reqid || f->seen_ack) /* Expected id? */ + return; /* Nope, toss... */ + + if (code == CONFNAK) { + ++f->rnakloops; + treat_as_reject = (f->rnakloops >= f->maxnakloops); + if (f->callbacks->nakci == NULL + || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { + ppp_error("Received bad configure-nak: %P", inp, len); + return; + } + } else { + f->rnakloops = 0; + if (f->callbacks->rejci == NULL + || !(ret = f->callbacks->rejci(f, inp, len))) { + ppp_error("Received bad configure-rej: %P", inp, len); + return; + } + } + + f->seen_ack = 1; + + switch (f->state) { + case PPP_FSM_CLOSED: + case PPP_FSM_STOPPED: + fsm_sdata(f, TERMACK, id, NULL, 0); + break; + + case PPP_FSM_REQSENT: + case PPP_FSM_ACKSENT: + /* They didn't agree to what we wanted - try another request */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + if (ret < 0) + f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ + else + fsm_sconfreq(f, 0); /* Send Configure-Request */ + break; + + case PPP_FSM_ACKRCVD: + /* Got a Nak/reject when we had already had an Ack?? oh well... */ + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_OPENED: + /* Go down and restart negotiation */ + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); /* Send initial Configure-Request */ + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rtermreq - Receive Terminate-Req. + */ +static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + + switch (f->state) { + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + f->state = PPP_FSM_REQSENT; /* Start over but keep trying */ + break; + + case PPP_FSM_OPENED: + if (len > 0) { + ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); + } else + ppp_info("%s terminated by peer", PROTO_NAME(f)); + f->retransmits = 0; + f->state = PPP_FSM_STOPPING; + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); + break; + default: + break; + } + + fsm_sdata(f, TERMACK, id, NULL, 0); +} + + +/* + * fsm_rtermack - Receive Terminate-Ack. + */ +static void fsm_rtermack(fsm *f) { + switch (f->state) { + case PPP_FSM_CLOSING: + UNTIMEOUT(fsm_timeout, f); + f->state = PPP_FSM_CLOSED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + case PPP_FSM_STOPPING: + UNTIMEOUT(fsm_timeout, f); + f->state = PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_ACKRCVD: + f->state = PPP_FSM_REQSENT; + break; + + case PPP_FSM_OPENED: + if (f->callbacks->down) + (*f->callbacks->down)(f); /* Inform upper layers */ + fsm_sconfreq(f, 0); + f->state = PPP_FSM_REQSENT; + break; + default: + break; + } +} + + +/* + * fsm_rcoderej - Receive an Code-Reject. + */ +static void fsm_rcoderej(fsm *f, u_char *inp, int len) { + u_char code, id; + + if (len < HEADERLEN) { + FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); + + if( f->state == PPP_FSM_ACKRCVD ) + f->state = PPP_FSM_REQSENT; +} + + +/* + * fsm_protreject - Peer doesn't speak this protocol. + * + * Treat this as a catastrophic error (RXJ-). + */ +void fsm_protreject(fsm *f) { + switch( f->state ){ + case PPP_FSM_CLOSING: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + /* no break */ + case PPP_FSM_CLOSED: + f->state = PPP_FSM_CLOSED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_STOPPING: + case PPP_FSM_REQSENT: + case PPP_FSM_ACKRCVD: + case PPP_FSM_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + /* no break */ + case PPP_FSM_STOPPED: + f->state = PPP_FSM_STOPPED; + if( f->callbacks->finished ) + (*f->callbacks->finished)(f); + break; + + case PPP_FSM_OPENED: + terminate_layer(f, PPP_FSM_STOPPING); + break; + + default: + FSMDEBUG(("%s: Protocol-reject event in state %d!", + PROTO_NAME(f), f->state)); + /* no break */ + } +} + + +/* + * fsm_sconfreq - Send a Configure-Request. + */ +static void fsm_sconfreq(fsm *f, int retransmit) { + ppp_pcb *pcb = f->pcb; + struct pbuf *p; + u_char *outp; + int cilen; + + if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){ + /* Not currently negotiating - reset options */ + if( f->callbacks->resetci ) + (*f->callbacks->resetci)(f); + f->nakloops = 0; + f->rnakloops = 0; + } + + if( !retransmit ){ + /* New request - reset retransmission counter, use new ID */ + f->retransmits = pcb->settings.fsm_max_conf_req_transmits; + f->reqid = ++f->id; + } + + f->seen_ack = 0; + + /* + * Make up the request packet + */ + if( f->callbacks->cilen && f->callbacks->addci ){ + cilen = (*f->callbacks->cilen)(f); + if( cilen > pcb->peer_mru - HEADERLEN ) + cilen = pcb->peer_mru - HEADERLEN; + } else + cilen = 0; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + /* send the request to our peer */ + outp = (u_char*)p->payload; + MAKEHEADER(outp, f->protocol); + PUTCHAR(CONFREQ, outp); + PUTCHAR(f->reqid, outp); + PUTSHORT(cilen + HEADERLEN, outp); + if (cilen != 0) { + (*f->callbacks->addci)(f, outp, &cilen); + LWIP_ASSERT("cilen == p->len - HEADERLEN - PPP_HDRLEN", cilen == p->len - HEADERLEN - PPP_HDRLEN); + } + + ppp_write(pcb, p); + + /* start the retransmit timer */ + --f->retransmits; + TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); +} + + +/* + * fsm_sdata - Send some data. + * + * Used for all packets sent to our peer by this module. + */ +void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen) { + ppp_pcb *pcb = f->pcb; + struct pbuf *p; + u_char *outp; + int outlen; + + /* Adjust length to be smaller than MTU */ + if (datalen > pcb->peer_mru - HEADERLEN) + datalen = pcb->peer_mru - HEADERLEN; + outlen = datalen + HEADERLEN; + + p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + if (datalen) /* && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ + MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); + MAKEHEADER(outp, f->protocol); + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + ppp_write(pcb, p); +} + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipcp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipcp.c new file mode 100644 index 0000000000..b7c766eb0b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipcp.c @@ -0,0 +1,2418 @@ +/* + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" + +#if 0 /* UNUSED */ +/* global vars */ +u32_t netmask = 0; /* IP netmask to set on interface */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ +#endif /* UNUSED */ + +#if 0 /* moved to ppp_settings */ +bool noremoteip = 0; /* Let him have no IP address */ +#endif /* moved to ppp_setting */ + +#if 0 /* UNUSED */ +/* Hook for a plugin to know when IP protocol has come up */ +void (*ip_up_hook) (void) = NULL; + +/* Hook for a plugin to know when IP protocol has come down */ +void (*ip_down_hook) (void) = NULL; + +/* Hook for a plugin to choose the remote IP address */ +void (*ip_choose_hook) (u32_t *) = NULL; +#endif /* UNUSED */ + +#if PPP_NOTIFY +/* Notifiers for when IPCP goes up and down */ +struct notifier *ip_up_notifier = NULL; +struct notifier *ip_down_notifier = NULL; +#endif /* PPP_NOTIFY */ + +/* local vars */ +#if 0 /* moved to ppp_pcb */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ +static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ +static int ipcp_is_up; /* have called np_up() */ +static int ipcp_is_open; /* haven't called np_finished() */ +static bool ask_for_local; /* request our address from peer */ +#endif /* moved to ppp_pcb */ +#if 0 /* UNUSED */ +static char vj_value[8]; /* string form of vj option value */ +static char netmask_str[20]; /* string form of netmask value */ +#endif /* UNUSED */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipcp_resetci(fsm *f); /* Reset our CI */ +static int ipcp_cilen(fsm *f); /* Return length of our CI */ +static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ +static int ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */ +static int ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ +static void ipcp_up(fsm *f); /* We're UP */ +static void ipcp_down(fsm *f); /* We're DOWN */ +static void ipcp_finished(fsm *f); /* Don't need lower layer */ + +static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ + ipcp_resetci, /* Reset our Configuration Information */ + ipcp_cilen, /* Length of our Configuration Information */ + ipcp_addci, /* Add our Configuration Information */ + ipcp_ackci, /* ACK our Configuration Information */ + ipcp_nakci, /* NAK our Configuration Information */ + ipcp_rejci, /* Reject our Configuration Information */ + ipcp_reqci, /* Request peer's Configuration Information */ + ipcp_up, /* Called when fsm reaches OPENED state */ + ipcp_down, /* Called when fsm leaves OPENED state */ + NULL, /* Called when we want the lower layer up */ + ipcp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPCP" /* String name of protocol */ +}; + +/* + * Command-line options. + */ +#if PPP_OPTIONS +static int setvjslots (char **); +static int setdnsaddr (char **); +static int setwinsaddr (char **); +static int setnetmask (char **); +int setipaddr (char *, char **, int); + +static void printipaddr (option_t *, void (*)(void *, char *,...),void *); + +static option_t ipcp_option_list[] = { + { "noip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP" }, + { "-ip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP", OPT_ALIAS }, + + { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, + { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, + &ipcp_allowoptions[0].neg_vj }, + + { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_A2CLR, + &ipcp_allowoptions[0].cflag }, + { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, + &ipcp_allowoptions[0].cflag }, + + { "vj-max-slots", o_special, (void *)setvjslots, + "Set maximum VJ header slots", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, + + { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, + "Accept peer's address for us", 1 }, + { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, + "Accept peer's address for it", 1 }, + + { "ipparam", o_string, &ipparam, + "Set ip script parameter", OPT_PRIO }, + + { "noipdefault", o_bool, &disable_defaultip, + "Don't use name for default IP adrs", 1 }, + + { "ms-dns", 1, (void *)setdnsaddr, + "DNS address for the peer's use" }, + { "ms-wins", 1, (void *)setwinsaddr, + "Nameserver for SMB over TCP/IP for peer" }, + + { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, + "Set timeout for IPCP", OPT_PRIO }, + { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, + "Set max #xmits for term-reqs", OPT_PRIO }, + { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, + "Set max #xmits for conf-reqs", OPT_PRIO }, + { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, + "Set max #conf-naks for IPCP", OPT_PRIO }, + + { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, + "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, + { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_A2CLR, + &ipcp_wantoptions[0].default_route }, + { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, + &ipcp_wantoptions[0].default_route }, + + { "replacedefaultroute", o_bool, + &ipcp_wantoptions[0].replace_default_route, + "Replace default route", 1 + }, + { "noreplacedefaultroute", o_bool, + &ipcp_allowoptions[0].replace_default_route, + "Never replace default route", OPT_A2COPY, + &ipcp_wantoptions[0].replace_default_route }, + { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, + "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, + { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, + "disable proxyarp option", OPT_A2CLR, + &ipcp_wantoptions[0].proxy_arp }, + { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, + "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, + &ipcp_wantoptions[0].proxy_arp }, + + { "usepeerdns", o_bool, &usepeerdns, + "Ask peer for DNS address(es)", 1 }, + + { "netmask", o_special, (void *)setnetmask, + "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, + + { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, + "Disable old-style IP-Addresses usage", OPT_A2CLR, + &ipcp_allowoptions[0].old_addrs }, + { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, + "Disable IP-Address usage", OPT_A2CLR, + &ipcp_allowoptions[0].neg_addr }, + + { "noremoteip", o_bool, &noremoteip, + "Allow peer to have no IP address", 1 }, + + { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr, + "Don't send our IP address to peer", OPT_A2CLR, + &ipcp_wantoptions[0].old_addrs}, + + { "IP addresses", o_wild, (void *) &setipaddr, + "set local and remote IP addresses", + OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ipcp_init(ppp_pcb *pcb); +static void ipcp_open(ppp_pcb *pcb); +static void ipcp_close(ppp_pcb *pcb, const char *reason); +static void ipcp_lowerup(ppp_pcb *pcb); +static void ipcp_lowerdown(ppp_pcb *pcb); +static void ipcp_input(ppp_pcb *pcb, u_char *p, int len); +static void ipcp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int ipcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS +static void ip_check_options (void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT +static int ip_demand_conf (int); +static int ip_active_pkt (u_char *, int); +#endif /* DEMAND_SUPPORT */ +#if 0 /* UNUSED */ +static void create_resolv (u32_t, u32_t); +#endif /* UNUSED */ + +const struct protent ipcp_protent = { + PPP_IPCP, + ipcp_init, + ipcp_input, + ipcp_protrej, + ipcp_lowerup, + ipcp_lowerdown, + ipcp_open, + ipcp_close, +#if PRINTPKT_SUPPORT + ipcp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "IPCP", + "IP", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ipcp_option_list, + ip_check_options, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + ip_demand_conf, + ip_active_pkt +#endif /* DEMAND_SUPPORT */ +}; + +static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute); + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID 2 +#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ +#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ +#define CILEN_ADDR 6 /* new-style single address option */ +#define CILEN_ADDRS 10 /* old-style dual address option */ + + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED, already defined by lwIP */ +/* + * Make a string representation of a network IP address. + */ +char * +ip_ntoa(ipaddr) +u32_t ipaddr; +{ + static char b[64]; + + slprintf(b, sizeof(b), "%I", ipaddr); + return b; +} +#endif /* UNUSED, already defined by lwIP */ + +/* + * Option parsing. + */ +#if PPP_OPTIONS +/* + * setvjslots - set maximum number of connection slots for VJ compression + */ +static int +setvjslots(argv) + char **argv; +{ + int value; + + if (!int_option(*argv, &value)) + return 0; + + if (value < 2 || value > 16) { + option_error("vj-max-slots value must be between 2 and 16"); + return 0; + } + ipcp_wantoptions [0].maxslotindex = + ipcp_allowoptions[0].maxslotindex = value - 1; + slprintf(vj_value, sizeof(vj_value), "%d", value); + return 1; +} + +/* + * setdnsaddr - set the dns address(es) + */ +static int +setdnsaddr(argv) + char **argv; +{ + u32_t dns; + struct hostent *hp; + + dns = inet_addr(*argv); + if (dns == (u32_t) -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-dns option", + *argv); + return 0; + } + dns = *(u32_t *)hp->h_addr; + } + + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].dnsaddr[1] == 0) + ipcp_allowoptions[0].dnsaddr[0] = dns; + else + ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; + + /* always set the secondary address value. */ + ipcp_allowoptions[0].dnsaddr[1] = dns; + + return (1); +} + +/* + * setwinsaddr - set the wins address(es) + * This is primrarly used with the Samba package under UNIX or for pointing + * the caller to the existing WINS server on a Windows NT platform. + */ +static int +setwinsaddr(argv) + char **argv; +{ + u32_t wins; + struct hostent *hp; + + wins = inet_addr(*argv); + if (wins == (u32_t) -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-wins option", + *argv); + return 0; + } + wins = *(u32_t *)hp->h_addr; + } + + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].winsaddr[1] == 0) + ipcp_allowoptions[0].winsaddr[0] = wins; + else + ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; + + /* always set the secondary address value. */ + ipcp_allowoptions[0].winsaddr[1] = wins; + + return (1); +} + +/* + * setipaddr - Set the IP address + * If doit is 0, the call is to check whether this option is + * potentially an IP address specification. + * Not static so that plugins can call it to set the addresses + */ +int +setipaddr(arg, argv, doit) + char *arg; + char **argv; + int doit; +{ + struct hostent *hp; + char *colon; + u32_t local, remote; + ipcp_options *wo = &ipcp_wantoptions[0]; + static int prio_local = 0, prio_remote = 0; + + /* + * IP address pair separated by ":". + */ + if ((colon = strchr(arg, ':')) == NULL) + return 0; + if (!doit) + return 1; + + /* + * If colon first character, then no local addr. + */ + if (colon != arg && option_priority >= prio_local) { + *colon = '\0'; + if ((local = inet_addr(arg)) == (u32_t) -1) { + if ((hp = gethostbyname(arg)) == NULL) { + option_error("unknown host: %s", arg); + return 0; + } + local = *(u32_t *)hp->h_addr; + } + if (bad_ip_adrs(local)) { + option_error("bad local IP address %s", ip_ntoa(local)); + return 0; + } + if (local != 0) + wo->ouraddr = local; + *colon = ':'; + prio_local = option_priority; + } + + /* + * If colon last character, then no remote addr. + */ + if (*++colon != '\0' && option_priority >= prio_remote) { + if ((remote = inet_addr(colon)) == (u32_t) -1) { + if ((hp = gethostbyname(colon)) == NULL) { + option_error("unknown host: %s", colon); + return 0; + } + remote = *(u32_t *)hp->h_addr; + if (remote_name[0] == 0) + strlcpy(remote_name, colon, sizeof(remote_name)); + } + if (bad_ip_adrs(remote)) { + option_error("bad remote IP address %s", ip_ntoa(remote)); + return 0; + } + if (remote != 0) + wo->hisaddr = remote; + prio_remote = option_priority; + } + + return 1; +} + +static void +printipaddr(opt, printer, arg) + option_t *opt; + void (*printer) (void *, char *, ...); + void *arg; +{ + ipcp_options *wo = &ipcp_wantoptions[0]; + + if (wo->ouraddr != 0) + printer(arg, "%I", wo->ouraddr); + printer(arg, ":"); + if (wo->hisaddr != 0) + printer(arg, "%I", wo->hisaddr); +} + +/* + * setnetmask - set the netmask to be used on the interface. + */ +static int +setnetmask(argv) + char **argv; +{ + u32_t mask; + int n; + char *p; + + /* + * Unfortunately, if we use inet_addr, we can't tell whether + * a result of all 1s is an error or a valid 255.255.255.255. + */ + p = *argv; + n = parse_dotted_ip(p, &mask); + + mask = lwip_htonl(mask); + + if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { + option_error("invalid netmask value '%s'", *argv); + return 0; + } + + netmask = mask; + slprintf(netmask_str, sizeof(netmask_str), "%I", mask); + + return (1); +} + +int +parse_dotted_ip(p, vp) + char *p; + u32_t *vp; +{ + int n; + u32_t v, b; + char *endp, *p0 = p; + + v = 0; + for (n = 3;; --n) { + b = strtoul(p, &endp, 0); + if (endp == p) + return 0; + if (b > 255) { + if (n < 3) + return 0; + /* accept e.g. 0xffffff00 */ + *vp = b; + return endp - p0; + } + v |= b << (n * 8); + p = endp; + if (n == 0) + break; + if (*p != '.') + return 0; + ++p; + } + *vp = v; + return p - p0; +} +#endif /* PPP_OPTIONS */ + +/* + * ipcp_init - Initialize IPCP. + */ +static void ipcp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_IPCP; + f->callbacks = &ipcp_callbacks; + fsm_init(f); + + /* + * Some 3G modems use repeated IPCP NAKs as a way of stalling + * until they can contact a server on the network, so we increase + * the default number of NAKs we accept before we start treating + * them as rejects. + */ + f->maxnakloops = 100; + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); +#endif /* 0 */ + + wo->neg_addr = wo->old_addrs = 1; +#if VJ_SUPPORT + wo->neg_vj = 1; + wo->vj_protocol = IPCP_VJ_COMP; + wo->maxslotindex = MAX_STATES - 1; /* really max index */ + wo->cflag = 1; +#endif /* VJ_SUPPORT */ + +#if 0 /* UNUSED */ + /* wanting default route by default */ + wo->default_route = 1; +#endif /* UNUSED */ + + ao->neg_addr = ao->old_addrs = 1; +#if VJ_SUPPORT + /* max slots and slot-id compression are currently hardwired in */ + /* ppp_if.c to 16 and 1, this needs to be changed (among other */ + /* things) gmc */ + + ao->neg_vj = 1; + ao->maxslotindex = MAX_STATES - 1; + ao->cflag = 1; +#endif /* #if VJ_SUPPORT */ + +#if 0 /* UNUSED */ + /* + * XXX These control whether the user may use the proxyarp + * and defaultroute options. + */ + ao->proxy_arp = 1; + ao->default_route = 1; +#endif /* UNUSED */ +} + + +/* + * ipcp_open - IPCP is allowed to come up. + */ +static void ipcp_open(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_open(f); + pcb->ipcp_is_open = 1; +} + + +/* + * ipcp_close - Take IPCP down. + */ +static void ipcp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->ipcp_fsm; + fsm_close(f, reason); +} + + +/* + * ipcp_lowerup - The lower layer is up. + */ +static void ipcp_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerup(f); +} + + +/* + * ipcp_lowerdown - The lower layer is down. + */ +static void ipcp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerdown(f); +} + + +/* + * ipcp_input - Input IPCP packet. + */ +static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->ipcp_fsm; + fsm_input(f, p, len); +} + + +/* + * ipcp_protrej - A Protocol-Reject was received for IPCP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void ipcp_protrej(ppp_pcb *pcb) { + fsm *f = &pcb->ipcp_fsm; + fsm_lowerdown(f); +} + + +/* + * ipcp_resetci - Reset our CI. + * Called by fsm_sconfreq, Send Configure Request. + */ +static void ipcp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + + wo->req_addr = (wo->neg_addr || wo->old_addrs) && + (ao->neg_addr || ao->old_addrs); + if (wo->ouraddr == 0) + wo->accept_local = 1; + if (wo->hisaddr == 0) + wo->accept_remote = 1; +#if LWIP_DNS + wo->req_dns1 = wo->req_dns2 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */ +#endif /* LWIP_DNS */ + *go = *wo; + if (!pcb->ask_for_local) + go->ouraddr = 0; +#if 0 /* UNUSED */ + if (ip_choose_hook) { + ip_choose_hook(&wo->hisaddr); + if (wo->hisaddr) { + wo->accept_remote = 0; + } + } +#endif /* UNUSED */ + BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options)); +} + + +/* + * ipcp_cilen - Return length of our CI. + * Called by fsm_sconfreq, Send Configure Request. + */ +static int ipcp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; +#if VJ_SUPPORT + ipcp_options *wo = &pcb->ipcp_wantoptions; +#endif /* VJ_SUPPORT */ + ipcp_options *ho = &pcb->ipcp_hisoptions; + +#define LENCIADDRS(neg) (neg ? CILEN_ADDRS : 0) +#if VJ_SUPPORT +#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) +#endif /* VJ_SUPPORT */ +#define LENCIADDR(neg) (neg ? CILEN_ADDR : 0) +#if LWIP_DNS +#define LENCIDNS(neg) LENCIADDR(neg) +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ +#define LENCIWINS(neg) LENCIADDR(neg) +#endif /* UNUSED - WINS */ + + /* + * First see if we want to change our options to the old + * forms because we have received old forms from the peer. + */ + if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs) + go->neg_addr = 0; + +#if VJ_SUPPORT + if (wo->neg_vj && !go->neg_vj && !go->old_vj) { + /* try an older style of VJ negotiation */ + /* use the old style only if the peer did */ + if (ho->neg_vj && ho->old_vj) { + go->neg_vj = 1; + go->old_vj = 1; + go->vj_protocol = ho->vj_protocol; + } + } +#endif /* VJ_SUPPORT */ + + return (LENCIADDRS(!go->neg_addr && go->old_addrs) + +#if VJ_SUPPORT + LENCIVJ(go->neg_vj, go->old_vj) + +#endif /* VJ_SUPPORT */ + LENCIADDR(go->neg_addr) + +#if LWIP_DNS + LENCIDNS(go->req_dns1) + + LENCIDNS(go->req_dns2) + +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + LENCIWINS(go->winsaddr[0]) + + LENCIWINS(go->winsaddr[1]) + +#endif /* UNUSED - WINS */ + 0); +} + + +/* + * ipcp_addci - Add our desired CIs to a packet. + * Called by fsm_sconfreq, Send Configure Request. + */ +static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + int len = *lenp; + +#define ADDCIADDRS(opt, neg, val1, val2) \ + if (neg) { \ + if (len >= CILEN_ADDRS) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDRS, ucp); \ + l = lwip_ntohl(val1); \ + PUTLONG(l, ucp); \ + l = lwip_ntohl(val2); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDRS; \ + } else \ + go->old_addrs = 0; \ + } + +#if VJ_SUPPORT +#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ + if (neg) { \ + int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ + if (len >= vjlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(vjlen, ucp); \ + PUTSHORT(val, ucp); \ + if (!old) { \ + PUTCHAR(maxslotindex, ucp); \ + PUTCHAR(cflag, ucp); \ + } \ + len -= vjlen; \ + } else \ + neg = 0; \ + } +#endif /* VJ_SUPPORT */ + +#define ADDCIADDR(opt, neg, val) \ + if (neg) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(val); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + neg = 0; \ + } + +#if LWIP_DNS +#define ADDCIDNS(opt, neg, addr) \ + if (neg) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(addr); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + neg = 0; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define ADDCIWINS(opt, addr) \ + if (addr) { \ + if (len >= CILEN_ADDR) { \ + u32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_ADDR, ucp); \ + l = lwip_ntohl(addr); \ + PUTLONG(l, ucp); \ + len -= CILEN_ADDR; \ + } else \ + addr = 0; \ + } +#endif /* UNUSED - WINS */ + + ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, + go->hisaddr); + +#if VJ_SUPPORT + ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); + +#if LWIP_DNS + ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + *lenp -= len; +} + + +/* + * ipcp_ackci - Ack our CIs. + * Called by fsm_rconfack, Receive Configure ACK. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int ipcp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_short cilen, citype; + u32_t cilong; +#if VJ_SUPPORT + u_short cishort; + u_char cimaxslotindex, cicflag; +#endif /* VJ_SUPPORT */ + + /* + * CIs must be in exactly the same order that we sent... + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ + +#define ACKCIADDRS(opt, neg, val1, val2) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDRS) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDRS || \ + citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val1 != cilong) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val2 != cilong) \ + goto bad; \ + } + +#if VJ_SUPPORT +#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ + if (neg) { \ + int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ + if ((len -= vjlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != vjlen || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + if (!old) { \ + GETCHAR(cimaxslotindex, p); \ + if (cimaxslotindex != maxslotindex) \ + goto bad; \ + GETCHAR(cicflag, p); \ + if (cicflag != cflag) \ + goto bad; \ + } \ + } +#endif /* VJ_SUPPORT */ + +#define ACKCIADDR(opt, neg, val) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || \ + citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (val != cilong) \ + goto bad; \ + } + +#if LWIP_DNS +#define ACKCIDNS(opt, neg, addr) \ + if (neg) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (addr != cilong) \ + goto bad; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define ACKCIWINS(opt, addr) \ + if (addr) { \ + u32_t l; \ + if ((len -= CILEN_ADDR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_ADDR || citype != opt) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + if (addr != cilong) \ + goto bad; \ + } +#endif /* UNUSED - WINS */ + + ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, + go->hisaddr); + +#if VJ_SUPPORT + ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); + +#if LWIP_DNS + ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + + ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); + +bad: + IPCPDEBUG(("ipcp_ackci: received bad Ack!")); + return (0); +} + +/* + * ipcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPCP is in the OPENED state. + * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_char citype, cilen, *next; +#if VJ_SUPPORT + u_char cimaxslotindex, cicflag; + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t ciaddr1, ciaddr2, l; +#if LWIP_DNS + u32_t cidnsaddr; +#endif /* LWIP_DNS */ + ipcp_options no; /* options we've seen Naks for */ + ipcp_options try_; /* options to request next time */ + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIADDRS(opt, neg, code) \ + if ((neg) && \ + (cilen = p[1]) == CILEN_ADDRS && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciaddr1 = lwip_htonl(l); \ + GETLONG(l, p); \ + ciaddr2 = lwip_htonl(l); \ + no.old_addrs = 1; \ + code \ + } + +#if VJ_SUPPORT +#define NAKCIVJ(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#endif /* VJ_SUPPORT */ + +#define NAKCIADDR(opt, neg, code) \ + if (go->neg && \ + (cilen = p[1]) == CILEN_ADDR && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciaddr1 = lwip_htonl(l); \ + no.neg = 1; \ + code \ + } + +#if LWIP_DNS +#define NAKCIDNS(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cidnsaddr = lwip_htonl(l); \ + no.neg = 1; \ + code \ + } +#endif /* LWIP_DNS */ + + /* + * Accept the peer's idea of {our,his} address, if different + * from our idea, only if the accept_{local,remote} flag is set. + */ + NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, + if (treat_as_reject) { + try_.old_addrs = 0; + } else { + if (go->accept_local && ciaddr1) { + /* take his idea of our address */ + try_.ouraddr = ciaddr1; + } + if (go->accept_remote && ciaddr2) { + /* take his idea of his address */ + try_.hisaddr = ciaddr2; + } + } + ); + +#if VJ_SUPPORT + /* + * Accept the peer's value of maxslotindex provided that it + * is less than what we asked for. Turn off slot-ID compression + * if the peer wants. Send old-style compress-type option if + * the peer wants. + */ + NAKCIVJ(CI_COMPRESSTYPE, neg_vj, + if (treat_as_reject) { + try_.neg_vj = 0; + } else if (cilen == CILEN_VJ) { + GETCHAR(cimaxslotindex, p); + GETCHAR(cicflag, p); + if (cishort == IPCP_VJ_COMP) { + try_.old_vj = 0; + if (cimaxslotindex < go->maxslotindex) + try_.maxslotindex = cimaxslotindex; + if (!cicflag) + try_.cflag = 0; + } else { + try_.neg_vj = 0; + } + } else { + if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { + try_.old_vj = 1; + try_.vj_protocol = cishort; + } else { + try_.neg_vj = 0; + } + } + ); +#endif /* VJ_SUPPORT */ + + NAKCIADDR(CI_ADDR, neg_addr, + if (treat_as_reject) { + try_.neg_addr = 0; + try_.old_addrs = 0; + } else if (go->accept_local && ciaddr1) { + /* take his idea of our address */ + try_.ouraddr = ciaddr1; + } + ); + +#if LWIP_DNS + NAKCIDNS(CI_MS_DNS1, req_dns1, + if (treat_as_reject) { + try_.req_dns1 = 0; + } else { + try_.dnsaddr[0] = cidnsaddr; + } + ); + + NAKCIDNS(CI_MS_DNS2, req_dns2, + if (treat_as_reject) { + try_.req_dns2 = 0; + } else { + try_.dnsaddr[1] = cidnsaddr; + } + ); +#endif /* #if LWIP_DNS */ + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If they want to negotiate about IP addresses, we comply. + * If they want us to ask for compression, we refuse. + * If they want us to ask for ms-dns, we do that, since some + * peers get huffy if we don't. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) + goto bad; + next = p + cilen - 2; + + switch (citype) { +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (go->neg_vj || no.neg_vj || + (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) + goto bad; + no.neg_vj = 1; + break; +#endif /* VJ_SUPPORT */ + case CI_ADDRS: + if ((!go->neg_addr && go->old_addrs) || no.old_addrs + || cilen != CILEN_ADDRS) + goto bad; + try_.neg_addr = 0; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1 && go->accept_local) + try_.ouraddr = ciaddr1; + GETLONG(l, p); + ciaddr2 = lwip_htonl(l); + if (ciaddr2 && go->accept_remote) + try_.hisaddr = ciaddr2; + no.old_addrs = 1; + break; + case CI_ADDR: + if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) + goto bad; + try_.old_addrs = 0; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1 && go->accept_local) + try_.ouraddr = ciaddr1; + if (try_.ouraddr != 0) + try_.neg_addr = 1; + no.neg_addr = 1; + break; +#if LWIP_DNS + case CI_MS_DNS1: + if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + try_.dnsaddr[0] = lwip_htonl(l); + try_.req_dns1 = 1; + no.req_dns1 = 1; + break; + case CI_MS_DNS2: + if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + try_.dnsaddr[1] = lwip_htonl(l); + try_.req_dns2 = 1; + no.req_dns2 = 1; + break; +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + if (cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + ciaddr1 = lwip_htonl(l); + if (ciaddr1) + try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1; + break; +#endif /* UNUSED - WINS */ + default: + break; + } + p = next; + } + + /* + * OK, the Nak is good. Now we can update state. + * If there are any remaining options, we ignore them. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; + +bad: + IPCPDEBUG(("ipcp_nakci: received bad Nak!")); + return 0; +} + + +/* + * ipcp_rejci - Reject some of our CIs. + * Callback from fsm_rconfnakrej. + */ +static int ipcp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipcp_options *go = &pcb->ipcp_gotoptions; + u_char cilen; +#if VJ_SUPPORT + u_char cimaxslotindex, ciflag; + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t cilong; + ipcp_options try_; /* options to request next time */ + + try_ = *go; + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIADDRS(opt, neg, val1, val2) \ + if ((neg) && \ + (cilen = p[1]) == CILEN_ADDRS && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val1) \ + goto bad; \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val2) \ + goto bad; \ + try_.old_addrs = 0; \ + } + +#if VJ_SUPPORT +#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ + if (go->neg && \ + p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ + len >= p[1] && \ + p[0] == opt) { \ + len -= p[1]; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + if (!old) { \ + GETCHAR(cimaxslotindex, p); \ + if (cimaxslotindex != maxslot) \ + goto bad; \ + GETCHAR(ciflag, p); \ + if (ciflag != cflag) \ + goto bad; \ + } \ + try_.neg = 0; \ + } +#endif /* VJ_SUPPORT */ + +#define REJCIADDR(opt, neg, val) \ + if (go->neg && \ + (cilen = p[1]) == CILEN_ADDR && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } + +#if LWIP_DNS +#define REJCIDNS(opt, neg, dnsaddr) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != dnsaddr) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ +#define REJCIWINS(opt, addr) \ + if (addr && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + u32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = lwip_htonl(l); \ + /* Check rejected value. */ \ + if (cilong != addr) \ + goto bad; \ + try_.winsaddr[opt == CI_MS_WINS2] = 0; \ + } +#endif /* UNUSED - WINS */ + + REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, + go->ouraddr, go->hisaddr); + +#if VJ_SUPPORT + REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, + go->maxslotindex, go->cflag); +#endif /* VJ_SUPPORT */ + + REJCIADDR(CI_ADDR, neg_addr, go->ouraddr); + +#if LWIP_DNS + REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + + REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); + + REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); +#endif /* UNUSED - WINS */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + IPCPDEBUG(("ipcp_rejci: received bad Reject!")); + return 0; +} + + +/* + * ipcp_reqci - Check the peer's requested CIs and send appropriate response. + * Callback from fsm_rconfreq, Receive Configure Request + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * len = Length of requested CIs + */ +static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + ipcp_options *wo = &pcb->ipcp_wantoptions; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *ao = &pcb->ipcp_allowoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ +#if VJ_SUPPORT + u_short cishort; /* Parsed short value */ +#endif /* VJ_SUPPORT */ + u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *ucp = inp; /* Pointer to current output char */ + int l = *len; /* Length left */ +#if VJ_SUPPORT + u_char maxslotindex, cflag; +#endif /* VJ_SUPPORT */ +#if LWIP_DNS + int d; +#endif /* LWIP_DNS */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + IPCPDEBUG(("ipcp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_ADDRS: + if (!ao->old_addrs || ho->neg_addr || + cilen != CILEN_ADDRS) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = lwip_htonl(tl); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * If neither we nor he knows his address, reject the option. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + /* + * If he doesn't know our address, or if we both have our address + * but disagree about it, then NAK it with our idea. + */ + GETLONG(tl, p); /* Parse desination address (ours) */ + ciaddr2 = lwip_htonl(tl); + if (ciaddr2 != wo->ouraddr) { + if (ciaddr2 == 0 || !wo->accept_local) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->ouraddr); + PUTLONG(tl, p); + } + } else { + wo->ouraddr = ciaddr2; /* accept peer's idea */ + } + } + + ho->old_addrs = 1; + ho->hisaddr = ciaddr1; + ho->ouraddr = ciaddr2; + break; + + case CI_ADDR: + if (!ao->neg_addr || ho->old_addrs || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no address, or if we both have his address but + * disagree about it, then NAK it with our idea. + * In particular, if we don't know his address, but he does, + * then accept it. + */ + GETLONG(tl, p); /* Parse source address (his) */ + ciaddr1 = lwip_htonl(tl); + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, p); + } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * Don't ACK an address of 0.0.0.0 - reject it instead. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; + } + + ho->neg_addr = 1; + ho->hisaddr = ciaddr1; + break; + +#if LWIP_DNS + case CI_MS_DNS1: + case CI_MS_DNS2: + /* Microsoft primary or secondary DNS request */ + d = citype == CI_MS_DNS2; + + /* If we do not have a DNS address then we cannot send it */ + if (ao->dnsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (lwip_htonl(tl) != ao->dnsaddr[d]) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(ao->dnsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; +#endif /* LWIP_DNS */ + +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + /* Microsoft primary or secondary WINS request */ + d = citype == CI_MS_WINS2; + + /* If we do not have a DNS address then we cannot send it */ + if (ao->winsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (lwip_htonl(tl) != ao->winsaddr[d]) { + DECPTR(sizeof(u32_t), p); + tl = lwip_ntohl(ao->winsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; +#endif /* UNUSED - WINS */ + +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (!ao->neg_vj || + (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + if (!(cishort == IPCP_VJ_COMP || + (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { + orc = CONFREJ; + break; + } + + ho->neg_vj = 1; + ho->vj_protocol = cishort; + if (cilen == CILEN_VJ) { + GETCHAR(maxslotindex, p); + if (maxslotindex > ao->maxslotindex) { + orc = CONFNAK; + if (!reject_if_disagree){ + DECPTR(1, p); + PUTCHAR(ao->maxslotindex, p); + } + } + GETCHAR(cflag, p); + if (cflag && !ao->cflag) { + orc = CONFNAK; + if (!reject_if_disagree){ + DECPTR(1, p); + PUTCHAR(wo->cflag, p); + } + } + ho->maxslotindex = maxslotindex; + ho->cflag = cflag; + } else { + ho->old_vj = 1; + ho->maxslotindex = MAX_STATES - 1; + ho->cflag = 1; + } + break; +#endif /* VJ_SUPPORT */ + + default: + orc = CONFREJ; + break; + } +endswitch: + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree) /* Getting fed up with sending NAKs? */ + orc = CONFREJ; /* Get tough if so */ + else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + if (rc == CONFACK) { /* Ack'd all prior CIs? */ + rc = CONFNAK; /* Not anymore... */ + ucp = inp; /* Backup */ + } + } + } + + if (orc == CONFREJ && /* Reject this CI */ + rc != CONFREJ) { /* but no prior ones? */ + rc = CONFREJ; + ucp = inp; /* Backup */ + } + + /* Need to move CI? */ + if (ucp != cip) + MEMCPY(ucp, cip, cilen); /* Move it */ + + /* Update output pointer */ + INCPTR(cilen, ucp); + } + + /* + * If we aren't rejecting this packet, and we want to negotiate + * their address, and they didn't send their address, then we + * send a NAK with a CI_ADDR option appended. We assume the + * input buffer is long enough that we can append the extra + * option safely. + */ + if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && + wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) { + if (rc == CONFACK) { + rc = CONFNAK; + ucp = inp; /* reset pointer */ + wo->req_addr = 0; /* don't ask again */ + } + PUTCHAR(CI_ADDR, ucp); + PUTCHAR(CILEN_ADDR, ucp); + tl = lwip_ntohl(wo->hisaddr); + PUTLONG(tl, ucp); + } + + *len = ucp - inp; /* Compute output length */ + IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +#if 0 /* UNUSED */ +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options() +{ + struct hostent *hp; + u32_t local; + ipcp_options *wo = &ipcp_wantoptions[0]; + + /* + * Default our local IP address based on our hostname. + * If local IP address already given, don't bother. + */ + if (wo->ouraddr == 0 && !disable_defaultip) { + /* + * Look up our hostname (possibly with domain name appended) + * and take the first IP address as our local IP address. + * If there isn't an IP address for our hostname, too bad. + */ + wo->accept_local = 1; /* don't insist on this default value */ + if ((hp = gethostbyname(hostname)) != NULL) { + local = *(u32_t *)hp->h_addr; + if (local != 0 && !bad_ip_adrs(local)) + wo->ouraddr = local; + } + } + ask_for_local = wo->ouraddr != 0 || !disable_defaultip; +} +#endif /* UNUSED */ + +#if DEMAND_SUPPORT +/* + * ip_demand_conf - configure the interface as though + * IPCP were up, for use with dial-on-demand. + */ +static int +ip_demand_conf(u) + int u; +{ + ppp_pcb *pcb = &ppp_pcb_list[u]; + ipcp_options *wo = &ipcp_wantoptions[u]; + + if (wo->hisaddr == 0 && !pcb->settings.noremoteip) { + /* make up an arbitrary address for the peer */ + wo->hisaddr = lwip_htonl(0x0a707070 + ifunit); + wo->accept_remote = 1; + } + if (wo->ouraddr == 0) { + /* make up an arbitrary address for us */ + wo->ouraddr = lwip_htonl(0x0a404040 + ifunit); + wo->accept_local = 1; + ask_for_local = 0; /* don't tell the peer this address */ + } + if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr))) + return 0; + if (!sifup(pcb)) + return 0; + if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE)) + return 0; +#if 0 /* UNUSED */ + if (wo->default_route) + if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr, + wo->replace_default_route)) + default_route_set[u] = 1; +#endif /* UNUSED */ +#if 0 /* UNUSED - PROXY ARP */ + if (wo->proxy_arp) + if (sifproxyarp(pcb, wo->hisaddr)) + proxy_arp_set[u] = 1; +#endif /* UNUSED - PROXY ARP */ + + ppp_notice("local IP address %I", wo->ouraddr); + if (wo->hisaddr) + ppp_notice("remote IP address %I", wo->hisaddr); + + return 1; +} +#endif /* DEMAND_SUPPORT */ + +/* + * ipcp_up - IPCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ +static void ipcp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + u32_t mask; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + ipcp_options *wo = &pcb->ipcp_wantoptions; + + IPCPDEBUG(("ipcp: up")); + + /* + * We must have a non-zero IP address for both ends of the link. + */ + if (!ho->neg_addr && !ho->old_addrs) + ho->hisaddr = wo->hisaddr; + + if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) + && wo->ouraddr != 0) { + ppp_error("Peer refused to agree to our IP address"); + ipcp_close(f->pcb, "Refused our IP address"); + return; + } + if (go->ouraddr == 0) { + ppp_error("Could not determine local IP address"); + ipcp_close(f->pcb, "Could not determine local IP address"); + return; + } + if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { + ho->hisaddr = lwip_htonl(0x0a404040); + ppp_warn("Could not determine remote IP address: defaulting to %I", + ho->hisaddr); + } +#if 0 /* UNUSED */ + script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); + if (ho->hisaddr != 0) + script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); +#endif /* UNUSED */ + +#if LWIP_DNS + if (!go->req_dns1) + go->dnsaddr[0] = 0; + if (!go->req_dns2) + go->dnsaddr[1] = 0; +#if 0 /* UNUSED */ + if (go->dnsaddr[0]) + script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); + if (go->dnsaddr[1]) + script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); +#endif /* UNUSED */ + if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { + sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); +#if 0 /* UNUSED */ + script_setenv("USEPEERDNS", "1", 0); + create_resolv(go->dnsaddr[0], go->dnsaddr[1]); +#endif /* UNUSED */ + } +#endif /* LWIP_DNS */ + + /* + * Check that the peer is allowed to use the IP address it wants. + */ + if (ho->hisaddr != 0) { + u32_t addr = lwip_ntohl(ho->hisaddr); + if ((addr >> IP_CLASSA_NSHIFT) == IP_LOOPBACKNET + || IP_MULTICAST(addr) || IP_BADCLASS(addr) + /* + * For now, consider that PPP in server mode with peer required + * to authenticate must provide the peer IP address, reject any + * IP address wanted by peer different than the one we wanted. + */ +#if PPP_SERVER && PPP_AUTH_SUPPORT + || (pcb->settings.auth_required && wo->hisaddr != ho->hisaddr) +#endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ + ) { + ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ipcp_close(pcb, "Unauthorized remote IP address"); + return; + } + } +#if 0 /* Unused */ + /* Upstream checking code */ + if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { + ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); + ipcp_close(f->unit, "Unauthorized remote IP address"); + return; + } +#endif /* Unused */ + +#if VJ_SUPPORT + /* set tcp compression */ + sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex); +#endif /* VJ_SUPPORT */ + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, the interface is already + * configured, so we put out any saved-up packets, then set the + * interface to pass IP packets. + */ + if (demand) { + if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { + ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, + wo->replace_default_route); + if (go->ouraddr != wo->ouraddr) { + ppp_warn("Local IP address changed to %I", go->ouraddr); + script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); + wo->ouraddr = go->ouraddr; + } else + script_unsetenv("OLDIPLOCAL"); + if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { + ppp_warn("Remote IP address changed to %I", ho->hisaddr); + script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); + wo->hisaddr = ho->hisaddr; + } else + script_unsetenv("OLDIPREMOTE"); + + /* Set the interface to the new addresses */ + mask = get_mask(go->ouraddr); + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + + /* assign a default route through the interface if required */ + if (ipcp_wantoptions[f->unit].default_route) + if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) + default_route_set[f->unit] = 1; + +#if 0 /* UNUSED - PROXY ARP */ + /* Make a proxy ARP entry if requested. */ + if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp) + if (sifproxyarp(pcb, ho->hisaddr)) + proxy_arp_set[f->unit] = 1; +#endif /* UNUSED - PROXY ARP */ + + } + demand_rexmit(PPP_IP,go->ouraddr); + sifnpmode(pcb, PPP_IP, NPMODE_PASS); + + } else +#endif /* DEMAND_SUPPORT */ + { + /* + * Set IP addresses and (if specified) netmask. + */ + mask = get_mask(go->ouraddr); + +#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->pcb, "Interface configuration failed"); + return; + } +#endif + + /* bring the interface up for IP */ + if (!sifup(pcb)) { +#if PPP_DEBUG + ppp_warn("Interface failed to come up"); +#endif /* PPP_DEBUG */ + ipcp_close(f->pcb, "Interface configuration failed"); + return; + } + +#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) + if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { +#if PPP_DEBUG + ppp_warn("Interface configuration failed"); +#endif /* PPP_DEBUG */ + ipcp_close(f->unit, "Interface configuration failed"); + return; + } +#endif +#if DEMAND_SUPPORT + sifnpmode(pcb, PPP_IP, NPMODE_PASS); +#endif /* DEMAND_SUPPORT */ + +#if 0 /* UNUSED */ + /* assign a default route through the interface if required */ + if (wo->default_route) + if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) + pcb->default_route_set = 1; +#endif /* UNUSED */ + +#if 0 /* UNUSED - PROXY ARP */ + /* Make a proxy ARP entry if requested. */ + if (ho->hisaddr != 0 && wo->proxy_arp) + if (sifproxyarp(pcb, ho->hisaddr)) + pcb->proxy_arp_set = 1; +#endif /* UNUSED - PROXY ARP */ + + wo->ouraddr = go->ouraddr; + + ppp_notice("local IP address %I", go->ouraddr); + if (ho->hisaddr != 0) + ppp_notice("remote IP address %I", ho->hisaddr); +#if LWIP_DNS + if (go->dnsaddr[0]) + ppp_notice("primary DNS address %I", go->dnsaddr[0]); + if (go->dnsaddr[1]) + ppp_notice("secondary DNS address %I", go->dnsaddr[1]); +#endif /* LWIP_DNS */ + } + +#if PPP_STATS_SUPPORT + reset_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ + + np_up(pcb, PPP_IP); + pcb->ipcp_is_up = 1; + +#if PPP_NOTIFY + notify(ip_up_notifier, 0); +#endif /* PPP_NOTIFY */ +#if 0 /* UNUSED */ + if (ip_up_hook) + ip_up_hook(); +#endif /* UNUSED */ +} + + +/* + * ipcp_down - IPCP has gone DOWN. + * + * Take the IP network interface down, clear its addresses + * and delete routes through it. + */ +static void ipcp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipcp_options *ho = &pcb->ipcp_hisoptions; + ipcp_options *go = &pcb->ipcp_gotoptions; + + IPCPDEBUG(("ipcp: down")); +#if PPP_STATS_SUPPORT + /* XXX a bit IPv4-centric here, we only need to get the stats + * before the interface is marked down. */ + /* XXX more correct: we must get the stats before running the notifiers, + * at least for the radius plugin */ + update_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ +#if PPP_NOTIFY + notify(ip_down_notifier, 0); +#endif /* PPP_NOTIFY */ +#if 0 /* UNUSED */ + if (ip_down_hook) + ip_down_hook(); +#endif /* UNUSED */ + if (pcb->ipcp_is_up) { + pcb->ipcp_is_up = 0; + np_down(pcb, PPP_IP); + } +#if VJ_SUPPORT + sifvjcomp(pcb, 0, 0, 0); +#endif /* VJ_SUPPORT */ + +#if PPP_STATS_SUPPORT + print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), + * because print_link_stats() sets link_stats_valid + * to 0 (zero) */ +#endif /* PPP_STATS_SUPPORT */ + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, set the interface + * to queue up outgoing packets (for now). + */ + if (demand) { + sifnpmode(pcb, PPP_IP, NPMODE_QUEUE); + } else +#endif /* DEMAND_SUPPORT */ + { +#if DEMAND_SUPPORT + sifnpmode(pcb, PPP_IP, NPMODE_DROP); +#endif /* DEMAND_SUPPORT */ + sifdown(pcb); + ipcp_clear_addrs(pcb, go->ouraddr, + ho->hisaddr, 0); +#if LWIP_DNS + cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); +#endif /* LWIP_DNS */ + } +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, + * proxy arp entries, etc. + */ +static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) { + LWIP_UNUSED_ARG(replacedefaultroute); + +#if 0 /* UNUSED - PROXY ARP */ + if (pcb->proxy_arp_set) { + cifproxyarp(pcb, hisaddr); + pcb->proxy_arp_set = 0; + } +#endif /* UNUSED - PROXY ARP */ +#if 0 /* UNUSED */ + /* If replacedefaultroute, sifdefaultroute will be called soon + * with replacedefaultroute set and that will overwrite the current + * default route. This is the case only when doing demand, otherwise + * during demand, this cifdefaultroute would restore the old default + * route which is not what we want in this case. In the non-demand + * case, we'll delete the default route and restore the old if there + * is one saved by an sifdefaultroute with replacedefaultroute. + */ + if (!replacedefaultroute && pcb->default_route_set) { + cifdefaultroute(pcb, ouraddr, hisaddr); + pcb->default_route_set = 0; + } +#endif /* UNUSED */ + cifaddr(pcb, ouraddr, hisaddr); +} + + +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void ipcp_finished(fsm *f) { + ppp_pcb *pcb = f->pcb; + if (pcb->ipcp_is_open) { + pcb->ipcp_is_open = 0; + np_finished(pcb, PPP_IP); + } +} + + +#if 0 /* UNUSED */ +/* + * create_resolv - create the replacement resolv.conf file + */ +static void +create_resolv(peerdns1, peerdns2) + u32_t peerdns1, peerdns2; +{ + +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ipcp_printpkt - print the contents of an IPCP packet. + */ +static const char* const ipcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +static int ipcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, olen; + const u_char *pstart, *optend; +#if VJ_SUPPORT + u_short cishort; +#endif /* VJ_SUPPORT */ + u32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipcp_codenames)) + printer(arg, " %s", ipcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case CI_ADDRS: + if (olen == CILEN_ADDRS) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addrs %I", lwip_htonl(cilong)); + GETLONG(cilong, p); + printer(arg, " %I", lwip_htonl(cilong)); + } + break; +#if VJ_SUPPORT + case CI_COMPRESSTYPE: + if (olen >= CILEN_COMPRESS) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "compress "); + switch (cishort) { + case IPCP_VJ_COMP: + printer(arg, "VJ"); + break; + case IPCP_VJ_COMP_OLD: + printer(arg, "old-VJ"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; +#endif /* VJ_SUPPORT */ + case CI_ADDR: + if (olen == CILEN_ADDR) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addr %I", lwip_htonl(cilong)); + } + break; +#if LWIP_DNS + case CI_MS_DNS1: + case CI_MS_DNS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2), + htonl(cilong)); + break; +#endif /* LWIP_DNS */ +#if 0 /* UNUSED - WINS */ + case CI_MS_WINS1: + case CI_MS_WINS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-wins %I", lwip_htonl(cilong)); + break; +#endif /* UNUSED - WINS */ + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * ip_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP_HDRLEN 20 /* bytes */ +#define IP_OFFMASK 0x1fff +#ifndef IPPROTO_TCP +#define IPPROTO_TCP 6 +#endif +#define TCP_HDRLEN 20 +#define TH_FIN 0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define net_short(x) (((x)[0] << 8) + (x)[1]) +#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) +#define get_ipoff(x) net_short((unsigned char *)(x) + 6) +#define get_ipproto(x) (((unsigned char *)(x))[9]) +#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int +ip_active_pkt(pkt, len) + u_char *pkt; + int len; +{ + u_char *tcp; + int hlen; + + len -= PPP_HDRLEN; + pkt += PPP_HDRLEN; + if (len < IP_HDRLEN) + return 0; + if ((get_ipoff(pkt) & IP_OFFMASK) != 0) + return 0; + if (get_ipproto(pkt) != IPPROTO_TCP) + return 1; + hlen = get_iphl(pkt) * 4; + if (len < hlen + TCP_HDRLEN) + return 0; + tcp = pkt + hlen; + if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) + return 0; + return 1; +} +#endif /* DEMAND_SUPPORT */ + +#endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipv6cp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipv6cp.c new file mode 100644 index 0000000000..11c18df743 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ipv6cp.c @@ -0,0 +1,1533 @@ +/* + * ipv6cp.c - PPP IPV6 Control Protocol. + * + * Copyright (c) 1999 Tommi Komulainen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Tommi Komulainen + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Original version, based on RFC2023 : + + Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, + Alain.Durand@imag.fr, IMAG, + Jean-Luc.Richier@imag.fr, IMAG-LSR. + + Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt + Économique ayant pour membres BULL S.A. et l'INRIA). + + Ce logiciel informatique est disponible aux conditions + usuelles dans la recherche, c'est-à-dire qu'il peut + être utilisé, copié, modifié, distribué à l'unique + condition que ce texte soit conservé afin que + l'origine de ce logiciel soit reconnue. + + Le nom de l'Institut National de Recherche en Informatique + et en Automatique (INRIA), de l'IMAG, ou d'une personne morale + ou physique ayant participé à l'élaboration de ce logiciel ne peut + être utilisé sans son accord préalable explicite. + + Ce logiciel est fourni tel quel sans aucune garantie, + support ou responsabilité d'aucune sorte. + Ce logiciel est dérivé de sources d'origine + "University of California at Berkeley" et + "Digital Equipment Corporation" couvertes par des copyrights. + + L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) + est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National + Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant + sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). + + This work has been done in the context of GIE DYADE (joint R & D venture + between BULL S.A. and INRIA). + + This software is available with usual "research" terms + with the aim of retain credits of the software. + Permission to use, copy, modify and distribute this software for any + purpose and without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies, + and the name of INRIA, IMAG, or any contributor not be used in advertising + or publicity pertaining to this material without the prior explicit + permission. The software is provided "as is" without any + warranties, support or liabilities of any kind. + This software is derived from source code from + "University of California at Berkeley" and + "Digital Equipment Corporation" protected by copyrights. + + Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) + is a federation of seven research units funded by the CNRS, National + Polytechnic Institute of Grenoble and University Joseph Fourier. + The research unit in Software, Systems, Networks (LSR) is member of IMAG. +*/ + +/* + * Derived from : + * + * + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ + */ + +/* + * @todo: + * + * Proxy Neighbour Discovery. + * + * Better defines for selecting the ordering of + * interface up / set address. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/fsm.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/ipv6cp.h" +#include "netif/ppp/magic.h" + +/* global vars */ +#if 0 /* UNUSED */ +int no_ifaceid_neg = 0; +#endif /* UNUSED */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void ipv6cp_resetci(fsm *f); /* Reset our CI */ +static int ipv6cp_cilen(fsm *f); /* Return length of our CI */ +static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ +static int ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ +static int ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ +static void ipv6cp_up(fsm *f); /* We're UP */ +static void ipv6cp_down(fsm *f); /* We're DOWN */ +static void ipv6cp_finished(fsm *f); /* Don't need lower layer */ + +static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ + ipv6cp_resetci, /* Reset our Configuration Information */ + ipv6cp_cilen, /* Length of our Configuration Information */ + ipv6cp_addci, /* Add our Configuration Information */ + ipv6cp_ackci, /* ACK our Configuration Information */ + ipv6cp_nakci, /* NAK our Configuration Information */ + ipv6cp_rejci, /* Reject our Configuration Information */ + ipv6cp_reqci, /* Request peer's Configuration Information */ + ipv6cp_up, /* Called when fsm reaches OPENED state */ + ipv6cp_down, /* Called when fsm leaves OPENED state */ + NULL, /* Called when we want the lower layer up */ + ipv6cp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPV6CP" /* String name of protocol */ +}; + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static int setifaceid(char **arg)); +static void printifaceid(option_t *, + void (*)(void *, char *, ...), void *)); + +static option_t ipv6cp_option_list[] = { + { "ipv6", o_special, (void *)setifaceid, + "Set interface identifiers for IPV6", + OPT_A2PRINTER, (void *)printifaceid }, + + { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, + { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, + { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, + "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, + + { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local, + "Accept peer's interface identifier for us", 1 }, + + { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, + "Use (default) IPv4 address as interface identifier", 1 }, + + { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, + "Use uniquely-available persistent value for link local address", 1 }, + + { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, + "Set timeout for IPv6CP", OPT_PRIO }, + { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, + "Set max #xmits for term-reqs", OPT_PRIO }, + { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, + "Set max #xmits for conf-reqs", OPT_PRIO }, + { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, + "Set max #conf-naks for IPv6CP", OPT_PRIO }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points from main code. + */ +static void ipv6cp_init(ppp_pcb *pcb); +static void ipv6cp_open(ppp_pcb *pcb); +static void ipv6cp_close(ppp_pcb *pcb, const char *reason); +static void ipv6cp_lowerup(ppp_pcb *pcb); +static void ipv6cp_lowerdown(ppp_pcb *pcb); +static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len); +static void ipv6cp_protrej(ppp_pcb *pcb); +#if PPP_OPTIONS +static void ipv6_check_options(void); +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT +static int ipv6_demand_conf(int u); +#endif /* DEMAND_SUPPORT */ +#if PRINTPKT_SUPPORT +static int ipv6cp_printpkt(const u_char *p, int plen, + void (*printer)(void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ +#if DEMAND_SUPPORT +static int ipv6_active_pkt(u_char *pkt, int len); +#endif /* DEMAND_SUPPORT */ + +const struct protent ipv6cp_protent = { + PPP_IPV6CP, + ipv6cp_init, + ipv6cp_input, + ipv6cp_protrej, + ipv6cp_lowerup, + ipv6cp_lowerdown, + ipv6cp_open, + ipv6cp_close, +#if PRINTPKT_SUPPORT + ipv6cp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "IPV6CP", + "IPV6", +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + ipv6cp_option_list, + ipv6_check_options, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + ipv6_demand_conf, + ipv6_active_pkt +#endif /* DEMAND_SUPPORT */ +}; + +static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid); +#if 0 /* UNUSED */ +static void ipv6cp_script(char *)); +static void ipv6cp_script_done(void *)); +#endif /* UNUSED */ + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID 2 +#define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ +#define CILEN_IFACEID 10 /* RFC2472, interface identifier */ + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED */ +/* + * This state variable is used to ensure that we don't + * run an ipcp-up/down script while one is already running. + */ +static enum script_state { + s_down, + s_up, +} ipv6cp_script_state; +static pid_t ipv6cp_script_pid; +#endif /* UNUSED */ + +static char *llv6_ntoa(eui64_t ifaceid); + +#if PPP_OPTIONS +/* + * setifaceid - set the interface identifiers manually + */ +static int +setifaceid(argv) + char **argv; +{ + char *comma, *arg, c; + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + struct in6_addr addr; + static int prio_local, prio_remote; + +#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ + (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) + + arg = *argv; + if ((comma = strchr(arg, ',')) == NULL) + comma = arg + strlen(arg); + + /* + * If comma first character, then no local identifier + */ + if (comma != arg) { + c = *comma; + *comma = '\0'; + + if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { + option_error("Illegal interface identifier (local): %s", arg); + return 0; + } + + if (option_priority >= prio_local) { + eui64_copy(addr.s6_addr32[2], wo->ourid); + wo->opt_local = 1; + prio_local = option_priority; + } + *comma = c; + } + + /* + * If comma last character, the no remote identifier + */ + if (*comma != 0 && *++comma != '\0') { + if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { + option_error("Illegal interface identifier (remote): %s", comma); + return 0; + } + if (option_priority >= prio_remote) { + eui64_copy(addr.s6_addr32[2], wo->hisid); + wo->opt_remote = 1; + prio_remote = option_priority; + } + } + + if (override_value("+ipv6", option_priority, option_source)) + ipv6cp_protent.enabled_flag = 1; + return 1; +} + +static void +printifaceid(opt, printer, arg) + option_t *opt; + void (*printer)(void *, char *, ...)); + void *arg; +{ + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + + if (wo->opt_local) + printer(arg, "%s", llv6_ntoa(wo->ourid)); + printer(arg, ","); + if (wo->opt_remote) + printer(arg, "%s", llv6_ntoa(wo->hisid)); +} +#endif /* PPP_OPTIONS */ + +/* + * Make a string representation of a network address. + */ +static char * +llv6_ntoa(eui64_t ifaceid) +{ + static char b[26]; + + sprintf(b, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ifaceid.e8[0], ifaceid.e8[1], ifaceid.e8[2], ifaceid.e8[3], + ifaceid.e8[4], ifaceid.e8[5], ifaceid.e8[6], ifaceid.e8[7]); + + return b; +} + + +/* + * ipv6cp_init - Initialize IPV6CP. + */ +static void ipv6cp_init(ppp_pcb *pcb) { + fsm *f = &pcb->ipv6cp_fsm; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_IPV6CP; + f->callbacks = &ipv6cp_callbacks; + fsm_init(f); + +#if 0 /* Not necessary, everything is cleared in ppp_new() */ + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); +#endif /* 0 */ + + wo->accept_local = 1; + wo->neg_ifaceid = 1; + ao->neg_ifaceid = 1; + +#ifdef IPV6CP_COMP + wo->neg_vj = 1; + ao->neg_vj = 1; + wo->vj_protocol = IPV6CP_COMP; +#endif + +} + + +/* + * ipv6cp_open - IPV6CP is allowed to come up. + */ +static void ipv6cp_open(ppp_pcb *pcb) { + fsm_open(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_close - Take IPV6CP down. + */ +static void ipv6cp_close(ppp_pcb *pcb, const char *reason) { + fsm_close(&pcb->ipv6cp_fsm, reason); +} + + +/* + * ipv6cp_lowerup - The lower layer is up. + */ +static void ipv6cp_lowerup(ppp_pcb *pcb) { + fsm_lowerup(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_lowerdown - The lower layer is down. + */ +static void ipv6cp_lowerdown(ppp_pcb *pcb) { + fsm_lowerdown(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_input - Input IPV6CP packet. + */ +static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm_input(&pcb->ipv6cp_fsm, p, len); +} + + +/* + * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void ipv6cp_protrej(ppp_pcb *pcb) { + fsm_lowerdown(&pcb->ipv6cp_fsm); +} + + +/* + * ipv6cp_resetci - Reset our CI. + */ +static void ipv6cp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + + wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; + + if (!wo->opt_local) { + eui64_magic_nz(wo->ourid); + } + + *go = *wo; + eui64_zero(go->hisid); /* last proposed interface identifier */ +} + + +/* + * ipv6cp_cilen - Return length of our CI. + */ +static int ipv6cp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + +#ifdef IPV6CP_COMP +#define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) +#endif /* IPV6CP_COMP */ +#define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) + + return (LENCIIFACEID(go->neg_ifaceid) + +#ifdef IPV6CP_COMP + LENCIVJ(go->neg_vj) + +#endif /* IPV6CP_COMP */ + 0); +} + + +/* + * ipv6cp_addci - Add our desired CIs to a packet. + */ +static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + int len = *lenp; + +#ifdef IPV6CP_COMP +#define ADDCIVJ(opt, neg, val) \ + if (neg) { \ + int vjlen = CILEN_COMPRESS; \ + if (len >= vjlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(vjlen, ucp); \ + PUTSHORT(val, ucp); \ + len -= vjlen; \ + } else \ + neg = 0; \ + } +#endif /* IPV6CP_COMP */ + +#define ADDCIIFACEID(opt, neg, val1) \ + if (neg) { \ + int idlen = CILEN_IFACEID; \ + if (len >= idlen) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(idlen, ucp); \ + eui64_put(val1, ucp); \ + len -= idlen; \ + } else \ + neg = 0; \ + } + + ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + *lenp -= len; +} + + +/* + * ipv6cp_ackci - Ack our CIs. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int ipv6cp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_short cilen, citype; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + + /* + * CIs must be in exactly the same order that we sent... + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ + +#ifdef IPV6CP_COMP +#define ACKCIVJ(opt, neg, val) \ + if (neg) { \ + int vjlen = CILEN_COMPRESS; \ + if ((len -= vjlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != vjlen || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + } +#endif /* IPV6CP_COMP */ + +#define ACKCIIFACEID(opt, neg, val1) \ + if (neg) { \ + int idlen = CILEN_IFACEID; \ + if ((len -= idlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != idlen || \ + citype != opt) \ + goto bad; \ + eui64_get(ifaceid, p); \ + if (! eui64_equals(val1, ifaceid)) \ + goto bad; \ + } + + ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); + +bad: + IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); + return (0); +} + +/* + * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPV6CP is in the OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char citype, cilen, *next; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + ipv6cp_options no; /* options we've seen Naks for */ + ipv6cp_options try_; /* options to request next time */ + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIIFACEID(opt, neg, code) \ + if (go->neg && \ + len >= (cilen = CILEN_IFACEID) && \ + p[1] == cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + eui64_get(ifaceid, p); \ + no.neg = 1; \ + code \ + } + +#ifdef IPV6CP_COMP +#define NAKCIVJ(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_COMPRESS) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#endif /* IPV6CP_COMP */ + + /* + * Accept the peer's idea of {our,his} interface identifier, if different + * from our idea, only if the accept_{local,remote} flag is set. + */ + NAKCIIFACEID(CI_IFACEID, neg_ifaceid, + if (treat_as_reject) { + try_.neg_ifaceid = 0; + } else if (go->accept_local) { + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->hisid)) /* bad luck */ + eui64_magic(ifaceid); + try_.ourid = ifaceid; + IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); + } + ); + +#ifdef IPV6CP_COMP + NAKCIVJ(CI_COMPRESSTYPE, neg_vj, + { + if (cishort == IPV6CP_COMP && !treat_as_reject) { + try_.vj_protocol = cishort; + } else { + try_.neg_vj = 0; + } + } + ); +#endif /* IPV6CP_COMP */ + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If they want to negotiate about interface identifier, we comply. + * If they want us to ask for compression, we refuse. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) + goto bad; + next = p + cilen - 2; + + switch (citype) { +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + if (go->neg_vj || no.neg_vj || + (cilen != CILEN_COMPRESS)) + goto bad; + no.neg_vj = 1; + break; +#endif /* IPV6CP_COMP */ + case CI_IFACEID: + if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) + goto bad; + try_.neg_ifaceid = 1; + eui64_get(ifaceid, p); + if (go->accept_local) { + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->hisid)) /* bad luck */ + eui64_magic(ifaceid); + try_.ourid = ifaceid; + } + no.neg_ifaceid = 1; + break; + default: + break; + } + p = next; + } + + /* If there is still anything left, this packet is bad. */ + if (len != 0) + goto bad; + + /* + * OK, the Nak is good. Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + + return 1; + +bad: + IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); + return 0; +} + + +/* + * ipv6cp_rejci - Reject some of our CIs. + */ +static int ipv6cp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char cilen; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + ipv6cp_options try_; /* options to request next time */ + + try_ = *go; + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIIFACEID(opt, neg, val1) \ + if (go->neg && \ + len >= (cilen = CILEN_IFACEID) && \ + p[1] == cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + eui64_get(ifaceid, p); \ + /* Check rejected value. */ \ + if (! eui64_equals(ifaceid, val1)) \ + goto bad; \ + try_.neg = 0; \ + } + +#ifdef IPV6CP_COMP +#define REJCIVJ(opt, neg, val) \ + if (go->neg && \ + p[1] == CILEN_COMPRESS && \ + len >= p[1] && \ + p[0] == opt) { \ + len -= p[1]; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* IPV6CP_COMP */ + + REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); + +#ifdef IPV6CP_COMP + REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); +#endif /* IPV6CP_COMP */ + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); + return 0; +} + + +/* + * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * len = Length of requested CIs + * + */ +static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + u_short cilen, citype; /* Parsed len, type */ +#ifdef IPV6CP_COMP + u_short cishort; /* Parsed short value */ +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; /* Parsed interface identifier */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *ucp = inp; /* Pointer to current output char */ + int l = *len; /* Length left */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_IFACEID: + IPV6CPDEBUG(("ipv6cp: received interface identifier ")); + + if (!ao->neg_ifaceid || + cilen != CILEN_IFACEID) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + + /* + * If he has no interface identifier, or if we both have same + * identifier then NAK it with new idea. + * In particular, if we don't know his identifier, but he does, + * then accept it. + */ + eui64_get(ifaceid, p); + IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); + if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { + orc = CONFREJ; /* Reject CI */ + break; + } + if (!eui64_iszero(wo->hisid) && + !eui64_equals(ifaceid, wo->hisid) && + eui64_iszero(go->hisid)) { + + orc = CONFNAK; + ifaceid = wo->hisid; + go->hisid = ifaceid; + DECPTR(sizeof(ifaceid), p); + eui64_put(ifaceid, p); + } else + if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { + orc = CONFNAK; + if (eui64_iszero(go->hisid)) /* first time, try option */ + ifaceid = wo->hisid; + while (eui64_iszero(ifaceid) || + eui64_equals(ifaceid, go->ourid)) /* bad luck */ + eui64_magic(ifaceid); + go->hisid = ifaceid; + DECPTR(sizeof(ifaceid), p); + eui64_put(ifaceid, p); + } + + ho->neg_ifaceid = 1; + ho->hisid = ifaceid; + break; + +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); + if (!ao->neg_vj || + (cilen != CILEN_COMPRESS)) { + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + IPV6CPDEBUG(("(%d)", cishort)); + + if (!(cishort == IPV6CP_COMP)) { + orc = CONFREJ; + break; + } + + ho->neg_vj = 1; + ho->vj_protocol = cishort; + break; +#endif /* IPV6CP_COMP */ + + default: + orc = CONFREJ; + break; + } + +endswitch: + IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); + + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree) /* Getting fed up with sending NAKs? */ + orc = CONFREJ; /* Get tough if so */ + else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + if (rc == CONFACK) { /* Ack'd all prior CIs? */ + rc = CONFNAK; /* Not anymore... */ + ucp = inp; /* Backup */ + } + } + } + + if (orc == CONFREJ && /* Reject this CI */ + rc != CONFREJ) { /* but no prior ones? */ + rc = CONFREJ; + ucp = inp; /* Backup */ + } + + /* Need to move CI? */ + if (ucp != cip) + MEMCPY(ucp, cip, cilen); /* Move it */ + + /* Update output pointer */ + INCPTR(cilen, ucp); + } + + /* + * If we aren't rejecting this packet, and we want to negotiate + * their identifier and they didn't send their identifier, then we + * send a NAK with a CI_IFACEID option appended. We assume the + * input buffer is long enough that we can append the extra + * option safely. + */ + if (rc != CONFREJ && !ho->neg_ifaceid && + wo->req_ifaceid && !reject_if_disagree) { + if (rc == CONFACK) { + rc = CONFNAK; + ucp = inp; /* reset pointer */ + wo->req_ifaceid = 0; /* don't ask again */ + } + PUTCHAR(CI_IFACEID, ucp); + PUTCHAR(CILEN_IFACEID, ucp); + eui64_put(wo->hisid, ucp); + } + + *len = ucp - inp; /* Compute output length */ + IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); + return (rc); /* Return final code */ +} + +#if PPP_OPTIONS +/* + * ipv6_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void ipv6_check_options() { + ipv6cp_options *wo = &ipv6cp_wantoptions[0]; + + if (!ipv6cp_protent.enabled_flag) + return; + + /* + * Persistent link-local id is only used when user has not explicitly + * configure/hard-code the id + */ + if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { + + /* + * On systems where there are no Ethernet interfaces used, there + * may be other ways to obtain a persistent id. Right now, it + * will fall back to using magic [see eui64_magic] below when + * an EUI-48 from MAC address can't be obtained. Other possibilities + * include obtaining EEPROM serial numbers, or some other unique + * yet persistent number. On Sparc platforms, this is possible, + * but too bad there's no standards yet for x86 machines. + */ + if (ether_to_eui64(&wo->ourid)) { + wo->opt_local = 1; + } + } + + if (!wo->opt_local) { /* init interface identifier */ + if (wo->use_ip && eui64_iszero(wo->ourid)) { + eui64_setlo32(wo->ourid, lwip_ntohl(ipcp_wantoptions[0].ouraddr)); + if (!eui64_iszero(wo->ourid)) + wo->opt_local = 1; + } + + while (eui64_iszero(wo->ourid)) + eui64_magic(wo->ourid); + } + + if (!wo->opt_remote) { + if (wo->use_ip && eui64_iszero(wo->hisid)) { + eui64_setlo32(wo->hisid, lwip_ntohl(ipcp_wantoptions[0].hisaddr)); + if (!eui64_iszero(wo->hisid)) + wo->opt_remote = 1; + } + } + + if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { + option_error("local/remote LL address required for demand-dialling\n"); + exit(1); + } +} +#endif /* PPP_OPTIONS */ + +#if DEMAND_SUPPORT +/* + * ipv6_demand_conf - configure the interface as though + * IPV6CP were up, for use with dial-on-demand. + */ +static int ipv6_demand_conf(int u) { + ipv6cp_options *wo = &ipv6cp_wantoptions[u]; + + if (!sif6up(u)) + return 0; + + if (!sif6addr(u, wo->ourid, wo->hisid)) + return 0; + + if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) + return 0; + + ppp_notice("ipv6_demand_conf"); + ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); + ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); + + return 1; +} +#endif /* DEMAND_SUPPORT */ + + +/* + * ipv6cp_up - IPV6CP has come UP. + * + * Configure the IPv6 network interface appropriately and bring it up. + */ +static void ipv6cp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + + IPV6CPDEBUG(("ipv6cp: up")); + + /* + * We must have a non-zero LL address for both ends of the link. + */ + if (!ho->neg_ifaceid) + ho->hisid = wo->hisid; + +#if 0 /* UNUSED */ + if(!no_ifaceid_neg) { +#endif /* UNUSED */ + if (eui64_iszero(ho->hisid)) { + ppp_error("Could not determine remote LL address"); + ipv6cp_close(f->pcb, "Could not determine remote LL address"); + return; + } + if (eui64_iszero(go->ourid)) { + ppp_error("Could not determine local LL address"); + ipv6cp_close(f->pcb, "Could not determine local LL address"); + return; + } + if (eui64_equals(go->ourid, ho->hisid)) { + ppp_error("local and remote LL addresses are equal"); + ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); + return; + } +#if 0 /* UNUSED */ + } +#endif /* UNUSED */ +#if 0 /* UNUSED */ + script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); + script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); +#endif /* UNUSED */ + +#ifdef IPV6CP_COMP + /* set tcp compression */ + sif6comp(f->unit, ho->neg_vj); +#endif + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, the interface is already + * configured, so we put out any saved-up packets, then set the + * interface to pass IPv6 packets. + */ + if (demand) { + if (! eui64_equals(go->ourid, wo->ourid) || + ! eui64_equals(ho->hisid, wo->hisid)) { + if (! eui64_equals(go->ourid, wo->ourid)) + warn("Local LL address changed to %s", + llv6_ntoa(go->ourid)); + if (! eui64_equals(ho->hisid, wo->hisid)) + warn("Remote LL address changed to %s", + llv6_ntoa(ho->hisid)); + ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); + + /* Set the interface to the new addresses */ + if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { + if (debug) + warn("sif6addr failed"); + ipv6cp_close(f->unit, "Interface configuration failed"); + return; + } + + } + demand_rexmit(PPP_IPV6); + sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); + + } else +#endif /* DEMAND_SUPPORT */ + { + /* + * Set LL addresses + */ + if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { + PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); + ipv6cp_close(f->pcb, "Interface configuration failed"); + return; + } + + /* bring the interface up for IPv6 */ + if (!sif6up(f->pcb)) { + PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)")); + ipv6cp_close(f->pcb, "Interface configuration failed"); + return; + } +#if DEMAND_SUPPORT + sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); +#endif /* DEMAND_SUPPORT */ + + ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); + ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); + } + + np_up(f->pcb, PPP_IPV6); + pcb->ipv6cp_is_up = 1; + +#if 0 /* UNUSED */ + /* + * Execute the ipv6-up script, like this: + * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL + */ + if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { + ipv6cp_script_state = s_up; + ipv6cp_script(_PATH_IPV6UP); + } +#endif /* UNUSED */ +} + + +/* + * ipv6cp_down - IPV6CP has gone DOWN. + * + * Take the IPv6 network interface down, clear its addresses + * and delete routes through it. + */ +static void ipv6cp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + ipv6cp_options *go = &pcb->ipv6cp_gotoptions; + ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; + + IPV6CPDEBUG(("ipv6cp: down")); +#if PPP_STATS_SUPPORT + update_link_stats(f->unit); +#endif /* PPP_STATS_SUPPORT */ + if (pcb->ipv6cp_is_up) { + pcb->ipv6cp_is_up = 0; + np_down(f->pcb, PPP_IPV6); + } +#ifdef IPV6CP_COMP + sif6comp(f->unit, 0); +#endif + +#if DEMAND_SUPPORT + /* + * If we are doing dial-on-demand, set the interface + * to queue up outgoing packets (for now). + */ + if (demand) { + sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); + } else +#endif /* DEMAND_SUPPORT */ + { +#if DEMAND_SUPPORT + sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); +#endif /* DEMAND_SUPPORT */ + ipv6cp_clear_addrs(f->pcb, + go->ourid, + ho->hisid); + sif6down(f->pcb); + } + +#if 0 /* UNUSED */ + /* Execute the ipv6-down script */ + if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { + ipv6cp_script_state = s_down; + ipv6cp_script(_PATH_IPV6DOWN); + } +#endif /* UNUSED */ +} + + +/* + * ipv6cp_clear_addrs() - clear the interface addresses, routes, + * proxy neighbour discovery entries, etc. + */ +static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { + cif6addr(pcb, ourid, hisid); +} + + +/* + * ipv6cp_finished - possibly shut down the lower layers. + */ +static void ipv6cp_finished(fsm *f) { + np_finished(f->pcb, PPP_IPV6); +} + + +#if 0 /* UNUSED */ +/* + * ipv6cp_script_done - called when the ipv6-up or ipv6-down script + * has finished. + */ +static void +ipv6cp_script_done(arg) + void *arg; +{ + ipv6cp_script_pid = 0; + switch (ipv6cp_script_state) { + case s_up: + if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { + ipv6cp_script_state = s_down; + ipv6cp_script(_PATH_IPV6DOWN); + } + break; + case s_down: + if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { + ipv6cp_script_state = s_up; + ipv6cp_script(_PATH_IPV6UP); + } + break; + } +} + + +/* + * ipv6cp_script - Execute a script with arguments + * interface-name tty-name speed local-LL remote-LL. + */ +static void +ipv6cp_script(script) + char *script; +{ + char strspeed[32], strlocal[32], strremote[32]; + char *argv[8]; + + sprintf(strspeed, "%d", baud_rate); + strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); + strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); + + argv[0] = script; + argv[1] = ifname; + argv[2] = devnam; + argv[3] = strspeed; + argv[4] = strlocal; + argv[5] = strremote; + argv[6] = ipparam; + argv[7] = NULL; + + ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, + NULL, 0); +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ipv6cp_printpkt - print the contents of an IPV6CP packet. + */ +static const char* const ipv6cp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +static int ipv6cp_printpkt(const u_char *p, int plen, + void (*printer)(void *, const char *, ...), void *arg) { + int code, id, len, olen; + const u_char *pstart, *optend; +#ifdef IPV6CP_COMP + u_short cishort; +#endif /* IPV6CP_COMP */ + eui64_t ifaceid; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames)) + printer(arg, " %s", ipv6cp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { +#ifdef IPV6CP_COMP + case CI_COMPRESSTYPE: + if (olen >= CILEN_COMPRESS) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "compress "); + printer(arg, "0x%x", cishort); + } + break; +#endif /* IPV6CP_COMP */ + case CI_IFACEID: + if (olen == CILEN_IFACEID) { + p += 2; + eui64_get(ifaceid, p); + printer(arg, "addr %s", llv6_ntoa(ifaceid)); + } + break; + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP6_HDRLEN 40 /* bytes */ +#define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ +#define TCP_HDRLEN 20 +#define TH_FIN 0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define get_ip6nh(x) (((unsigned char *)(x))[6]) +#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int ipv6_active_pkt(u_char *pkt, int len) { + u_char *tcp; + + len -= PPP_HDRLEN; + pkt += PPP_HDRLEN; + if (len < IP6_HDRLEN) + return 0; + if (get_ip6nh(pkt) == IP6_NHDR_FRAG) + return 0; + if (get_ip6nh(pkt) != IPPROTO_TCP) + return 1; + if (len < IP6_HDRLEN + TCP_HDRLEN) + return 0; + tcp = pkt + IP6_HDRLEN; + if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) + return 0; + return 1; +} +#endif /* DEMAND_SUPPORT */ + +#endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/lcp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/lcp.c new file mode 100644 index 0000000000..90ed183b75 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/lcp.c @@ -0,0 +1,2790 @@ +/* + * lcp.c - PPP Link Control Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#include "netif/ppp/magic.h" + +/* + * When the link comes up we want to be able to wait for a short while, + * or until seeing some input from the peer, before starting to send + * configure-requests. We do this by delaying the fsm_lowerup call. + */ +/* steal a bit in fsm flags word */ +#define DELAYED_UP 0x80 + +static void lcp_delayed_up(void *arg); + +/* + * LCP-related command-line options. + */ +#if 0 /* UNUSED */ +int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ +int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +/* options */ +static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ +static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ +#endif /* UNUSED */ + +#if 0 /* UNUSED */ +#if PPP_LCP_ADAPTIVE +bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ +#endif +bool lax_recv = 0; /* accept control chars in asyncmap */ +bool noendpoint = 0; /* don't send/accept endpoint discriminator */ +#endif /* UNUSED */ + +#if PPP_OPTIONS +static int noopt (char **); +#endif /* PPP_OPTIONS */ + +#ifdef HAVE_MULTILINK +static int setendpoint (char **); +static void printendpoint (option_t *, void (*)(void *, char *, ...), + void *); +#endif /* HAVE_MULTILINK */ + +#if PPP_OPTIONS +static option_t lcp_option_list[] = { + /* LCP options */ + { "-all", o_special_noarg, (void *)noopt, + "Don't request/allow any LCP options" }, + + { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression, + "Disable address/control compression", + OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, + { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression, + "Disable address/control compression", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, + + { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, + "Set asyncmap (for received packets)", + OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, + { "-as", o_uint32, &lcp_wantoptions[0].asyncmap, + "Set asyncmap (for received packets)", + OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, + { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, + "Disable asyncmap negotiation", + OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, + &lcp_allowoptions[0].neg_asyncmap }, + { "-am", o_uint32, &lcp_wantoptions[0].asyncmap, + "Disable asyncmap negotiation", + OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, + &lcp_allowoptions[0].neg_asyncmap }, + + { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber, + "Disable magic number negotiation (looped-back line detection)", + OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, + { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber, + "Disable magic number negotiation (looped-back line detection)", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, + + { "mru", o_int, &lcp_wantoptions[0].mru, + "Set MRU (maximum received packet size) for negotiation", + OPT_PRIO, &lcp_wantoptions[0].neg_mru }, + { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru, + "Disable MRU negotiation (use default 1500)", + OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, + { "-mru", o_bool, &lcp_wantoptions[0].neg_mru, + "Disable MRU negotiation (use default 1500)", + OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, + + { "mtu", o_int, &lcp_allowoptions[0].mru, + "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, + + { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression, + "Disable protocol field compression", + OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, + { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression, + "Disable protocol field compression", + OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, + + { "passive", o_bool, &lcp_wantoptions[0].passive, + "Set passive mode", 1 }, + { "-p", o_bool, &lcp_wantoptions[0].passive, + "Set passive mode", OPT_ALIAS | 1 }, + + { "silent", o_bool, &lcp_wantoptions[0].silent, + "Set silent mode", 1 }, + + { "lcp-echo-failure", o_int, &lcp_echo_fails, + "Set number of consecutive echo failures to indicate link failure", + OPT_PRIO }, + { "lcp-echo-interval", o_int, &lcp_echo_interval, + "Set time in seconds between LCP echo requests", OPT_PRIO }, +#if PPP_LCP_ADAPTIVE + { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, + "Suppress LCP echo requests if traffic was received", 1 }, +#endif + { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, + "Set time in seconds between LCP retransmissions", OPT_PRIO }, + { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, + "Set maximum number of LCP terminate-request transmissions", OPT_PRIO }, + { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits, + "Set maximum number of LCP configure-request transmissions", OPT_PRIO }, + { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops, + "Set limit on number of LCP configure-naks", OPT_PRIO }, + + { "receive-all", o_bool, &lax_recv, + "Accept all received control characters", 1 }, + +#ifdef HAVE_MULTILINK + { "mrru", o_int, &lcp_wantoptions[0].mrru, + "Maximum received packet size for multilink bundle", + OPT_PRIO, &lcp_wantoptions[0].neg_mrru }, + + { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Use short sequence numbers in multilink headers", + OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf }, + { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Don't use short sequence numbers in multilink headers", + OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf }, + + { "endpoint", o_special, (void *) setendpoint, + "Endpoint discriminator for multilink", + OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint }, +#endif /* HAVE_MULTILINK */ + + { "noendpoint", o_bool, &noendpoint, + "Don't send or accept multilink endpoint discriminator", 1 }, + + {NULL} +}; +#endif /* PPP_OPTIONS */ + +/* + * Callbacks for fsm code. (CI = Configuration Information) + */ +static void lcp_resetci(fsm *f); /* Reset our CI */ +static int lcp_cilen(fsm *f); /* Return length of our CI */ +static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */ +static int lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ +static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ +static int lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ +static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */ +static void lcp_up(fsm *f); /* We're UP */ +static void lcp_down(fsm *f); /* We're DOWN */ +static void lcp_starting (fsm *); /* We need lower layer up */ +static void lcp_finished (fsm *); /* We need lower layer down */ +static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len); +static void lcp_rprotrej(fsm *f, u_char *inp, int len); + +/* + * routines to send LCP echos to peer + */ + +static void lcp_echo_lowerup(ppp_pcb *pcb); +static void lcp_echo_lowerdown(ppp_pcb *pcb); +static void LcpEchoTimeout(void *arg); +static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len); +static void LcpSendEchoRequest(fsm *f); +static void LcpLinkFailure(fsm *f); +static void LcpEchoCheck(fsm *f); + +static const fsm_callbacks lcp_callbacks = { /* LCP callback routines */ + lcp_resetci, /* Reset our Configuration Information */ + lcp_cilen, /* Length of our Configuration Information */ + lcp_addci, /* Add our Configuration Information */ + lcp_ackci, /* ACK our Configuration Information */ + lcp_nakci, /* NAK our Configuration Information */ + lcp_rejci, /* Reject our Configuration Information */ + lcp_reqci, /* Request peer's Configuration Information */ + lcp_up, /* Called when fsm reaches OPENED state */ + lcp_down, /* Called when fsm leaves OPENED state */ + lcp_starting, /* Called when we want the lower layer up */ + lcp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + lcp_extcode, /* Called to handle LCP-specific codes */ + "LCP" /* String name of protocol */ +}; + +/* + * Protocol entry points. + * Some of these are called directly. + */ + +static void lcp_init(ppp_pcb *pcb); +static void lcp_input(ppp_pcb *pcb, u_char *p, int len); +static void lcp_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int lcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent lcp_protent = { + PPP_LCP, + lcp_init, + lcp_input, + lcp_protrej, + lcp_lowerup, + lcp_lowerdown, + lcp_open, + lcp_close, +#if PRINTPKT_SUPPORT + lcp_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "LCP", + NULL, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + lcp_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID 2 +#define CILEN_CHAR 3 +#define CILEN_SHORT 4 /* CILEN_VOID + 2 */ +#if CHAP_SUPPORT +#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */ +#endif /* CHAP_SUPPORT */ +#define CILEN_LONG 6 /* CILEN_VOID + 4 */ +#if LQR_SUPPORT +#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */ +#endif /* LQR_SUPPORT */ +#define CILEN_CBCP 3 + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") + +#if PPP_OPTIONS +/* + * noopt - Disable all options (why?). + */ +static int +noopt(argv) + char **argv; +{ + BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); + BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); + + return (1); +} +#endif /* PPP_OPTIONS */ + +#ifdef HAVE_MULTILINK +static int +setendpoint(argv) + char **argv; +{ + if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) { + lcp_wantoptions[0].neg_endpoint = 1; + return 1; + } + option_error("Can't parse '%s' as an endpoint discriminator", *argv); + return 0; +} + +static void +printendpoint(opt, printer, arg) + option_t *opt; + void (*printer) (void *, char *, ...); + void *arg; +{ + printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint)); +} +#endif /* HAVE_MULTILINK */ + +/* + * lcp_init - Initialize LCP. + */ +static void lcp_init(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + + f->pcb = pcb; + f->protocol = PPP_LCP; + f->callbacks = &lcp_callbacks; + + fsm_init(f); + + BZERO(wo, sizeof(*wo)); + wo->neg_mru = 1; + wo->mru = PPP_DEFMRU; + wo->neg_asyncmap = 1; + wo->neg_magicnumber = 1; + wo->neg_pcompression = 1; + wo->neg_accompression = 1; + + BZERO(ao, sizeof(*ao)); + ao->neg_mru = 1; + ao->mru = PPP_MAXMRU; + ao->neg_asyncmap = 1; +#if CHAP_SUPPORT + ao->neg_chap = 1; + ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + ao->neg_upap = 1; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + ao->neg_eap = 1; +#endif /* EAP_SUPPORT */ + ao->neg_magicnumber = 1; + ao->neg_pcompression = 1; + ao->neg_accompression = 1; + ao->neg_endpoint = 1; +} + + +/* + * lcp_open - LCP is allowed to come up. + */ +void lcp_open(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + lcp_options *wo = &pcb->lcp_wantoptions; + + f->flags &= ~(OPT_PASSIVE | OPT_SILENT); + if (wo->passive) + f->flags |= OPT_PASSIVE; + if (wo->silent) + f->flags |= OPT_SILENT; + fsm_open(f); +} + + +/* + * lcp_close - Take LCP down. + */ +void lcp_close(ppp_pcb *pcb, const char *reason) { + fsm *f = &pcb->lcp_fsm; + int oldstate; + + if (pcb->phase != PPP_PHASE_DEAD +#ifdef HAVE_MULTILINK + && pcb->phase != PPP_PHASE_MASTER +#endif /* HAVE_MULTILINK */ + ) + new_phase(pcb, PPP_PHASE_TERMINATE); + + if (f->flags & DELAYED_UP) { + UNTIMEOUT(lcp_delayed_up, f); + f->state = PPP_FSM_STOPPED; + } + oldstate = f->state; + + fsm_close(f, reason); + if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) { + /* + * This action is not strictly according to the FSM in RFC1548, + * but it does mean that the program terminates if you do a + * lcp_close() when a connection hasn't been established + * because we are in passive/silent mode or because we have + * delayed the fsm_lowerup() call and it hasn't happened yet. + */ + f->flags &= ~DELAYED_UP; + lcp_finished(f); + } +} + + +/* + * lcp_lowerup - The lower layer is up. + */ +void lcp_lowerup(ppp_pcb *pcb) { + lcp_options *wo = &pcb->lcp_wantoptions; + fsm *f = &pcb->lcp_fsm; + /* + * Don't use A/C or protocol compression on transmission, + * but accept A/C and protocol compressed packets + * if we are going to ask for A/C and protocol compression. + */ + if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0 + || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff), + wo->neg_pcompression, wo->neg_accompression) < 0) + return; + pcb->peer_mru = PPP_MRU; + + if (pcb->settings.listen_time != 0) { + f->flags |= DELAYED_UP; + TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time); + } else + fsm_lowerup(f); +} + + +/* + * lcp_lowerdown - The lower layer is down. + */ +void lcp_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + UNTIMEOUT(lcp_delayed_up, f); + } else + fsm_lowerdown(f); +} + + +/* + * lcp_delayed_up - Bring the lower layer up now. + */ +static void lcp_delayed_up(void *arg) { + fsm *f = (fsm*)arg; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + fsm_lowerup(f); + } +} + + +/* + * lcp_input - Input LCP packet. + */ +static void lcp_input(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->lcp_fsm; + + if (f->flags & DELAYED_UP) { + f->flags &= ~DELAYED_UP; + UNTIMEOUT(lcp_delayed_up, f); + fsm_lowerup(f); + } + fsm_input(f, p, len); +} + +/* + * lcp_extcode - Handle a LCP-specific code. + */ +static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char *magp; + + switch( code ){ + case PROTREJ: + lcp_rprotrej(f, inp, len); + break; + + case ECHOREQ: + if (f->state != PPP_FSM_OPENED) + break; + magp = inp; + PUTLONG(go->magicnumber, magp); + fsm_sdata(f, ECHOREP, id, inp, len); + break; + + case ECHOREP: + lcp_received_echo_reply(f, id, inp, len); + break; + + case DISCREQ: + case IDENTIF: + case TIMEREM: + break; + + default: + return 0; + } + return 1; +} + + +/* + * lcp_rprotrej - Receive an Protocol-Reject. + * + * Figure out which protocol is rejected and inform it. + */ +static void lcp_rprotrej(fsm *f, u_char *inp, int len) { + int i; + const struct protent *protp; + u_short prot; +#if PPP_PROTOCOLNAME + const char *pname; +#endif /* PPP_PROTOCOLNAME */ + + if (len < 2) { + LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); + return; + } + + GETSHORT(prot, inp); + + /* + * Protocol-Reject packets received in any state other than the LCP + * OPENED state SHOULD be silently discarded. + */ + if( f->state != PPP_FSM_OPENED ){ + LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state)); + return; + } + +#if PPP_PROTOCOLNAME + pname = protocol_name(prot); +#endif /* PPP_PROTOCOLNAME */ + + /* + * Upcall the proper Protocol-Reject routine. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (protp->protocol == prot) { +#if PPP_PROTOCOLNAME + if (pname != NULL) + ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname, + prot); + else +#endif /* PPP_PROTOCOLNAME */ + ppp_dbglog("Protocol-Reject for 0x%x received", prot); + (*protp->protrej)(f->pcb); + return; + } + +#if PPP_PROTOCOLNAME + if (pname != NULL) + ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, + prot); + else +#endif /* #if PPP_PROTOCOLNAME */ + ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot); +} + + +/* + * lcp_protrej - A Protocol-Reject was received. + */ +/*ARGSUSED*/ +static void lcp_protrej(ppp_pcb *pcb) { + /* + * Can't reject LCP! + */ + ppp_error("Received Protocol-Reject for LCP!"); + fsm_protreject(&pcb->lcp_fsm); +} + + +/* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) { + fsm *f = &pcb->lcp_fsm; + /* + * Send back the protocol and the information field of the + * rejected packet. We only get here if LCP is in the OPENED state. + */ +#if 0 + p += 2; + len -= 2; +#endif + + fsm_sdata(f, PROTREJ, ++f->id, + p, len); +} + + +/* + * lcp_resetci - Reset our CI. + */ +static void lcp_resetci(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + +#if PPP_AUTH_SUPPORT + + /* note: default value is true for allow options */ + if (pcb->settings.user && pcb->settings.passwd) { +#if PAP_SUPPORT + if (pcb->settings.refuse_pap) { + ao->neg_upap = 0; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (pcb->settings.refuse_chap) { + ao->chap_mdtype &= ~MDTYPE_MD5; + } +#if MSCHAP_SUPPORT + if (pcb->settings.refuse_mschap) { + ao->chap_mdtype &= ~MDTYPE_MICROSOFT; + } + if (pcb->settings.refuse_mschap_v2) { + ao->chap_mdtype &= ~MDTYPE_MICROSOFT_V2; + } +#endif /* MSCHAP_SUPPORT */ + ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (pcb->settings.refuse_eap) { + ao->neg_eap = 0; + } +#endif /* EAP_SUPPORT */ + +#if PPP_SERVER + /* note: default value is false for wanted options */ + if (pcb->settings.auth_required) { +#if PAP_SUPPORT + if (!pcb->settings.refuse_pap) { + wo->neg_upap = 1; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (!pcb->settings.refuse_chap) { + wo->chap_mdtype |= MDTYPE_MD5; + } +#if MSCHAP_SUPPORT + if (!pcb->settings.refuse_mschap) { + wo->chap_mdtype |= MDTYPE_MICROSOFT; + } + if (!pcb->settings.refuse_mschap_v2) { + wo->chap_mdtype |= MDTYPE_MICROSOFT_V2; + } +#endif /* MSCHAP_SUPPORT */ + wo->neg_chap = (wo->chap_mdtype != MDTYPE_NONE); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (!pcb->settings.refuse_eap) { + wo->neg_eap = 1; + } +#endif /* EAP_SUPPORT */ + } +#endif /* PPP_SERVER */ + + } else { +#if PAP_SUPPORT + ao->neg_upap = 0; +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + ao->neg_chap = 0; + ao->chap_mdtype = MDTYPE_NONE; +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + ao->neg_eap = 0; +#endif /* EAP_SUPPORT */ + } + + PPPDEBUG(LOG_DEBUG, ("ppp: auth protocols:")); +#if PAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" PAP=%d", ao->neg_upap)); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" CHAP=%d CHAP_MD5=%d", ao->neg_chap, !!(ao->chap_mdtype&MDTYPE_MD5))); +#if MSCHAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" CHAP_MS=%d CHAP_MS2=%d", !!(ao->chap_mdtype&MDTYPE_MICROSOFT), !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2))); +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + PPPDEBUG(LOG_DEBUG, (" EAP=%d", ao->neg_eap)); +#endif /* EAP_SUPPORT */ + PPPDEBUG(LOG_DEBUG, ("\n")); + +#endif /* PPP_AUTH_SUPPORT */ + + wo->magicnumber = magic(); + wo->numloops = 0; + *go = *wo; +#ifdef HAVE_MULTILINK + if (!multilink) { + go->neg_mrru = 0; +#endif /* HAVE_MULTILINK */ + go->neg_ssnhf = 0; + go->neg_endpoint = 0; +#ifdef HAVE_MULTILINK + } +#endif /* HAVE_MULTILINK */ + if (pcb->settings.noendpoint) + ao->neg_endpoint = 0; + pcb->peer_mru = PPP_MRU; +#if 0 /* UNUSED */ + auth_reset(pcb); +#endif /* UNUSED */ +} + + +/* + * lcp_cilen - Return length of our CI. + */ +static int lcp_cilen(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + +#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) +#if CHAP_SUPPORT +#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) +#endif /* CHAP_SUPPORT */ +#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) +#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) +#if LQR_SUPPORT +#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) +#endif /* LQR_SUPPORT */ +#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) + /* + * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will + * accept more than one. We prefer EAP first, then CHAP, then + * PAP. + */ + return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + + LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + +#if EAP_SUPPORT + LENCISHORT(go->neg_eap) + +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + LENCICHAP(!go->neg_eap && go->neg_chap) + +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + LENCICHAP(go->neg_chap) + +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) + +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + LENCISHORT(!go->neg_eap && go->neg_upap) + +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + LENCISHORT(!go->neg_chap && go->neg_upap) + +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + LENCISHORT(go->neg_upap) + +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + LENCILQR(go->neg_lqr) + +#endif /* LQR_SUPPORT */ + LENCICBCP(go->neg_cbcp) + + LENCILONG(go->neg_magicnumber) + + LENCIVOID(go->neg_pcompression) + + LENCIVOID(go->neg_accompression) + +#ifdef HAVE_MULTILINK + LENCISHORT(go->neg_mrru) + +#endif /* HAVE_MULTILINK */ + LENCIVOID(go->neg_ssnhf) + + (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0)); +} + + +/* + * lcp_addci - Add our desired CIs to a packet. + */ +static void lcp_addci(fsm *f, u_char *ucp, int *lenp) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char *start_ucp = ucp; + +#define ADDCIVOID(opt, neg) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_VOID, ucp); \ + } +#define ADDCISHORT(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_SHORT, ucp); \ + PUTSHORT(val, ucp); \ + } +#if CHAP_SUPPORT +#define ADDCICHAP(opt, neg, val) \ + if (neg) { \ + PUTCHAR((opt), ucp); \ + PUTCHAR(CILEN_CHAP, ucp); \ + PUTSHORT(PPP_CHAP, ucp); \ + PUTCHAR((CHAP_DIGEST(val)), ucp); \ + } +#endif /* CHAP_SUPPORT */ +#define ADDCILONG(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LONG, ucp); \ + PUTLONG(val, ucp); \ + } +#if LQR_SUPPORT +#define ADDCILQR(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_LQR, ucp); \ + PUTSHORT(PPP_LQR, ucp); \ + PUTLONG(val, ucp); \ + } +#endif /* LQR_SUPPORT */ +#define ADDCICHAR(opt, neg, val) \ + if (neg) { \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR, ucp); \ + PUTCHAR(val, ucp); \ + } +#define ADDCIENDP(opt, neg, class, val, len) \ + if (neg) { \ + int i; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR + len, ucp); \ + PUTCHAR(class, ucp); \ + for (i = 0; i < len; ++i) \ + PUTCHAR(val[i], ucp); \ + } + + ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, + go->asyncmap); +#if EAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); + ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); + ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); + ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); +#ifdef HAVE_MULTILINK + ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru); +#endif + ADDCIVOID(CI_SSNHF, go->neg_ssnhf); + ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + if (ucp - start_ucp != *lenp) { + /* this should never happen, because peer_mtu should be 1500 */ + ppp_error("Bug in lcp_addci: wrong length"); + } +} + + +/* + * lcp_ackci - Ack our CIs. + * This should not modify any state if the Ack is bad. + * + * Returns: + * 0 - Ack was bad. + * 1 - Ack was good. + */ +static int lcp_ackci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char cilen, citype, cichar; + u_short cishort; + u32_t cilong; + + /* + * CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define ACKCIVOID(opt, neg) \ + if (neg) { \ + if ((len -= CILEN_VOID) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_VOID || \ + citype != opt) \ + goto bad; \ + } +#define ACKCISHORT(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_SHORT) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_SHORT || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != val) \ + goto bad; \ + } +#define ACKCICHAR(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_CHAR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAR || \ + citype != opt) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != val) \ + goto bad; \ + } +#if CHAP_SUPPORT +#define ACKCICHAP(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_CHAP) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAP || \ + citype != (opt)) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != PPP_CHAP) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != (CHAP_DIGEST(val))) \ + goto bad; \ + } +#endif /* CHAP_SUPPORT */ +#define ACKCILONG(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_LONG) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_LONG || \ + citype != opt) \ + goto bad; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + goto bad; \ + } +#if LQR_SUPPORT +#define ACKCILQR(opt, neg, val) \ + if (neg) { \ + if ((len -= CILEN_LQR) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_LQR || \ + citype != opt) \ + goto bad; \ + GETSHORT(cishort, p); \ + if (cishort != PPP_LQR) \ + goto bad; \ + GETLONG(cilong, p); \ + if (cilong != val) \ + goto bad; \ + } +#endif /* LQR_SUPPORT */ +#define ACKCIENDP(opt, neg, class, val, vlen) \ + if (neg) { \ + int i; \ + if ((len -= CILEN_CHAR + vlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAR + vlen || \ + citype != opt) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != class) \ + goto bad; \ + for (i = 0; i < vlen; ++i) { \ + GETCHAR(cichar, p); \ + if (cichar != val[i]) \ + goto bad; \ + } \ + } + + ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); + ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, + go->asyncmap); +#if EAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT + ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); +#endif /* EAP_SUPPORT */ +#if !EAP_SUPPORT + ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); +#endif /* !EAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ +#if EAP_SUPPORT && CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && CHAP_SUPPORT */ +#if EAP_SUPPORT && !CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); +#endif /* EAP_SUPPORT && !CHAP_SUPPORT */ +#if !EAP_SUPPORT && CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && CHAP_SUPPORT */ +#if !EAP_SUPPORT && !CHAP_SUPPORT + ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); +#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ +#endif /* PAP_SUPPORT */ +#if LQR_SUPPORT + ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); + ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); + ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); + ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); +#ifdef HAVE_MULTILINK + ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru); +#endif /* HAVE_MULTILINK */ + ACKCIVOID(CI_SSNHF, go->neg_ssnhf); + ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + return (1); +bad: + LCPDEBUG(("lcp_acki: received bad Ack!")); + return (0); +} + + +/* + * lcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if LCP is in the OPENED state. + * + * Returns: + * 0 - Nak was bad. + * 1 - Nak was good. + */ +static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *wo = &pcb->lcp_wantoptions; + u_char citype, cichar, *next; + u_short cishort; + u32_t cilong; + lcp_options no; /* options we've seen Naks for */ + lcp_options try_; /* options to request next time */ + int looped_back = 0; + int cilen; + + BZERO(&no, sizeof(no)); + try_ = *go; + + /* + * Any Nak'd CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define NAKCIVOID(opt, neg) \ + if (go->neg && \ + len >= CILEN_VOID && \ + p[1] == CILEN_VOID && \ + p[0] == opt) { \ + len -= CILEN_VOID; \ + INCPTR(CILEN_VOID, p); \ + no.neg = 1; \ + try_.neg = 0; \ + } +#if CHAP_SUPPORT +#define NAKCICHAP(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + no.neg = 1; \ + code \ + } +#endif /* CHAP_SUPPORT */ +#define NAKCICHAR(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_CHAR && \ + p[1] == CILEN_CHAR && \ + p[0] == opt) { \ + len -= CILEN_CHAR; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + no.neg = 1; \ + code \ + } +#define NAKCISHORT(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_SHORT && \ + p[1] == CILEN_SHORT && \ + p[0] == opt) { \ + len -= CILEN_SHORT; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + no.neg = 1; \ + code \ + } +#define NAKCILONG(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_LONG && \ + p[1] == CILEN_LONG && \ + p[0] == opt) { \ + len -= CILEN_LONG; \ + INCPTR(2, p); \ + GETLONG(cilong, p); \ + no.neg = 1; \ + code \ + } +#if LQR_SUPPORT +#define NAKCILQR(opt, neg, code) \ + if (go->neg && \ + len >= CILEN_LQR && \ + p[1] == CILEN_LQR && \ + p[0] == opt) { \ + len -= CILEN_LQR; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETLONG(cilong, p); \ + no.neg = 1; \ + code \ + } +#endif /* LQR_SUPPORT */ +#define NAKCIENDP(opt, neg) \ + if (go->neg && \ + len >= CILEN_CHAR && \ + p[0] == opt && \ + p[1] >= CILEN_CHAR && \ + p[1] <= len) { \ + len -= p[1]; \ + INCPTR(p[1], p); \ + no.neg = 1; \ + try_.neg = 0; \ + } + + /* + * NOTE! There must be no assignments to individual fields of *go in + * the code below. Any such assignment is a BUG! + */ + /* + * We don't care if they want to send us smaller packets than + * we want. Therefore, accept any MRU less than what we asked for, + * but then ignore the new value when setting the MRU in the kernel. + * If they send us a bigger MRU than what we asked, accept it, up to + * the limit of the default MRU we'd get if we didn't negotiate. + */ + if (go->neg_mru && go->mru != PPP_DEFMRU) { + NAKCISHORT(CI_MRU, neg_mru, + if (cishort <= wo->mru || cishort <= PPP_DEFMRU) + try_.mru = cishort; + ); + } + + /* + * Add any characters they want to our (receive-side) asyncmap. + */ + if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) { + NAKCILONG(CI_ASYNCMAP, neg_asyncmap, + try_.asyncmap = go->asyncmap | cilong; + ); + } + + /* + * If they've nak'd our authentication-protocol, check whether + * they are proposing a different protocol, or a different + * hash algorithm for CHAP. + */ + if ((0 +#if CHAP_SUPPORT + || go->neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap +#endif /* EAP_SUPPORT */ + ) + && len >= CILEN_SHORT + && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { + cilen = p[1]; + len -= cilen; +#if CHAP_SUPPORT + no.neg_chap = go->neg_chap; +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + no.neg_upap = go->neg_upap; +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + no.neg_eap = go->neg_eap; +#endif /* EAP_SUPPORT */ + INCPTR(2, p); + GETSHORT(cishort, p); + +#if PAP_SUPPORT + if (cishort == PPP_PAP && cilen == CILEN_SHORT) { +#if EAP_SUPPORT + /* If we were asking for EAP, then we need to stop that. */ + if (go->neg_eap) + try_.neg_eap = 0; + else +#endif /* EAP_SUPPORT */ + +#if CHAP_SUPPORT + /* If we were asking for CHAP, then we need to stop that. */ + if (go->neg_chap) + try_.neg_chap = 0; + else +#endif /* CHAP_SUPPORT */ + + /* + * If we weren't asking for CHAP or EAP, then we were asking for + * PAP, in which case this Nak is bad. + */ + goto bad; + } else +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { + GETCHAR(cichar, p); +#if EAP_SUPPORT + /* Stop asking for EAP, if we were. */ + if (go->neg_eap) { + try_.neg_eap = 0; + /* Try to set up to use their suggestion, if possible */ + if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) + try_.chap_mdtype = CHAP_MDTYPE_D(cichar); + } else +#endif /* EAP_SUPPORT */ + if (go->neg_chap) { + /* + * We were asking for our preferred algorithm, they must + * want something different. + */ + if (cichar != CHAP_DIGEST(go->chap_mdtype)) { + if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) { + /* Use their suggestion if we support it ... */ + try_.chap_mdtype = CHAP_MDTYPE_D(cichar); + } else { + /* ... otherwise, try our next-preferred algorithm. */ + try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype)); + if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */ + try_.neg_chap = 0; + } + } else { + /* + * Whoops, they Nak'd our algorithm of choice + * but then suggested it back to us. + */ + goto bad; + } + } else { + /* + * Stop asking for PAP if we were asking for it. + */ +#if PAP_SUPPORT + try_.neg_upap = 0; +#endif /* PAP_SUPPORT */ + } + + } else +#endif /* CHAP_SUPPORT */ + { + +#if EAP_SUPPORT + /* + * If we were asking for EAP, and they're Conf-Naking EAP, + * well, that's just strange. Nobody should do that. + */ + if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap) + ppp_dbglog("Unexpected Conf-Nak for EAP"); + + /* + * We don't recognize what they're suggesting. + * Stop asking for what we were asking for. + */ + if (go->neg_eap) + try_.neg_eap = 0; + else +#endif /* EAP_SUPPORT */ + +#if CHAP_SUPPORT + if (go->neg_chap) + try_.neg_chap = 0; + else +#endif /* CHAP_SUPPORT */ + +#if PAP_SUPPORT + if(1) + try_.neg_upap = 0; + else +#endif /* PAP_SUPPORT */ + {} + + p += cilen - CILEN_SHORT; + } + } + +#if LQR_SUPPORT + /* + * If they can't cope with our link quality protocol, we'll have + * to stop asking for LQR. We haven't got any other protocol. + * If they Nak the reporting period, take their value XXX ? + */ + NAKCILQR(CI_QUALITY, neg_lqr, + if (cishort != PPP_LQR) + try_.neg_lqr = 0; + else + try_.lqr_period = cilong; + ); +#endif /* LQR_SUPPORT */ + + /* + * Only implementing CBCP...not the rest of the callback options + */ + NAKCICHAR(CI_CALLBACK, neg_cbcp, + try_.neg_cbcp = 0; + (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */ + ); + + /* + * Check for a looped-back line. + */ + NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, + try_.magicnumber = magic(); + looped_back = 1; + ); + + /* + * Peer shouldn't send Nak for protocol compression or + * address/control compression requests; they should send + * a Reject instead. If they send a Nak, treat it as a Reject. + */ + NAKCIVOID(CI_PCOMPRESSION, neg_pcompression); + NAKCIVOID(CI_ACCOMPRESSION, neg_accompression); + +#ifdef HAVE_MULTILINK + /* + * Nak for MRRU option - accept their value if it is smaller + * than the one we want. + */ + if (go->neg_mrru) { + NAKCISHORT(CI_MRRU, neg_mrru, + if (treat_as_reject) + try_.neg_mrru = 0; + else if (cishort <= wo->mrru) + try_.mrru = cishort; + ); + } +#else /* HAVE_MULTILINK */ + LWIP_UNUSED_ARG(treat_as_reject); +#endif /* HAVE_MULTILINK */ + + /* + * Nak for short sequence numbers shouldn't be sent, treat it + * like a reject. + */ + NAKCIVOID(CI_SSNHF, neg_ssnhf); + + /* + * Nak of the endpoint discriminator option is not permitted, + * treat it like a reject. + */ + NAKCIENDP(CI_EPDISC, neg_endpoint); + + /* + * There may be remaining CIs, if the peer is requesting negotiation + * on an option that we didn't include in our request packet. + * If we see an option that we requested, or one we've already seen + * in this packet, then this packet is bad. + * If we wanted to respond by starting to negotiate on the requested + * option(s), we could, but we don't, because except for the + * authentication type and quality protocol, if we are not negotiating + * an option, it is because we were told not to. + * For the authentication type, the Nak from the peer means + * `let me authenticate myself with you' which is a bit pointless. + * For the quality protocol, the Nak means `ask me to send you quality + * reports', but if we didn't ask for them, we don't want them. + * An option we don't recognize represents the peer asking to + * negotiate some option we don't support, so ignore it. + */ + while (len >= CILEN_VOID) { + GETCHAR(citype, p); + GETCHAR(cilen, p); + if (cilen < CILEN_VOID || (len -= cilen) < 0) + goto bad; + next = p + cilen - 2; + + switch (citype) { + case CI_MRU: + if ((go->neg_mru && go->mru != PPP_DEFMRU) + || no.neg_mru || cilen != CILEN_SHORT) + goto bad; + GETSHORT(cishort, p); + if (cishort < PPP_DEFMRU) { + try_.neg_mru = 1; + try_.mru = cishort; + } + break; + case CI_ASYNCMAP: + if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + || no.neg_asyncmap || cilen != CILEN_LONG) + goto bad; + break; + case CI_AUTHTYPE: + if (0 +#if CHAP_SUPPORT + || go->neg_chap || no.neg_chap +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + || go->neg_upap || no.neg_upap +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + || go->neg_eap || no.neg_eap +#endif /* EAP_SUPPORT */ + ) + goto bad; + break; + case CI_MAGICNUMBER: + if (go->neg_magicnumber || no.neg_magicnumber || + cilen != CILEN_LONG) + goto bad; + break; + case CI_PCOMPRESSION: + if (go->neg_pcompression || no.neg_pcompression + || cilen != CILEN_VOID) + goto bad; + break; + case CI_ACCOMPRESSION: + if (go->neg_accompression || no.neg_accompression + || cilen != CILEN_VOID) + goto bad; + break; +#if LQR_SUPPORT + case CI_QUALITY: + if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) + goto bad; + break; +#endif /* LQR_SUPPORT */ +#ifdef HAVE_MULTILINK + case CI_MRRU: + if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT) + goto bad; + break; +#endif /* HAVE_MULTILINK */ + case CI_SSNHF: + if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID) + goto bad; + try_.neg_ssnhf = 1; + break; + case CI_EPDISC: + if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR) + goto bad; + break; + default: + break; + } + p = next; + } + + /* + * OK, the Nak is good. Now we can update state. + * If there are any options left we ignore them. + */ + if (f->state != PPP_FSM_OPENED) { + if (looped_back) { + if (++try_.numloops >= pcb->settings.lcp_loopbackfail) { + ppp_notice("Serial line is looped back."); + pcb->err_code = PPPERR_LOOPBACK; + lcp_close(f->pcb, "Loopback detected"); + } + } else + try_.numloops = 0; + *go = try_; + } + + return 1; + +bad: + LCPDEBUG(("lcp_nakci: received bad Nak!")); + return 0; +} + + +/* + * lcp_rejci - Peer has Rejected some of our CIs. + * This should not modify any state if the Reject is bad + * or if LCP is in the OPENED state. + * + * Returns: + * 0 - Reject was bad. + * 1 - Reject was good. + */ +static int lcp_rejci(fsm *f, u_char *p, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u_char cichar; + u_short cishort; + u32_t cilong; + lcp_options try_; /* options to request next time */ + + try_ = *go; + + /* + * Any Rejected CIs must be in exactly the same order that we sent. + * Check packet length and CI length at each step. + * If we find any deviations, then this packet is bad. + */ +#define REJCIVOID(opt, neg) \ + if (go->neg && \ + len >= CILEN_VOID && \ + p[1] == CILEN_VOID && \ + p[0] == opt) { \ + len -= CILEN_VOID; \ + INCPTR(CILEN_VOID, p); \ + try_.neg = 0; \ + } +#define REJCISHORT(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_SHORT && \ + p[1] == CILEN_SHORT && \ + p[0] == opt) { \ + len -= CILEN_SHORT; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + /* Check rejected value. */ \ + if (cishort != val) \ + goto bad; \ + try_.neg = 0; \ + } + +#if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_eap = try_.neg_upap = 0; \ + } +#endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */ + +#if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_upap = 0; \ + } +#endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */ + +#if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + try_.neg_eap = 0; \ + } +#endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */ + +#if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT +#define REJCICHAP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CHAP && \ + p[1] == CILEN_CHAP && \ + p[0] == opt) { \ + len -= CILEN_CHAP; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */ + +#define REJCILONG(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_LONG && \ + p[1] == CILEN_LONG && \ + p[0] == opt) { \ + len -= CILEN_LONG; \ + INCPTR(2, p); \ + GETLONG(cilong, p); \ + /* Check rejected value. */ \ + if (cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } +#if LQR_SUPPORT +#define REJCILQR(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_LQR && \ + p[1] == CILEN_LQR && \ + p[0] == opt) { \ + len -= CILEN_LQR; \ + INCPTR(2, p); \ + GETSHORT(cishort, p); \ + GETLONG(cilong, p); \ + /* Check rejected value. */ \ + if (cishort != PPP_LQR || cilong != val) \ + goto bad; \ + try_.neg = 0; \ + } +#endif /* LQR_SUPPORT */ +#define REJCICBCP(opt, neg, val) \ + if (go->neg && \ + len >= CILEN_CBCP && \ + p[1] == CILEN_CBCP && \ + p[0] == opt) { \ + len -= CILEN_CBCP; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + /* Check rejected value. */ \ + if (cichar != val) \ + goto bad; \ + try_.neg = 0; \ + } +#define REJCIENDP(opt, neg, class, val, vlen) \ + if (go->neg && \ + len >= CILEN_CHAR + vlen && \ + p[0] == opt && \ + p[1] == CILEN_CHAR + vlen) { \ + int i; \ + len -= CILEN_CHAR + vlen; \ + INCPTR(2, p); \ + GETCHAR(cichar, p); \ + if (cichar != class) \ + goto bad; \ + for (i = 0; i < vlen; ++i) { \ + GETCHAR(cichar, p); \ + if (cichar != val[i]) \ + goto bad; \ + } \ + try_.neg = 0; \ + } + + REJCISHORT(CI_MRU, neg_mru, go->mru); + REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); +#if EAP_SUPPORT + REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP); + if (!go->neg_eap) { +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype); + if (!go->neg_chap) { +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + } +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + } +#endif /* EAP_SUPPORT */ +#if LQR_SUPPORT + REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); +#endif /* LQR_SUPPORT */ + REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); + REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); + REJCIVOID(CI_PCOMPRESSION, neg_pcompression); + REJCIVOID(CI_ACCOMPRESSION, neg_accompression); +#ifdef HAVE_MULTILINK + REJCISHORT(CI_MRRU, neg_mrru, go->mrru); +#endif /* HAVE_MULTILINK */ + REJCIVOID(CI_SSNHF, neg_ssnhf); + REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_, + go->endpoint.value, go->endpoint.length); + + /* + * If there are any remaining CIs, then this packet is bad. + */ + if (len != 0) + goto bad; + /* + * Now we can update state. + */ + if (f->state != PPP_FSM_OPENED) + *go = try_; + return 1; + +bad: + LCPDEBUG(("lcp_rejci: received bad Reject!")); + return 0; +} + + +/* + * lcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately. If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + * + * inp = Requested CIs + * lenp = Length of requested CIs + */ +static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ho = &pcb->lcp_hisoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + u_char *cip, *next; /* Pointer to current and next CIs */ + int cilen, citype, cichar; /* Parsed len, type, char value */ + u_short cishort; /* Parsed short value */ + u32_t cilong; /* Parse long value */ + int rc = CONFACK; /* Final packet return code */ + int orc; /* Individual option return code */ + u_char *p; /* Pointer to next char to parse */ + u_char *rejp; /* Pointer to next char in reject frame */ + struct pbuf *nakp; /* Nak buffer */ + u_char *nakoutp; /* Pointer to next char in Nak frame */ + int l = *lenp; /* Length left */ + + /* + * Reset all his options. + */ + BZERO(ho, sizeof(*ho)); + + /* + * Process all his options. + */ + next = inp; + nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); + if(NULL == nakp) + return 0; + if(nakp->tot_len != nakp->len) { + pbuf_free(nakp); + return 0; + } + + nakoutp = (u_char*)nakp->payload; + rejp = inp; + while (l) { + orc = CONFACK; /* Assume success */ + cip = p = next; /* Remember begining of CI */ + if (l < 2 || /* Not enough data for CI header or */ + p[1] < 2 || /* CI length too small or */ + p[1] > l) { /* CI length too big? */ + LCPDEBUG(("lcp_reqci: bad CI length!")); + orc = CONFREJ; /* Reject bad CI */ + cilen = l; /* Reject till end of packet */ + l = 0; /* Don't loop again */ + citype = 0; + goto endswitch; + } + GETCHAR(citype, p); /* Parse CI type */ + GETCHAR(cilen, p); /* Parse CI length */ + l -= cilen; /* Adjust remaining length */ + next += cilen; /* Step to next CI */ + + switch (citype) { /* Check CI type */ + case CI_MRU: + if (!ao->neg_mru || /* Allow option? */ + cilen != CILEN_SHORT) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETSHORT(cishort, p); /* Parse MRU */ + + /* + * He must be able to receive at least our minimum. + * No need to check a maximum. If he sends a large number, + * we'll just ignore it. + */ + if (cishort < PPP_MINMRU) { + orc = CONFNAK; /* Nak CI */ + PUTCHAR(CI_MRU, nakoutp); + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_MINMRU, nakoutp); /* Give him a hint */ + break; + } + ho->neg_mru = 1; /* Remember he sent MRU */ + ho->mru = cishort; /* And remember value */ + break; + + case CI_ASYNCMAP: + if (!ao->neg_asyncmap || + cilen != CILEN_LONG) { + orc = CONFREJ; + break; + } + GETLONG(cilong, p); + + /* + * Asyncmap must have set at least the bits + * which are set in lcp_allowoptions[unit].asyncmap. + */ + if ((ao->asyncmap & ~cilong) != 0) { + orc = CONFNAK; + PUTCHAR(CI_ASYNCMAP, nakoutp); + PUTCHAR(CILEN_LONG, nakoutp); + PUTLONG(ao->asyncmap | cilong, nakoutp); + break; + } + ho->neg_asyncmap = 1; + ho->asyncmap = cilong; + break; + + case CI_AUTHTYPE: + if (cilen < CILEN_SHORT || + !(0 +#if PAP_SUPPORT + || ao->neg_upap +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || ao->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || ao->neg_eap +#endif /* EAP_SUPPORT */ + )) { + /* + * Reject the option if we're not willing to authenticate. + */ + ppp_dbglog("No auth is possible"); + orc = CONFREJ; + break; + } + GETSHORT(cishort, p); + + /* + * Authtype must be PAP, CHAP, or EAP. + * + * Note: if more than one of ao->neg_upap, ao->neg_chap, and + * ao->neg_eap are set, and the peer sends a Configure-Request + * with two or more authenticate-protocol requests, then we will + * reject the second request. + * Whether we end up doing CHAP, UPAP, or EAP depends then on + * the ordering of the CIs in the peer's Configure-Request. + */ + +#if PAP_SUPPORT + if (cishort == PPP_PAP) { + /* we've already accepted CHAP or EAP */ + if (0 +#if CHAP_SUPPORT + || ho->neg_chap +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || ho->neg_eap +#endif /* EAP_SUPPORT */ + || cilen != CILEN_SHORT) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_upap) { /* we don't want to do PAP */ + orc = CONFNAK; /* NAK it and suggest CHAP or EAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_EAP, nakoutp); + } else { +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + } +#endif /* EAP_SUPPORT */ + break; + } + ho->neg_upap = 1; + break; + } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + if (cishort == PPP_CHAP) { + /* we've already accepted PAP or EAP */ + if ( +#if PAP_SUPPORT + ho->neg_upap || +#endif /* PAP_SUPPORT */ +#if EAP_SUPPORT + ho->neg_eap || +#endif /* EAP_SUPPORT */ + cilen != CILEN_CHAP) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_chap) { /* we don't want to do CHAP */ + orc = CONFNAK; /* NAK it and suggest EAP or PAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); + PUTCHAR(CILEN_SHORT, nakoutp); +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTSHORT(PPP_EAP, nakoutp); + } else +#endif /* EAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTSHORT(PPP_PAP, nakoutp); + } + else +#endif /* PAP_SUPPORT */ + {} + break; + } + GETCHAR(cichar, p); /* get digest type */ + if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) { + /* + * We can't/won't do the requested type, + * suggest something else. + */ + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakoutp); + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + break; + } + ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */ + ho->neg_chap = 1; + break; + } +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + if (cishort == PPP_EAP) { + /* we've already accepted CHAP or PAP */ + if ( +#if CHAP_SUPPORT + ho->neg_chap || +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + ho->neg_upap || +#endif /* PAP_SUPPORT */ + cilen != CILEN_SHORT) { + LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting...")); + orc = CONFREJ; + break; + } + if (!ao->neg_eap) { /* we don't want to do EAP */ + orc = CONFNAK; /* NAK it and suggest CHAP or PAP */ + PUTCHAR(CI_AUTHTYPE, nakoutp); +#if CHAP_SUPPORT + if (ao->neg_chap) { + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_PAP, nakoutp); + } else +#endif /* PAP_SUPPORT */ + {} + break; + } + ho->neg_eap = 1; + break; + } +#endif /* EAP_SUPPORT */ + + /* + * We don't recognize the protocol they're asking for. + * Nak it with something we're willing to do. + * (At this point we know ao->neg_upap || ao->neg_chap || + * ao->neg_eap.) + */ + orc = CONFNAK; + PUTCHAR(CI_AUTHTYPE, nakoutp); + +#if EAP_SUPPORT + if (ao->neg_eap) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_EAP, nakoutp); + } else +#endif /* EAP_SUPPORT */ +#if CHAP_SUPPORT + if (ao->neg_chap) { + PUTCHAR(CILEN_CHAP, nakoutp); + PUTSHORT(PPP_CHAP, nakoutp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); + } else +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT + if(1) { + PUTCHAR(CILEN_SHORT, nakoutp); + PUTSHORT(PPP_PAP, nakoutp); + } else +#endif /* PAP_SUPPORT */ + {} + break; + +#if LQR_SUPPORT + case CI_QUALITY: + if (!ao->neg_lqr || + cilen != CILEN_LQR) { + orc = CONFREJ; + break; + } + + GETSHORT(cishort, p); + GETLONG(cilong, p); + + /* + * Check the protocol and the reporting period. + * XXX When should we Nak this, and what with? + */ + if (cishort != PPP_LQR) { + orc = CONFNAK; + PUTCHAR(CI_QUALITY, nakoutp); + PUTCHAR(CILEN_LQR, nakoutp); + PUTSHORT(PPP_LQR, nakoutp); + PUTLONG(ao->lqr_period, nakoutp); + break; + } + break; +#endif /* LQR_SUPPORT */ + + case CI_MAGICNUMBER: + if (!(ao->neg_magicnumber || go->neg_magicnumber) || + cilen != CILEN_LONG) { + orc = CONFREJ; + break; + } + GETLONG(cilong, p); + + /* + * He must have a different magic number. + */ + if (go->neg_magicnumber && + cilong == go->magicnumber) { + cilong = magic(); /* Don't put magic() inside macro! */ + orc = CONFNAK; + PUTCHAR(CI_MAGICNUMBER, nakoutp); + PUTCHAR(CILEN_LONG, nakoutp); + PUTLONG(cilong, nakoutp); + break; + } + ho->neg_magicnumber = 1; + ho->magicnumber = cilong; + break; + + + case CI_PCOMPRESSION: + if (!ao->neg_pcompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_pcompression = 1; + break; + + case CI_ACCOMPRESSION: + if (!ao->neg_accompression || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_accompression = 1; + break; + +#ifdef HAVE_MULTILINK + case CI_MRRU: + if (!ao->neg_mrru + || !multilink + || cilen != CILEN_SHORT) { + orc = CONFREJ; + break; + } + + GETSHORT(cishort, p); + /* possibly should insist on a minimum/maximum MRRU here */ + ho->neg_mrru = 1; + ho->mrru = cishort; + break; +#endif /* HAVE_MULTILINK */ + + case CI_SSNHF: + if (!ao->neg_ssnhf +#ifdef HAVE_MULTILINK + || !multilink +#endif /* HAVE_MULTILINK */ + || cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_ssnhf = 1; + break; + + case CI_EPDISC: + if (!ao->neg_endpoint || + cilen < CILEN_CHAR || + cilen > CILEN_CHAR + MAX_ENDP_LEN) { + orc = CONFREJ; + break; + } + GETCHAR(cichar, p); + cilen -= CILEN_CHAR; + ho->neg_endpoint = 1; + ho->endpoint.class_ = cichar; + ho->endpoint.length = cilen; + MEMCPY(ho->endpoint.value, p, cilen); + INCPTR(cilen, p); + break; + + default: + LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype)); + orc = CONFREJ; + break; + } + +endswitch: + if (orc == CONFACK && /* Good CI */ + rc != CONFACK) /* but prior CI wasnt? */ + continue; /* Don't send this one */ + + if (orc == CONFNAK) { /* Nak this CI? */ + if (reject_if_disagree /* Getting fed up with sending NAKs? */ + && citype != CI_MAGICNUMBER) { + orc = CONFREJ; /* Get tough if so */ + } else { + if (rc == CONFREJ) /* Rejecting prior CI? */ + continue; /* Don't send this one */ + rc = CONFNAK; + } + } + if (orc == CONFREJ) { /* Reject this CI */ + rc = CONFREJ; + if (cip != rejp) /* Need to move rejected CI? */ + MEMCPY(rejp, cip, cilen); /* Move it */ + INCPTR(cilen, rejp); /* Update output pointer */ + } + } + + /* + * If we wanted to send additional NAKs (for unsent CIs), the + * code would go here. The extra NAKs would go at *nakoutp. + * At present there are no cases where we want to ask the + * peer to negotiate an option. + */ + + switch (rc) { + case CONFACK: + *lenp = next - inp; + break; + case CONFNAK: + /* + * Copy the Nak'd options from the nak buffer to the caller's buffer. + */ + *lenp = nakoutp - (u_char*)nakp->payload; + MEMCPY(inp, nakp->payload, *lenp); + break; + case CONFREJ: + *lenp = rejp - inp; + break; + default: + break; + } + + pbuf_free(nakp); + LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc))); + return (rc); /* Return final code */ +} + + +/* + * lcp_up - LCP has come UP. + */ +static void lcp_up(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *wo = &pcb->lcp_wantoptions; + lcp_options *ho = &pcb->lcp_hisoptions; + lcp_options *go = &pcb->lcp_gotoptions; + lcp_options *ao = &pcb->lcp_allowoptions; + int mtu, mru; + + if (!go->neg_magicnumber) + go->magicnumber = 0; + if (!ho->neg_magicnumber) + ho->magicnumber = 0; + + /* + * Set our MTU to the smaller of the MTU we wanted and + * the MRU our peer wanted. If we negotiated an MRU, + * set our MRU to the larger of value we wanted and + * the value we got in the negotiation. + * Note on the MTU: the link MTU can be the MRU the peer wanted, + * the interface MTU is set to the lowest of that, the + * MTU we want to use, and our link MRU. + */ + mtu = ho->neg_mru? ho->mru: PPP_MRU; + mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU; +#ifdef HAVE_MULTILINK + if (!(multilink && go->neg_mrru && ho->neg_mrru)) +#endif /* HAVE_MULTILINK */ + netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); + ppp_send_config(pcb, mtu, + (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), + ho->neg_pcompression, ho->neg_accompression); + ppp_recv_config(pcb, mru, + (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff), + go->neg_pcompression, go->neg_accompression); + + if (ho->neg_mru) + pcb->peer_mru = ho->mru; + + lcp_echo_lowerup(f->pcb); /* Enable echo messages */ + + link_established(pcb); +} + + +/* + * lcp_down - LCP has gone DOWN. + * + * Alert other protocols. + */ +static void lcp_down(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + + lcp_echo_lowerdown(f->pcb); + + link_down(pcb); + + ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0); + ppp_recv_config(pcb, PPP_MRU, + (go->neg_asyncmap? go->asyncmap: 0xffffffff), + go->neg_pcompression, go->neg_accompression); + pcb->peer_mru = PPP_MRU; +} + + +/* + * lcp_starting - LCP needs the lower layer up. + */ +static void lcp_starting(fsm *f) { + ppp_pcb *pcb = f->pcb; + link_required(pcb); +} + + +/* + * lcp_finished - LCP has finished with the lower layer. + */ +static void lcp_finished(fsm *f) { + ppp_pcb *pcb = f->pcb; + link_terminated(pcb); +} + + +#if PRINTPKT_SUPPORT +/* + * lcp_printpkt - print the contents of an LCP packet. + */ +static const char* const lcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej", "ProtRej", + "EchoReq", "EchoRep", "DiscReq", "Ident", + "TimeRem" +}; + +static int lcp_printpkt(const u_char *p, int plen, + void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len, olen, i; + const u_char *pstart, *optend; + u_short cishort; + u32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(lcp_codenames)) + printer(arg, " %s", lcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case CI_MRU: + if (olen == CILEN_SHORT) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "mru %d", cishort); + } + break; + case CI_ASYNCMAP: + if (olen == CILEN_LONG) { + p += 2; + GETLONG(cilong, p); + printer(arg, "asyncmap 0x%x", cilong); + } + break; + case CI_AUTHTYPE: + if (olen >= CILEN_SHORT) { + p += 2; + printer(arg, "auth "); + GETSHORT(cishort, p); + switch (cishort) { +#if PAP_SUPPORT + case PPP_PAP: + printer(arg, "pap"); + break; +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + case PPP_CHAP: + printer(arg, "chap"); + if (p < optend) { + switch (*p) { + case CHAP_MD5: + printer(arg, " MD5"); + ++p; + break; +#if MSCHAP_SUPPORT + case CHAP_MICROSOFT: + printer(arg, " MS"); + ++p; + break; + + case CHAP_MICROSOFT_V2: + printer(arg, " MS-v2"); + ++p; + break; +#endif /* MSCHAP_SUPPORT */ + default: + break; + } + } + break; +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + case PPP_EAP: + printer(arg, "eap"); + break; +#endif /* EAP_SUPPORT */ + default: + printer(arg, "0x%x", cishort); + } + } + break; +#if LQR_SUPPORT + case CI_QUALITY: + if (olen >= CILEN_SHORT) { + p += 2; + printer(arg, "quality "); + GETSHORT(cishort, p); + switch (cishort) { + case PPP_LQR: + printer(arg, "lqr"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; +#endif /* LQR_SUPPORT */ + case CI_CALLBACK: + if (olen >= CILEN_CHAR) { + p += 2; + printer(arg, "callback "); + GETCHAR(cishort, p); + switch (cishort) { + case CBCP_OPT: + printer(arg, "CBCP"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; + case CI_MAGICNUMBER: + if (olen == CILEN_LONG) { + p += 2; + GETLONG(cilong, p); + printer(arg, "magic 0x%x", cilong); + } + break; + case CI_PCOMPRESSION: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "pcomp"); + } + break; + case CI_ACCOMPRESSION: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "accomp"); + } + break; + case CI_MRRU: + if (olen == CILEN_SHORT) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "mrru %d", cishort); + } + break; + case CI_SSNHF: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "ssnhf"); + } + break; + case CI_EPDISC: +#ifdef HAVE_MULTILINK + if (olen >= CILEN_CHAR) { + struct epdisc epd; + p += 2; + GETCHAR(epd.class, p); + epd.length = olen - CILEN_CHAR; + if (epd.length > MAX_ENDP_LEN) + epd.length = MAX_ENDP_LEN; + if (epd.length > 0) { + MEMCPY(epd.value, p, epd.length); + p += epd.length; + } + printer(arg, "endpoint [%s]", epdisc_to_str(&epd)); + } +#else + printer(arg, "endpoint"); +#endif + break; + default: + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + + case ECHOREQ: + case ECHOREP: + case DISCREQ: + if (len >= 4) { + GETLONG(cilong, p); + printer(arg, " magic=0x%x", cilong); + len -= 4; + } + break; + + case IDENTIF: + case TIMEREM: + if (len >= 4) { + GETLONG(cilong, p); + printer(arg, " magic=0x%x", cilong); + len -= 4; + } + if (code == TIMEREM) { + if (len < 4) + break; + GETLONG(cilong, p); + printer(arg, " seconds=%u", cilong); + len -= 4; + } + if (len > 0) { + printer(arg, " "); + ppp_print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (i = 0; i < len && i < 32; ++i) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + if (i < len) { + printer(arg, " ..."); + p += len - i; + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +/* + * Time to shut down the link because there is nothing out there. + */ + +static void LcpLinkFailure(fsm *f) { + ppp_pcb *pcb = f->pcb; + if (f->state == PPP_FSM_OPENED) { + ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending); + ppp_notice("Serial link appears to be disconnected."); + pcb->err_code = PPPERR_PEERDEAD; + lcp_close(pcb, "Peer not responding"); + } +} + +/* + * Timer expired for the LCP echo requests from this process. + */ + +static void LcpEchoCheck(fsm *f) { + ppp_pcb *pcb = f->pcb; + + LcpSendEchoRequest (f); + if (f->state != PPP_FSM_OPENED) + return; + + /* + * Start the timer for the next interval. + */ + if (pcb->lcp_echo_timer_running) + ppp_warn("assertion lcp_echo_timer_running==0 failed"); + TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval); + pcb->lcp_echo_timer_running = 1; +} + +/* + * LcpEchoTimeout - Timer expired on the LCP echo + */ + +static void LcpEchoTimeout(void *arg) { + fsm *f = (fsm*)arg; + ppp_pcb *pcb = f->pcb; + if (pcb->lcp_echo_timer_running != 0) { + pcb->lcp_echo_timer_running = 0; + LcpEchoCheck ((fsm *) arg); + } +} + +/* + * LcpEchoReply - LCP has received a reply to the echo + */ + +static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u32_t magic_val; + LWIP_UNUSED_ARG(id); + + /* Check the magic number - don't count replies from ourselves. */ + if (len < 4) { + ppp_dbglog("lcp: received short Echo-Reply, length %d", len); + return; + } + GETLONG(magic_val, inp); + if (go->neg_magicnumber + && magic_val == go->magicnumber) { + ppp_warn("appear to have received our own echo-reply!"); + return; + } + + /* Reset the number of outstanding echo frames */ + pcb->lcp_echos_pending = 0; +} + +/* + * LcpSendEchoRequest - Send an echo request frame to the peer + */ + +static void LcpSendEchoRequest(fsm *f) { + ppp_pcb *pcb = f->pcb; + lcp_options *go = &pcb->lcp_gotoptions; + u32_t lcp_magic; + u_char pkt[4], *pktp; + + /* + * Detect the failure of the peer at this point. + */ + if (pcb->settings.lcp_echo_fails != 0) { + if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) { + LcpLinkFailure(f); + pcb->lcp_echos_pending = 0; + } + } + +#if PPP_LCP_ADAPTIVE + /* + * If adaptive echos have been enabled, only send the echo request if + * no traffic was received since the last one. + */ + if (pcb->settings.lcp_echo_adaptive) { + static unsigned int last_pkts_in = 0; + +#if PPP_STATS_SUPPORT + update_link_stats(f->unit); + link_stats_valid = 0; +#endif /* PPP_STATS_SUPPORT */ + + if (link_stats.pkts_in != last_pkts_in) { + last_pkts_in = link_stats.pkts_in; + return; + } + } +#endif + + /* + * Make and send the echo request frame. + */ + if (f->state == PPP_FSM_OPENED) { + lcp_magic = go->magicnumber; + pktp = pkt; + PUTLONG(lcp_magic, pktp); + fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt); + ++pcb->lcp_echos_pending; + } +} + +/* + * lcp_echo_lowerup - Start the timer for the LCP frame + */ + +static void lcp_echo_lowerup(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + /* Clear the parameters for generating echo frames */ + pcb->lcp_echos_pending = 0; + pcb->lcp_echo_number = 0; + pcb->lcp_echo_timer_running = 0; + + /* If a timeout interval is specified then start the timer */ + if (pcb->settings.lcp_echo_interval != 0) + LcpEchoCheck (f); +} + +/* + * lcp_echo_lowerdown - Stop the timer for the LCP frame + */ + +static void lcp_echo_lowerdown(ppp_pcb *pcb) { + fsm *f = &pcb->lcp_fsm; + + if (pcb->lcp_echo_timer_running != 0) { + UNTIMEOUT (LcpEchoTimeout, f); + pcb->lcp_echo_timer_running = 0; + } +} + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/magic.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/magic.c new file mode 100644 index 0000000000..d0d87c5e55 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/magic.c @@ -0,0 +1,294 @@ +/* + * magic.c - PPP Magic Number routines. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/***************************************************************************** +* randm.c - Random number generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 98-06-03 Guy Lancaster , Global Election Systems Inc. +* Extracted from avos. +*****************************************************************************/ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/magic.h" + +#if PPP_MD5_RANDM /* Using MD5 for better randomness if enabled */ + +#include "netif/ppp/pppcrypt.h" + +#define MD5_HASH_SIZE 16 +static char magic_randpool[MD5_HASH_SIZE]; /* Pool of randomness. */ +static long magic_randcount; /* Pseudo-random incrementer */ +static u32_t magic_randomseed; /* Seed used for random number generation. */ + +/* + * Churn the randomness pool on a random event. Call this early and often + * on random and semi-random system events to build randomness in time for + * usage. For randomly timed events, pass a null pointer and a zero length + * and this will use the system timer and other sources to add randomness. + * If new random data is available, pass a pointer to that and it will be + * included. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + */ +static void magic_churnrand(char *rand_data, u32_t rand_len) { + lwip_md5_context md5_ctx; + + /* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: %u@%P\n", rand_len, rand_data)); */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); + if (rand_data) { + lwip_md5_update(&md5_ctx, (u_char *)rand_data, rand_len); + } else { + struct { + /* INCLUDE fields for any system sources of randomness */ + u32_t jiffies; +#ifdef LWIP_RAND + u32_t rand; +#endif /* LWIP_RAND */ + } sys_data; + magic_randomseed += sys_jiffies(); + sys_data.jiffies = magic_randomseed; +#ifdef LWIP_RAND + sys_data.rand = LWIP_RAND(); +#endif /* LWIP_RAND */ + /* Load sys_data fields here. */ + lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data)); + } + lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool); + lwip_md5_free(&md5_ctx); +/* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: -> 0\n")); */ +} + +/* + * Initialize the random number generator. + */ +void magic_init(void) { + magic_churnrand(NULL, 0); +} + +/* + * Randomize our random seed value. + */ +void magic_randomize(void) { + magic_churnrand(NULL, 0); +} + +/* + * magic_random_bytes - Fill a buffer with random bytes. + * + * Use the random pool to generate random data. This degrades to pseudo + * random when used faster than randomness is supplied using magic_churnrand(). + * Note: It's important that there be sufficient randomness in magic_randpool + * before this is called for otherwise the range of the result may be + * narrow enough to make a search feasible. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + * + * XXX Why does he not just call magic_churnrand() for each block? Probably + * so that you don't ever publish the seed which could possibly help + * predict future values. + * XXX Why don't we preserve md5 between blocks and just update it with + * magic_randcount each time? Probably there is a weakness but I wish that + * it was documented. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len) { + lwip_md5_context md5_ctx; + u_char tmp[MD5_HASH_SIZE]; + u32_t n; + + while (buf_len > 0) { + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + lwip_md5_update(&md5_ctx, (u_char *)magic_randpool, sizeof(magic_randpool)); + lwip_md5_update(&md5_ctx, (u_char *)&magic_randcount, sizeof(magic_randcount)); + lwip_md5_finish(&md5_ctx, tmp); + lwip_md5_free(&md5_ctx); + magic_randcount++; + n = LWIP_MIN(buf_len, MD5_HASH_SIZE); + MEMCPY(buf, tmp, n); + buf += n; + buf_len -= n; + } +} + +/* + * Return a new random number. + */ +u32_t magic(void) { + u32_t new_rand; + + magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand)); + + return new_rand; +} + +#else /* PPP_MD5_RANDM */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +#ifndef LWIP_RAND +static int magic_randomized; /* Set when truely randomized. */ +#endif /* LWIP_RAND */ +static u32_t magic_randomseed; /* Seed used for random number generation. */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ + +/* + * Initialize the random number generator. + * + * Here we attempt to compute a random number seed but even if + * it isn't random, we'll randomize it later. + * + * The current method uses the fields from the real time clock, + * the idle process counter, the millisecond counter, and the + * hardware timer tick counter. When this is invoked + * in startup(), then the idle counter and timer values may + * repeat after each boot and the real time clock may not be + * operational. Thus we call it again on the first random + * event. + */ +void magic_init(void) { + magic_randomseed += sys_jiffies(); +#ifndef LWIP_RAND + /* Initialize the Borland random number generator. */ + srand((unsigned)magic_randomseed); +#endif /* LWIP_RAND */ +} + +/* + * magic_init - Initialize the magic number generator. + * + * Randomize our random seed value. Here we use the fact that + * this function is called at *truely random* times by the polling + * and network functions. Here we only get 16 bits of new random + * value but we use the previous value to randomize the other 16 + * bits. + */ +void magic_randomize(void) { +#ifndef LWIP_RAND + if (!magic_randomized) { + magic_randomized = !0; + magic_init(); + /* The initialization function also updates the seed. */ + } else { +#endif /* LWIP_RAND */ + magic_randomseed += sys_jiffies(); +#ifndef LWIP_RAND + } +#endif /* LWIP_RAND */ +} + +/* + * Return a new random number. + * + * Here we use the Borland rand() function to supply a pseudo random + * number which we make truely random by combining it with our own + * seed which is randomized by truely random events. + * Thus the numbers will be truely random unless there have been no + * operator or network events in which case it will be pseudo random + * seeded by the real time clock. + */ +u32_t magic(void) { +#ifdef LWIP_RAND + return LWIP_RAND() + magic_randomseed; +#else /* LWIP_RAND */ + return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed; +#endif /* LWIP_RAND */ +} + +/* + * magic_random_bytes - Fill a buffer with random bytes. + */ +void magic_random_bytes(unsigned char *buf, u32_t buf_len) { + u32_t new_rand, n; + + while (buf_len > 0) { + new_rand = magic(); + n = LWIP_MIN(buf_len, sizeof(new_rand)); + MEMCPY(buf, &new_rand, n); + buf += n; + buf_len -= n; + } +} +#endif /* PPP_MD5_RANDM */ + +/* + * Return a new random number between 0 and (2^pow)-1 included. + */ +u32_t magic_pow(u8_t pow) { + return magic() & ~(~0UL<. + * Copyright (c) 2002,2003,2004 Google, Inc. + * All rights reserved. + * + * License: + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. + * + * Changelog: + * 08/12/05 - Matt Domsch + * Only need extra skb padding on transmit, not receive. + * 06/18/04 - Matt Domsch , Oleg Makarenko + * Use Linux kernel 2.6 arc4 and sha1 routines rather than + * providing our own. + * 2/15/04 - TS: added #include and testing for Kernel + * version before using + * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are + * deprecated in 2.6 + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MPPE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "lwip/err.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/ccp.h" +#include "netif/ppp/mppe.h" +#include "netif/ppp/pppdebug.h" +#include "netif/ppp/pppcrypt.h" + +#define SHA1_SIGNATURE_SIZE 20 + +/* ppp_mppe_state.bits definitions */ +#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ +#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ +#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ +#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ + +#define MPPE_BIT_FLUSHED MPPE_BIT_A +#define MPPE_BIT_ENCRYPTED MPPE_BIT_D + +#define MPPE_BITS(p) ((p)[0] & 0xf0) +#define MPPE_CCOUNT(p) ((((p)[0] & 0x0f) << 8) + (p)[1]) +#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ + +#define MPPE_OVHD 2 /* MPPE overhead/packet */ +#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ + +/* + * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. + * Well, not what's written there, but rather what they meant. + */ +static void mppe_rekey(ppp_mppe_state * state, int initial_key) +{ + lwip_sha1_context sha1_ctx; + u8_t sha1_digest[SHA1_SIGNATURE_SIZE]; + + /* + * Key Derivation, from RFC 3078, RFC 3079. + * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. + */ + lwip_sha1_init(&sha1_ctx); + lwip_sha1_starts(&sha1_ctx); + lwip_sha1_update(&sha1_ctx, state->master_key, state->keylen); + lwip_sha1_update(&sha1_ctx, mppe_sha1_pad1, SHA1_PAD_SIZE); + lwip_sha1_update(&sha1_ctx, state->session_key, state->keylen); + lwip_sha1_update(&sha1_ctx, mppe_sha1_pad2, SHA1_PAD_SIZE); + lwip_sha1_finish(&sha1_ctx, sha1_digest); + lwip_sha1_free(&sha1_ctx); + MEMCPY(state->session_key, sha1_digest, state->keylen); + + if (!initial_key) { + lwip_arc4_init(&state->arc4); + lwip_arc4_setup(&state->arc4, sha1_digest, state->keylen); + lwip_arc4_crypt(&state->arc4, state->session_key, state->keylen); + lwip_arc4_free(&state->arc4); + } + if (state->keylen == 8) { + /* See RFC 3078 */ + state->session_key[0] = 0xd1; + state->session_key[1] = 0x26; + state->session_key[2] = 0x9e; + } + lwip_arc4_init(&state->arc4); + lwip_arc4_setup(&state->arc4, state->session_key, state->keylen); +} + +/* + * Set key, used by MSCHAP before mppe_init() is actually called by CCP so we + * don't have to keep multiple copies of keys. + */ +void mppe_set_key(ppp_pcb *pcb, ppp_mppe_state *state, u8_t *key) { + LWIP_UNUSED_ARG(pcb); + MEMCPY(state->master_key, key, MPPE_MAX_KEY_LEN); +} + +/* + * Initialize (de)compressor state. + */ +void +mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options) +{ +#if PPP_DEBUG + const u8_t *debugstr = (const u8_t*)"mppe_comp_init"; + if (&pcb->mppe_decomp == state) { + debugstr = (const u8_t*)"mppe_decomp_init"; + } +#endif /* PPP_DEBUG */ + + /* Save keys. */ + MEMCPY(state->session_key, state->master_key, sizeof(state->master_key)); + + if (options & MPPE_OPT_128) + state->keylen = 16; + else if (options & MPPE_OPT_40) + state->keylen = 8; + else { + PPPDEBUG(LOG_DEBUG, ("%s[%d]: unknown key length\n", debugstr, + pcb->netif->num)); + lcp_close(pcb, "MPPE required but peer negotiation failed"); + return; + } + if (options & MPPE_OPT_STATEFUL) + state->stateful = 1; + + /* Generate the initial session key. */ + mppe_rekey(state, 1); + +#if PPP_DEBUG + { + int i; + char mkey[sizeof(state->master_key) * 2 + 1]; + char skey[sizeof(state->session_key) * 2 + 1]; + + PPPDEBUG(LOG_DEBUG, ("%s[%d]: initialized with %d-bit %s mode\n", + debugstr, pcb->netif->num, (state->keylen == 16) ? 128 : 40, + (state->stateful) ? "stateful" : "stateless")); + + for (i = 0; i < (int)sizeof(state->master_key); i++) + sprintf(mkey + i * 2, "%02x", state->master_key[i]); + for (i = 0; i < (int)sizeof(state->session_key); i++) + sprintf(skey + i * 2, "%02x", state->session_key[i]); + PPPDEBUG(LOG_DEBUG, + ("%s[%d]: keys: master: %s initial session: %s\n", + debugstr, pcb->netif->num, mkey, skey)); + } +#endif /* PPP_DEBUG */ + + /* + * Initialize the coherency count. The initial value is not specified + * in RFC 3078, but we can make a reasonable assumption that it will + * start at 0. Setting it to the max here makes the comp/decomp code + * do the right thing (determined through experiment). + */ + state->ccount = MPPE_CCOUNT_SPACE - 1; + + /* + * Note that even though we have initialized the key table, we don't + * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. + */ + state->bits = MPPE_BIT_ENCRYPTED; +} + +/* + * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), + * tell the compressor to rekey. Note that we MUST NOT rekey for + * every CCP Reset-Request; we only rekey on the next xmit packet. + * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. + * So, rekeying for every CCP Reset-Request is broken as the peer will not + * know how many times we've rekeyed. (If we rekey and THEN get another + * CCP Reset-Request, we must rekey again.) + */ +void mppe_comp_reset(ppp_pcb *pcb, ppp_mppe_state *state) +{ + LWIP_UNUSED_ARG(pcb); + state->bits |= MPPE_BIT_FLUSHED; +} + +/* + * Compress (encrypt) a packet. + * It's strange to call this a compressor, since the output is always + * MPPE_OVHD + 2 bytes larger than the input. + */ +err_t +mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol) +{ + struct pbuf *n, *np; + u8_t *pl; + err_t err; + + LWIP_UNUSED_ARG(pcb); + + /* TCP stack requires that we don't change the packet payload, therefore we copy + * the whole packet before encryption. + */ + np = pbuf_alloc(PBUF_RAW, MPPE_OVHD + sizeof(protocol) + (*pb)->tot_len, PBUF_POOL); + if (!np) { + return ERR_MEM; + } + + /* Hide MPPE header + protocol */ + pbuf_header(np, -(s16_t)(MPPE_OVHD + sizeof(protocol))); + + if ((err = pbuf_copy(np, *pb)) != ERR_OK) { + pbuf_free(np); + return err; + } + + /* Reveal MPPE header + protocol */ + pbuf_header(np, (s16_t)(MPPE_OVHD + sizeof(protocol))); + + *pb = np; + pl = (u8_t*)np->payload; + + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: ccount %d\n", pcb->netif->num, state->ccount)); + /* FIXME: use PUT* macros */ + pl[0] = state->ccount>>8; + pl[1] = state->ccount; + + if (!state->stateful || /* stateless mode */ + ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ + (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ + /* We must rekey */ + if (state->stateful) { + PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: rekeying\n", pcb->netif->num)); + } + mppe_rekey(state, 0); + state->bits |= MPPE_BIT_FLUSHED; + } + pl[0] |= state->bits; + state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ + pl += MPPE_OVHD; + + /* Add protocol */ + /* FIXME: add PFC support */ + pl[0] = protocol >> 8; + pl[1] = protocol; + + /* Hide MPPE header */ + pbuf_header(np, -(s16_t)MPPE_OVHD); + + /* Encrypt packet */ + for (n = np; n != NULL; n = n->next) { + lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); + if (n->tot_len == n->len) { + break; + } + } + + /* Reveal MPPE header */ + pbuf_header(np, (s16_t)MPPE_OVHD); + + return ERR_OK; +} + +/* + * We received a CCP Reset-Ack. Just ignore it. + */ +void mppe_decomp_reset(ppp_pcb *pcb, ppp_mppe_state *state) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(state); + return; +} + +/* + * Decompress (decrypt) an MPPE packet. + */ +err_t +mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb) +{ + struct pbuf *n0 = *pb, *n; + u8_t *pl; + u16_t ccount; + u8_t flushed; + + /* MPPE Header */ + if (n0->len < MPPE_OVHD) { + PPPDEBUG(LOG_DEBUG, + ("mppe_decompress[%d]: short pkt (%d)\n", + pcb->netif->num, n0->len)); + state->sanity_errors += 100; + goto sanity_error; + } + + pl = (u8_t*)n0->payload; + flushed = MPPE_BITS(pl) & MPPE_BIT_FLUSHED; + ccount = MPPE_CCOUNT(pl); + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ccount %d\n", + pcb->netif->num, ccount)); + + /* sanity checks -- terminate with extreme prejudice */ + if (!(MPPE_BITS(pl) & MPPE_BIT_ENCRYPTED)) { + PPPDEBUG(LOG_DEBUG, + ("mppe_decompress[%d]: ENCRYPTED bit not set!\n", + pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + if (!state->stateful && !flushed) { + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set in " + "stateless mode!\n", pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { + PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set on " + "flag packet!\n", pcb->netif->num)); + state->sanity_errors += 100; + goto sanity_error; + } + + /* + * Check the coherency count. + */ + + if (!state->stateful) { + /* Discard late packet */ + if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE > MPPE_CCOUNT_SPACE / 2) { + state->sanity_errors++; + goto sanity_error; + } + + /* RFC 3078, sec 8.1. Rekey for every packet. */ + while (state->ccount != ccount) { + mppe_rekey(state, 0); + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + } + } else { + /* RFC 3078, sec 8.2. */ + if (!state->discard) { + /* normal state */ + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (ccount != state->ccount) { + /* + * (ccount > state->ccount) + * Packet loss detected, enter the discard state. + * Signal the peer to rekey (by sending a CCP Reset-Request). + */ + state->discard = 1; + ccp_resetrequest(pcb); + return ERR_BUF; + } + } else { + /* discard state */ + if (!flushed) { + /* ccp.c will be silent (no additional CCP Reset-Requests). */ + return ERR_BUF; + } else { + /* Rekey for every missed "flag" packet. */ + while ((ccount & ~0xff) != + (state->ccount & ~0xff)) { + mppe_rekey(state, 0); + state->ccount = + (state->ccount + + 256) % MPPE_CCOUNT_SPACE; + } + + /* reset */ + state->discard = 0; + state->ccount = ccount; + /* + * Another problem with RFC 3078 here. It implies that the + * peer need not send a Reset-Ack packet. But RFC 1962 + * requires it. Hopefully, M$ does send a Reset-Ack; even + * though it isn't required for MPPE synchronization, it is + * required to reset CCP state. + */ + } + } + if (flushed) + mppe_rekey(state, 0); + } + + /* Hide MPPE header */ + pbuf_header(n0, -(s16_t)(MPPE_OVHD)); + + /* Decrypt the packet. */ + for (n = n0; n != NULL; n = n->next) { + lwip_arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); + if (n->tot_len == n->len) { + break; + } + } + + /* good packet credit */ + state->sanity_errors >>= 1; + + return ERR_OK; + +sanity_error: + if (state->sanity_errors >= SANITY_MAX) { + /* + * Take LCP down if the peer is sending too many bogons. + * We don't want to do this for a single or just a few + * instances since it could just be due to packet corruption. + */ + lcp_close(pcb, "Too many MPPE errors"); + } + return ERR_BUF; +} + +#endif /* PPP_SUPPORT && MPPE_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/multilink.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/multilink.c new file mode 100644 index 0000000000..62014e8c87 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/multilink.c @@ -0,0 +1,609 @@ +/* + * multilink.c - support routines for multilink. + * + * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */ + +/* Multilink support + * + * Multilink uses Samba TDB (Trivial Database Library), which + * we cannot port, because it needs a filesystem. + * + * We have to choose between doing a memory-shared TDB-clone, + * or dropping multilink support at all. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/tdb.h" + +bool endpoint_specified; /* user gave explicit endpoint discriminator */ +char *bundle_id; /* identifier for our bundle */ +char *blinks_id; /* key for the list of links */ +bool doing_multilink; /* multilink was enabled and agreed to */ +bool multilink_master; /* we own the multilink bundle */ + +extern TDB_CONTEXT *pppdb; +extern char db_key[]; + +static void make_bundle_links (int append); +static void remove_bundle_link (void); +static void iterate_bundle_links (void (*func) (char *)); + +static int get_default_epdisc (struct epdisc *); +static int parse_num (char *str, const char *key, int *valp); +static int owns_unit (TDB_DATA pid, int unit); + +#define set_ip_epdisc(ep, addr) do { \ + ep->length = 4; \ + ep->value[0] = addr >> 24; \ + ep->value[1] = addr >> 16; \ + ep->value[2] = addr >> 8; \ + ep->value[3] = addr; \ +} while (0) + +#define LOCAL_IP_ADDR(addr) \ + (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \ + || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \ + || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */ + +#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH) + +void +mp_check_options() +{ + lcp_options *wo = &lcp_wantoptions[0]; + lcp_options *ao = &lcp_allowoptions[0]; + + doing_multilink = 0; + if (!multilink) + return; + /* if we're doing multilink, we have to negotiate MRRU */ + if (!wo->neg_mrru) { + /* mrru not specified, default to mru */ + wo->mrru = wo->mru; + wo->neg_mrru = 1; + } + ao->mrru = ao->mru; + ao->neg_mrru = 1; + + if (!wo->neg_endpoint && !noendpoint) { + /* get a default endpoint value */ + wo->neg_endpoint = get_default_epdisc(&wo->endpoint); + } +} + +/* + * Make a new bundle or join us to an existing bundle + * if we are doing multilink. + */ +int +mp_join_bundle() +{ + lcp_options *go = &lcp_gotoptions[0]; + lcp_options *ho = &lcp_hisoptions[0]; + lcp_options *ao = &lcp_allowoptions[0]; + int unit, pppd_pid; + int l, mtu; + char *p; + TDB_DATA key, pid, rec; + + if (doing_multilink) { + /* have previously joined a bundle */ + if (!go->neg_mrru || !ho->neg_mrru) { + notice("oops, didn't get multilink on renegotiation"); + lcp_close(pcb, "multilink required"); + return 0; + } + /* XXX should check the peer_authname and ho->endpoint + are the same as previously */ + return 0; + } + + if (!go->neg_mrru || !ho->neg_mrru) { + /* not doing multilink */ + if (go->neg_mrru) + notice("oops, multilink negotiated only for receive"); + mtu = ho->neg_mru? ho->mru: PPP_MRU; + if (mtu > ao->mru) + mtu = ao->mru; + if (demand) { + /* already have a bundle */ + cfg_bundle(0, 0, 0, 0); + netif_set_mtu(pcb, mtu); + return 0; + } + make_new_bundle(0, 0, 0, 0); + set_ifunit(1); + netif_set_mtu(pcb, mtu); + return 0; + } + + doing_multilink = 1; + + /* + * Find the appropriate bundle or join a new one. + * First we make up a name for the bundle. + * The length estimate is worst-case assuming every + * character has to be quoted. + */ + l = 4 * strlen(peer_authname) + 10; + if (ho->neg_endpoint) + l += 3 * ho->endpoint.length + 8; + if (bundle_name) + l += 3 * strlen(bundle_name) + 2; + bundle_id = malloc(l); + if (bundle_id == 0) + novm("bundle identifier"); + + p = bundle_id; + p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); + if (ho->neg_endpoint || bundle_name) + *p++ = '/'; + if (ho->neg_endpoint) + p += slprintf(p, bundle_id+l-p, "%s", + epdisc_to_str(&ho->endpoint)); + if (bundle_name) + p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); + + /* Make the key for the list of links belonging to the bundle */ + l = p - bundle_id; + blinks_id = malloc(l + 7); + if (blinks_id == NULL) + novm("bundle links key"); + slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); + + /* + * For demand mode, we only need to configure the bundle + * and attach the link. + */ + mtu = LWIP_MIN(ho->mrru, ao->mru); + if (demand) { + cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); + netif_set_mtu(pcb, mtu); + script_setenv("BUNDLE", bundle_id + 7, 1); + return 0; + } + + /* + * Check if the bundle ID is already in the database. + */ + unit = -1; + lock_db(); + key.dptr = bundle_id; + key.dsize = p - bundle_id; + pid = tdb_fetch(pppdb, key); + if (pid.dptr != NULL) { + /* bundle ID exists, see if the pppd record exists */ + rec = tdb_fetch(pppdb, pid); + if (rec.dptr != NULL && rec.dsize > 0) { + /* make sure the string is null-terminated */ + rec.dptr[rec.dsize-1] = 0; + /* parse the interface number */ + parse_num(rec.dptr, "IFNAME=ppp", &unit); + /* check the pid value */ + if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) + || !process_exists(pppd_pid) + || !owns_unit(pid, unit)) + unit = -1; + free(rec.dptr); + } + free(pid.dptr); + } + + if (unit >= 0) { + /* attach to existing unit */ + if (bundle_attach(unit)) { + set_ifunit(0); + script_setenv("BUNDLE", bundle_id + 7, 0); + make_bundle_links(1); + unlock_db(); + info("Link attached to %s", ifname); + return 1; + } + /* attach failed because bundle doesn't exist */ + } + + /* we have to make a new bundle */ + make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); + set_ifunit(1); + netif_set_mtu(pcb, mtu); + script_setenv("BUNDLE", bundle_id + 7, 1); + make_bundle_links(pcb); + unlock_db(); + info("New bundle %s created", ifname); + multilink_master = 1; + return 0; +} + +void mp_exit_bundle() +{ + lock_db(); + remove_bundle_link(); + unlock_db(); +} + +static void sendhup(char *str) +{ + int pid; + + if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) { + if (debug) + dbglog("sending SIGHUP to process %d", pid); + kill(pid, SIGHUP); + } +} + +void mp_bundle_terminated() +{ + TDB_DATA key; + + bundle_terminating = 1; + upper_layers_down(pcb); + notice("Connection terminated."); +#if PPP_STATS_SUPPORT + print_link_stats(); +#endif /* PPP_STATS_SUPPORT */ + if (!demand) { + remove_pidfiles(); + script_unsetenv("IFNAME"); + } + + lock_db(); + destroy_bundle(); + iterate_bundle_links(sendhup); + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + tdb_delete(pppdb, key); + unlock_db(); + + new_phase(PPP_PHASE_DEAD); + + doing_multilink = 0; + multilink_master = 0; +} + +static void make_bundle_links(int append) +{ + TDB_DATA key, rec; + char *p; + char entry[32]; + int l; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + slprintf(entry, sizeof(entry), "%s;", db_key); + p = entry; + if (append) { + rec = tdb_fetch(pppdb, key); + if (rec.dptr != NULL && rec.dsize > 0) { + rec.dptr[rec.dsize-1] = 0; + if (strstr(rec.dptr, db_key) != NULL) { + /* already in there? strange */ + warn("link entry already exists in tdb"); + return; + } + l = rec.dsize + strlen(entry); + p = malloc(l); + if (p == NULL) + novm("bundle link list"); + slprintf(p, l, "%s%s", rec.dptr, entry); + } else { + warn("bundle link list not found"); + } + if (rec.dptr != NULL) + free(rec.dptr); + } + rec.dptr = p; + rec.dsize = strlen(p) + 1; + if (tdb_store(pppdb, key, rec, TDB_REPLACE)) + error("couldn't %s bundle link list", + append? "update": "create"); + if (p != entry) + free(p); +} + +static void remove_bundle_link() +{ + TDB_DATA key, rec; + char entry[32]; + char *p, *q; + int l; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + slprintf(entry, sizeof(entry), "%s;", db_key); + + rec = tdb_fetch(pppdb, key); + if (rec.dptr == NULL || rec.dsize <= 0) { + if (rec.dptr != NULL) + free(rec.dptr); + return; + } + rec.dptr[rec.dsize-1] = 0; + p = strstr(rec.dptr, entry); + if (p != NULL) { + q = p + strlen(entry); + l = strlen(q) + 1; + memmove(p, q, l); + rec.dsize = p - rec.dptr + l; + if (tdb_store(pppdb, key, rec, TDB_REPLACE)) + error("couldn't update bundle link list (removal)"); + } + free(rec.dptr); +} + +static void iterate_bundle_links(void (*func)(char *)) +{ + TDB_DATA key, rec, pp; + char *p, *q; + + key.dptr = blinks_id; + key.dsize = strlen(blinks_id); + rec = tdb_fetch(pppdb, key); + if (rec.dptr == NULL || rec.dsize <= 0) { + error("bundle link list not found (iterating list)"); + if (rec.dptr != NULL) + free(rec.dptr); + return; + } + p = rec.dptr; + p[rec.dsize-1] = 0; + while ((q = strchr(p, ';')) != NULL) { + *q = 0; + key.dptr = p; + key.dsize = q - p; + pp = tdb_fetch(pppdb, key); + if (pp.dptr != NULL && pp.dsize > 0) { + pp.dptr[pp.dsize-1] = 0; + func(pp.dptr); + } + if (pp.dptr != NULL) + free(pp.dptr); + p = q + 1; + } + free(rec.dptr); +} + +static int +parse_num(str, key, valp) + char *str; + const char *key; + int *valp; +{ + char *p, *endp; + int i; + + p = strstr(str, key); + if (p != 0) { + p += strlen(key); + i = strtol(p, &endp, 10); + if (endp != p && (*endp == 0 || *endp == ';')) { + *valp = i; + return 1; + } + } + return 0; +} + +/* + * Check whether the pppd identified by `key' still owns ppp unit `unit'. + */ +static int +owns_unit(key, unit) + TDB_DATA key; + int unit; +{ + char ifkey[32]; + TDB_DATA kd, vd; + int ret = 0; + + slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); + kd.dptr = ifkey; + kd.dsize = strlen(ifkey); + vd = tdb_fetch(pppdb, kd); + if (vd.dptr != NULL) { + ret = vd.dsize == key.dsize + && memcmp(vd.dptr, key.dptr, vd.dsize) == 0; + free(vd.dptr); + } + return ret; +} + +static int +get_default_epdisc(ep) + struct epdisc *ep; +{ + char *p; + struct hostent *hp; + u32_t addr; + + /* First try for an ethernet MAC address */ + p = get_first_ethernet(); + if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) { + ep->class = EPD_MAC; + ep->length = 6; + return 1; + } + + /* see if our hostname corresponds to a reasonable IP address */ + hp = gethostbyname(hostname); + if (hp != NULL) { + addr = *(u32_t *)hp->h_addr; + if (!bad_ip_adrs(addr)) { + addr = lwip_ntohl(addr); + if (!LOCAL_IP_ADDR(addr)) { + ep->class = EPD_IP; + set_ip_epdisc(ep, addr); + return 1; + } + } + } + + return 0; +} + +/* + * epdisc_to_str - make a printable string from an endpoint discriminator. + */ + +static char *endp_class_names[] = { + "null", "local", "IP", "MAC", "magic", "phone" +}; + +char * +epdisc_to_str(ep) + struct epdisc *ep; +{ + static char str[MAX_ENDP_LEN*3+8]; + u_char *p = ep->value; + int i, mask = 0; + char *q, c, c2; + + if (ep->class == EPD_NULL && ep->length == 0) + return "null"; + if (ep->class == EPD_IP && ep->length == 4) { + u32_t addr; + + GETLONG(addr, p); + slprintf(str, sizeof(str), "IP:%I", lwip_htonl(addr)); + return str; + } + + c = ':'; + c2 = '.'; + if (ep->class == EPD_MAC && ep->length == 6) + c2 = ':'; + else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) + mask = 3; + q = str; + if (ep->class <= EPD_PHONENUM) + q += slprintf(q, sizeof(str)-1, "%s", + endp_class_names[ep->class]); + else + q += slprintf(q, sizeof(str)-1, "%d", ep->class); + c = ':'; + for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { + if ((i & mask) == 0) { + *q++ = c; + c = c2; + } + q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); + } + return str; +} + +static int hexc_val(int c) +{ + if (c >= 'a') + return c - 'a' + 10; + if (c >= 'A') + return c - 'A' + 10; + return c - '0'; +} + +int +str_to_epdisc(ep, str) + struct epdisc *ep; + char *str; +{ + int i, l; + char *p, *endp; + + for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) { + int sl = strlen(endp_class_names[i]); + if (strncasecmp(str, endp_class_names[i], sl) == 0) { + str += sl; + break; + } + } + if (i > EPD_PHONENUM) { + /* not a class name, try a decimal class number */ + i = strtol(str, &endp, 10); + if (endp == str) + return 0; /* can't parse class number */ + str = endp; + } + ep->class = i; + if (*str == 0) { + ep->length = 0; + return 1; + } + if (*str != ':' && *str != '.') + return 0; + ++str; + + if (i == EPD_IP) { + u32_t addr; + i = parse_dotted_ip(str, &addr); + if (i == 0 || str[i] != 0) + return 0; + set_ip_epdisc(ep, addr); + return 1; + } + if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) { + ep->length = 6; + return 1; + } + + p = str; + for (l = 0; l < MAX_ENDP_LEN; ++l) { + if (*str == 0) + break; + if (p <= str) + for (p = str; isxdigit(*p); ++p) + ; + i = p - str; + if (i == 0) + return 0; + ep->value[l] = hexc_val(*str++); + if ((i & 1) == 0) + ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); + if (*str == ':' || *str == '.') + ++str; + } + if (*str != 0 || (ep->class == EPD_MAC && l != 6)) + return 0; + ep->length = l; + return 1; +} + +#endif /* PPP_SUPPORT && HAVE_MULTILINK */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/README b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/README new file mode 100644 index 0000000000..3fdf159ec1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/README @@ -0,0 +1,22 @@ +About PolarSSL files into lwIP PPP support +------------------------------------------ + +This folder contains some files fetched from the latest BSD release of +the PolarSSL project (PolarSSL 0.10.1-bsd) for ciphers and encryption +methods we need for lwIP PPP support. + +The PolarSSL files were cleaned to contain only the necessary struct +fields and functions needed for lwIP. + +The PolarSSL API was not changed at all, so if you are already using +PolarSSL you can choose to skip the compilation of the included PolarSSL +library into lwIP. + +If you are not using the embedded copy you must include external +libraries into your arch/cc.h port file. + +Beware of the stack requirements which can be a lot larger if you are not +using our cleaned PolarSSL library. + + +PolarSSL project website: http://polarssl.org/ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/arc4.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/arc4.c new file mode 100644 index 0000000000..6e17ec421b --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/arc4.c @@ -0,0 +1,101 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_ARC4 + +#include "netif/ppp/polarssl/arc4.h" +/* + * ARC4 key schedule + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ) +{ + int i, j, k, a; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ) +{ + int i, x, y, a, b; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < buflen; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + buf[i] = (unsigned char) + ( buf[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/des.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/des.c new file mode 100644 index 0000000000..9a89d007bd --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/des.c @@ -0,0 +1,422 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES + +#include "netif/ppp/polarssl/des.h" + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const unsigned long SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const unsigned long SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const unsigned long SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const unsigned long SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const unsigned long SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const unsigned long SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const unsigned long SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const unsigned long SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const unsigned long LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const unsigned long RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } + +static void des_setkey( unsigned long SK[32], unsigned char key[8] ) +{ + int i; + unsigned long X, Y, T; + + GET_ULONG_BE( X, key, 0 ); + GET_ULONG_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ) +{ + des_setkey( ctx->sk, key ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } +} + +/* + * DES-ECB block encryption/decryption + */ +void des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + unsigned long X, Y, T, *SK; + + SK = ctx->sk; + + GET_ULONG_BE( X, input, 0 ); + GET_ULONG_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_ULONG_BE( Y, output, 0 ); + PUT_ULONG_BE( X, output, 4 ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_DES */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md4.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md4.c new file mode 100644 index 0000000000..b1701a07b9 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md4.c @@ -0,0 +1,281 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 + +#include "netif/ppp/polarssl/md4.h" + +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD4 context setup + */ +void md4_starts( md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md4_process( md4_context *ctx, const unsigned char data[64] ) +{ + unsigned long X[16], A, B, C, D; + + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD4 process buffer + */ +void md4_update( md4_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md4_update( ctx, md4_padding, padn ); + md4_update( ctx, msglen, 8 ); + + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); +} + +/* + * output = MD4( input buffer ) + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ) +{ + md4_context ctx; + + md4_starts( &ctx ); + md4_update( &ctx, input, ilen ); + md4_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD4 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md5.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md5.c new file mode 100644 index 0000000000..1ec4d81a69 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/md5.c @@ -0,0 +1,300 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 + +#include "netif/ppp/polarssl/md5.h" + +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD5 context setup + */ +void md5_starts( md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md5_process( md5_context *ctx, const unsigned char data[64] ) +{ + unsigned long X[16], A, B, C, D; + + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +void md5_update( md5_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char md5_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md5_update( ctx, md5_padding, padn ); + md5_update( ctx, msglen, 8 ); + + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); +} + +/* + * output = MD5( input buffer ) + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ) +{ + md5_context ctx; + + md5_starts( &ctx ); + md5_update( &ctx, input, ilen ); + md5_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_MD5 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/sha1.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/sha1.c new file mode 100644 index 0000000000..c2192eac54 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/polarssl/sha1.c @@ -0,0 +1,335 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine + * + * Copyright (C) 2009 Paul Bakker + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of PolarSSL or XySSL nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 + +#include "netif/ppp/polarssl/sha1.h" + +#include + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-1 context setup + */ +void sha1_starts( sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +static void sha1_process( sha1_context *ctx, const unsigned char data[64] ) +{ + unsigned long temp, W[16], A, B, C, D, E; + + GET_ULONG_BE( W[ 0], data, 0 ); + GET_ULONG_BE( W[ 1], data, 4 ); + GET_ULONG_BE( W[ 2], data, 8 ); + GET_ULONG_BE( W[ 3], data, 12 ); + GET_ULONG_BE( W[ 4], data, 16 ); + GET_ULONG_BE( W[ 5], data, 20 ); + GET_ULONG_BE( W[ 6], data, 24 ); + GET_ULONG_BE( W[ 7], data, 28 ); + GET_ULONG_BE( W[ 8], data, 32 ); + GET_ULONG_BE( W[ 9], data, 36 ); + GET_ULONG_BE( W[10], data, 40 ); + GET_ULONG_BE( W[11], data, 44 ); + GET_ULONG_BE( W[12], data, 48 ); + GET_ULONG_BE( W[13], data, 52 ); + GET_ULONG_BE( W[14], data, 56 ); + GET_ULONG_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ + W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, fill ); + sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + MEMCPY( (void *) (ctx->buffer + left), + input, ilen ); + } +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_BE( high, msglen, 0 ); + PUT_ULONG_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha1_update( ctx, sha1_padding, padn ); + sha1_update( ctx, msglen, 8 ); + + PUT_ULONG_BE( ctx->state[0], output, 0 ); + PUT_ULONG_BE( ctx->state[1], output, 4 ); + PUT_ULONG_BE( ctx->state[2], output, 8 ); + PUT_ULONG_BE( ctx->state[3], output, 12 ); + PUT_ULONG_BE( ctx->state[4], output, 16 ); +} + +/* + * output = SHA-1( input buffer ) + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_starts( &ctx ); + sha1_update( &ctx, input, ilen ); + sha1_finish( &ctx, output ); +} + +#endif /* PPP_SUPPORT && LWIP_INCLUDED_POLARSSL_SHA1 */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ppp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ppp.c new file mode 100644 index 0000000000..8b77765e5a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/ppp.c @@ -0,0 +1,1647 @@ +/***************************************************************************** +* ppp.c - Network Point to Point Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original. +*****************************************************************************/ + +/* + * ppp_defs.h - PPP definitions. + * + * if_pppvar.h - private structures and declarations for PPP. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * @defgroup ppp PPP netif + * @ingroup addons + * @verbinclude "ppp.txt" + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/tcpip.h" +#include "lwip/api.h" +#include "lwip/snmp.h" +#include "lwip/ip4.h" /* for ip4_input() */ +#if PPP_IPV6_SUPPORT +#include "lwip/ip6.h" /* for ip6_input() */ +#endif /* PPP_IPV6_SUPPORT */ +#include "lwip/dns.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppos.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/magic.h" + +#if PAP_SUPPORT +#include "netif/ppp/upap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "netif/ppp/chap-new.h" +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT +#include "netif/ppp/eap.h" +#endif /* EAP_SUPPORT */ +#if CCP_SUPPORT +#include "netif/ppp/ccp.h" +#endif /* CCP_SUPPORT */ +#if MPPE_SUPPORT +#include "netif/ppp/mppe.h" +#endif /* MPPE_SUPPORT */ +#if ECP_SUPPORT +#include "netif/ppp/ecp.h" +#endif /* EAP_SUPPORT */ +#if VJ_SUPPORT +#include "netif/ppp/vj.h" +#endif /* VJ_SUPPORT */ +#if PPP_IPV4_SUPPORT +#include "netif/ppp/ipcp.h" +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT +#include "netif/ppp/ipv6cp.h" +#endif /* PPP_IPV6_SUPPORT */ + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* Memory pools */ +#if PPPOS_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOS_PCB); +#endif +#if PPPOE_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOE_IF); +#endif +#if PPPOL2TP_SUPPORT +LWIP_MEMPOOL_PROTOTYPE(PPPOL2TP_PCB); +#endif +#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL_PROTOTYPE(PPPAPI_MSG); +#endif +LWIP_MEMPOOL_DECLARE(PPP_PCB, MEMP_NUM_PPP_PCB, sizeof(ppp_pcb), "PPP_PCB") + +/* FIXME: add stats per PPP session */ +#if PPP_STATS_SUPPORT +static struct timeval start_time; /* Time when link was started. */ +static struct pppd_stats old_link_stats; +struct pppd_stats link_stats; +unsigned link_connect_time; +int link_stats_valid; +#endif /* PPP_STATS_SUPPORT */ + +/* + * PPP Data Link Layer "protocol" table. + * One entry per supported protocol. + * The last entry must be NULL. + */ +const struct protent* const protocols[] = { + &lcp_protent, +#if PAP_SUPPORT + &pap_protent, +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + &chap_protent, +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT + &cbcp_protent, +#endif /* CBCP_SUPPORT */ +#if PPP_IPV4_SUPPORT + &ipcp_protent, +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + &ipv6cp_protent, +#endif /* PPP_IPV6_SUPPORT */ +#if CCP_SUPPORT + &ccp_protent, +#endif /* CCP_SUPPORT */ +#if ECP_SUPPORT + &ecp_protent, +#endif /* ECP_SUPPORT */ +#ifdef AT_CHANGE + &atcp_protent, +#endif /* AT_CHANGE */ +#if EAP_SUPPORT + &eap_protent, +#endif /* EAP_SUPPORT */ + NULL +}; + +/* Prototypes for procedures local to this file. */ +static void ppp_do_connect(void *arg); +static err_t ppp_netif_init_cb(struct netif *netif); +#if LWIP_IPV4 +static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr); +#endif /* LWIP_IPV4 */ +#if PPP_IPV6_SUPPORT +static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr); +#endif /* PPP_IPV6_SUPPORT */ +static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol); + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +#if PPP_AUTH_SUPPORT +void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd) { +#if PAP_SUPPORT + pcb->settings.refuse_pap = !(authtype & PPPAUTHTYPE_PAP); +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + pcb->settings.refuse_chap = !(authtype & PPPAUTHTYPE_CHAP); +#if MSCHAP_SUPPORT + pcb->settings.refuse_mschap = !(authtype & PPPAUTHTYPE_MSCHAP); + pcb->settings.refuse_mschap_v2 = !(authtype & PPPAUTHTYPE_MSCHAP_V2); +#endif /* MSCHAP_SUPPORT */ +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + pcb->settings.refuse_eap = !(authtype & PPPAUTHTYPE_EAP); +#endif /* EAP_SUPPORT */ + pcb->settings.user = user; + pcb->settings.passwd = passwd; +} +#endif /* PPP_AUTH_SUPPORT */ + +#if MPPE_SUPPORT +/* Set MPPE configuration */ +void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) { + if (flags == PPP_MPPE_DISABLE) { + pcb->settings.require_mppe = 0; + return; + } + + pcb->settings.require_mppe = 1; + pcb->settings.refuse_mppe_stateful = !(flags & PPP_MPPE_ALLOW_STATEFUL); + pcb->settings.refuse_mppe_40 = !!(flags & PPP_MPPE_REFUSE_40); + pcb->settings.refuse_mppe_128 = !!(flags & PPP_MPPE_REFUSE_128); +} +#endif /* MPPE_SUPPORT */ + +#if PPP_NOTIFY_PHASE +void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { + pcb->notify_phase_cb = notify_phase_cb; + notify_phase_cb(pcb, pcb->phase, pcb->ctx_cb); +} +#endif /* PPP_NOTIFY_PHASE */ + +/* + * Initiate a PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * Holdoff is the time to wait (in seconds) before initiating + * the connection. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_connect(ppp_pcb *pcb, u16_t holdoff) { + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_ALREADY; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_connect[%d]: holdoff=%d\n", pcb->netif->num, holdoff)); + + if (holdoff == 0) { + ppp_do_connect(pcb); + return ERR_OK; + } + + new_phase(pcb, PPP_PHASE_HOLDOFF); + sys_timeout((u32_t)(holdoff*1000), ppp_do_connect, pcb); + return ERR_OK; +} + +#if PPP_SERVER +/* + * Listen for an incoming PPP connection. + * + * This can only be called if PPP is in the dead phase. + * + * If this port connects to a modem, the modem connection must be + * established before calling this. + */ +err_t ppp_listen(ppp_pcb *pcb) { + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_ALREADY; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_listen[%d]\n", pcb->netif->num)); + + if (pcb->link_cb->listen) { + new_phase(pcb, PPP_PHASE_INITIALIZE); + pcb->link_cb->listen(pcb, pcb->link_ctx_cb); + return ERR_OK; + } + return ERR_IF; +} +#endif /* PPP_SERVER */ + +/* + * Initiate the end of a PPP connection. + * Any outstanding packets in the queues are dropped. + * + * Setting nocarrier to 1 close the PPP connection without initiating the + * shutdown procedure. Always using nocarrier = 0 is still recommended, + * this is going to take a little longer time if your link is down, but + * is a safer choice for the PPP state machine. + * + * Return 0 on success, an error code on failure. + */ +err_t +ppp_close(ppp_pcb *pcb, u8_t nocarrier) +{ + pcb->err_code = PPPERR_USER; + + /* holdoff phase, cancel the reconnection */ + if (pcb->phase == PPP_PHASE_HOLDOFF) { + sys_untimeout(ppp_do_connect, pcb); + new_phase(pcb, PPP_PHASE_DEAD); + } + + /* dead phase, nothing to do, call the status callback to be consistent */ + if (pcb->phase == PPP_PHASE_DEAD) { + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return ERR_OK; + } + + /* Already terminating, nothing to do */ + if (pcb->phase >= PPP_PHASE_TERMINATE) { + return ERR_INPROGRESS; + } + + /* LCP not open, close link protocol */ + if (pcb->phase < PPP_PHASE_ESTABLISH) { + new_phase(pcb, PPP_PHASE_DISCONNECT); + ppp_link_terminated(pcb); + return ERR_OK; + } + + /* + * Only accept carrier lost signal on the stable running phase in order + * to prevent changing the PPP phase FSM in transition phases. + * + * Always using nocarrier = 0 is still recommended, this is going to + * take a little longer time, but is a safer choice from FSM point of view. + */ + if (nocarrier && pcb->phase == PPP_PHASE_RUNNING) { + PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: carrier lost -> lcp_lowerdown\n", pcb->netif->num)); + lcp_lowerdown(pcb); + /* forced link termination, this will force link protocol to disconnect. */ + link_terminated(pcb); + return ERR_OK; + } + + /* Disconnect */ + PPPDEBUG(LOG_DEBUG, ("ppp_close[%d]: kill_link -> lcp_close\n", pcb->netif->num)); + /* LCP soft close request. */ + lcp_close(pcb, "User request"); + return ERR_OK; +} + +/* + * Release the control block. + * + * This can only be called if PPP is in the dead phase. + * + * You must use ppp_close() before if you wish to terminate + * an established PPP session. + * + * Return 0 on success, an error code on failure. + */ +err_t ppp_free(ppp_pcb *pcb) { + err_t err; + if (pcb->phase != PPP_PHASE_DEAD) { + return ERR_CONN; + } + + PPPDEBUG(LOG_DEBUG, ("ppp_free[%d]\n", pcb->netif->num)); + + netif_remove(pcb->netif); + + err = pcb->link_cb->free(pcb, pcb->link_ctx_cb); + + LWIP_MEMPOOL_FREE(PPP_PCB, pcb); + return err; +} + +/* Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. */ +err_t +ppp_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg) +{ + if (pcb == NULL) { + return ERR_VAL; + } + + switch(cmd) { + case PPPCTLG_UPSTATUS: /* Get the PPP up status. */ + if (!arg) { + goto fail; + } + *(int *)arg = (int)(0 +#if PPP_IPV4_SUPPORT + || pcb->if4_up +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || pcb->if6_up +#endif /* PPP_IPV6_SUPPORT */ + ); + return ERR_OK; + + case PPPCTLG_ERRCODE: /* Get the PPP error code. */ + if (!arg) { + goto fail; + } + *(int *)arg = (int)(pcb->err_code); + return ERR_OK; + + default: + goto fail; + } + +fail: + return ERR_VAL; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +static void ppp_do_connect(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); + + new_phase(pcb, PPP_PHASE_INITIALIZE); + pcb->link_cb->connect(pcb, pcb->link_ctx_cb); +} + +/* + * ppp_netif_init_cb - netif init callback + */ +static err_t ppp_netif_init_cb(struct netif *netif) { + netif->name[0] = 'p'; + netif->name[1] = 'p'; +#if LWIP_IPV4 + /* FIXME: change that when netif_null_output_ip4() will materialize */ + netif->output = ppp_netif_output_ip4; +#endif /* LWIP_IPV4 */ +#if PPP_IPV6_SUPPORT + netif->output_ip6 = ppp_netif_output_ip6; +#endif /* PPP_IPV6_SUPPORT */ + netif->flags = NETIF_FLAG_UP; +#if LWIP_NETIF_HOSTNAME + /* @todo: Initialize interface hostname */ + /* netif_set_hostname(netif, "lwip"); */ +#endif /* LWIP_NETIF_HOSTNAME */ + return ERR_OK; +} + +#if LWIP_IPV4 +/* + * Send an IPv4 packet on the given connection. + */ +static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, const ip4_addr_t *ipaddr) { + LWIP_UNUSED_ARG(ipaddr); +#if PPP_IPV4_SUPPORT + return ppp_netif_output(netif, pb, PPP_IP); +#else /* PPP_IPV4_SUPPORT */ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(pb); + return ERR_IF; +#endif /* PPP_IPV4_SUPPORT */ +} +#endif /* LWIP_IPV4 */ + +#if PPP_IPV6_SUPPORT +/* + * Send an IPv6 packet on the given connection. + */ +static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, const ip6_addr_t *ipaddr) { + LWIP_UNUSED_ARG(ipaddr); + return ppp_netif_output(netif, pb, PPP_IPV6); +} +#endif /* PPP_IPV6_SUPPORT */ + +static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protocol) { + ppp_pcb *pcb = (ppp_pcb*)netif->state; + err_t err; + struct pbuf *fpb = NULL; + + /* Check that the link is up. */ + if (0 +#if PPP_IPV4_SUPPORT + || (protocol == PPP_IP && !pcb->if4_up) +#endif /* PPP_IPV4_SUPPORT */ +#if PPP_IPV6_SUPPORT + || (protocol == PPP_IPV6 && !pcb->if6_up) +#endif /* PPP_IPV6_SUPPORT */ + ) { + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: link not up\n", pcb->netif->num)); + goto err_rte_drop; + } + +#if MPPE_SUPPORT + /* If MPPE is required, refuse any IP packet until we are able to crypt them. */ + if (pcb->settings.require_mppe && pcb->ccp_transmit_method != CI_MPPE) { + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: MPPE required, not up\n", pcb->netif->num)); + goto err_rte_drop; + } +#endif /* MPPE_SUPPORT */ + +#if VJ_SUPPORT + /* + * Attempt Van Jacobson header compression if VJ is configured and + * this is an IP packet. + */ + if (protocol == PPP_IP && pcb->vj_enabled) { + switch (vj_compress_tcp(&pcb->vj_comp, &pb)) { + case TYPE_IP: + /* No change... + protocol = PPP_IP; */ + break; + case TYPE_COMPRESSED_TCP: + /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_VJC_COMP; + break; + case TYPE_UNCOMPRESSED_TCP: + /* vj_compress_tcp() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_VJC_UNCOMP; + break; + default: + PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: bad IP packet\n", pcb->netif->num)); + LINK_STATS_INC(link.proterr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pcb->netif, ifoutdiscards); + return ERR_VAL; + } + } +#endif /* VJ_SUPPORT */ + +#if CCP_SUPPORT + switch (pcb->ccp_transmit_method) { + case 0: + break; /* Don't compress */ +#if MPPE_SUPPORT + case CI_MPPE: + if ((err = mppe_compress(pcb, &pcb->mppe_comp, &pb, protocol)) != ERR_OK) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + goto err; + } + /* if VJ compressor returned a new allocated pbuf, free it */ + if (fpb) { + pbuf_free(fpb); + } + /* mppe_compress() returns a new allocated pbuf, indicate we should free + * our duplicated pbuf later */ + fpb = pb; + protocol = PPP_COMP; + break; +#endif /* MPPE_SUPPORT */ + default: + PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: bad CCP transmit method\n", pcb->netif->num)); + goto err_rte_drop; /* Cannot really happen, we only negotiate what we are able to do */ + } +#endif /* CCP_SUPPORT */ + + err = pcb->link_cb->netif_output(pcb, pcb->link_ctx_cb, pb, protocol); + goto err; + +err_rte_drop: + err = ERR_RTE; + LINK_STATS_INC(link.rterr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); +err: + if (fpb) { + pbuf_free(fpb); + } + return err; +} + +/************************************/ +/*** PRIVATE FUNCTION DEFINITIONS ***/ +/************************************/ + +/* Initialize the PPP subsystem. */ +int ppp_init(void) +{ +#if PPPOS_SUPPORT + LWIP_MEMPOOL_INIT(PPPOS_PCB); +#endif +#if PPPOE_SUPPORT + LWIP_MEMPOOL_INIT(PPPOE_IF); +#endif +#if PPPOL2TP_SUPPORT + LWIP_MEMPOOL_INIT(PPPOL2TP_PCB); +#endif +#if LWIP_PPP_API && LWIP_MPU_COMPATIBLE + LWIP_MEMPOOL_INIT(PPPAPI_MSG); +#endif + + LWIP_MEMPOOL_INIT(PPP_PCB); + + /* + * Initialize magic number generator now so that protocols may + * use magic numbers in initialization. + */ + magic_init(); + + return 0; +} + +/* + * Create a new PPP control block. + * + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. + * + * Return a new PPP connection control block pointer + * on success or a null pointer on failure. + */ +ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, void *link_ctx_cb, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { + ppp_pcb *pcb; + const struct protent *protp; + int i; + + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + if (link_status_cb == NULL) { + return NULL; + } + + pcb = (ppp_pcb*)LWIP_MEMPOOL_ALLOC(PPP_PCB); + if (pcb == NULL) { + return NULL; + } + + memset(pcb, 0, sizeof(ppp_pcb)); + + /* default configuration */ +#if PAP_SUPPORT + pcb->settings.pap_timeout_time = UPAP_DEFTIMEOUT; + pcb->settings.pap_max_transmits = UPAP_DEFTRANSMITS; +#if PPP_SERVER + pcb->settings.pap_req_timeout = UPAP_DEFREQTIME; +#endif /* PPP_SERVER */ +#endif /* PAP_SUPPORT */ + +#if CHAP_SUPPORT + pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT; + pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS; +#if PPP_SERVER + pcb->settings.chap_rechallenge_time = CHAP_DEFRECHALLENGETIME; +#endif /* PPP_SERVER */ +#endif /* CHAP_SUPPPORT */ + +#if EAP_SUPPORT + pcb->settings.eap_req_time = EAP_DEFREQTIME; + pcb->settings.eap_allow_req = EAP_DEFALLOWREQ; +#if PPP_SERVER + pcb->settings.eap_timeout_time = EAP_DEFTIMEOUT; + pcb->settings.eap_max_transmits = EAP_DEFTRANSMITS; +#endif /* PPP_SERVER */ +#endif /* EAP_SUPPORT */ + + pcb->settings.lcp_loopbackfail = LCP_DEFLOOPBACKFAIL; + pcb->settings.lcp_echo_interval = LCP_ECHOINTERVAL; + pcb->settings.lcp_echo_fails = LCP_MAXECHOFAILS; + + pcb->settings.fsm_timeout_time = FSM_DEFTIMEOUT; + pcb->settings.fsm_max_conf_req_transmits = FSM_DEFMAXCONFREQS; + pcb->settings.fsm_max_term_transmits = FSM_DEFMAXTERMREQS; + pcb->settings.fsm_max_nak_loops = FSM_DEFMAXNAKLOOPS; + + pcb->netif = pppif; + MIB2_INIT_NETIF(pppif, snmp_ifType_ppp, 0); + if (!netif_add(pcb->netif, +#if LWIP_IPV4 + IP4_ADDR_ANY4, IP4_ADDR_BROADCAST, IP4_ADDR_ANY4, +#endif /* LWIP_IPV4 */ + (void *)pcb, ppp_netif_init_cb, NULL)) { + LWIP_MEMPOOL_FREE(PPP_PCB, pcb); + PPPDEBUG(LOG_ERR, ("ppp_new: netif_add failed\n")); + return NULL; + } + + pcb->link_cb = callbacks; + pcb->link_ctx_cb = link_ctx_cb; + pcb->link_status_cb = link_status_cb; + pcb->ctx_cb = ctx_cb; + + /* + * Initialize each protocol. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + (*protp->init)(pcb); + } + + new_phase(pcb, PPP_PHASE_DEAD); + return pcb; +} + +/** Initiate LCP open request */ +void ppp_start(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]\n", pcb->netif->num)); + + /* Clean data not taken care by anything else, mostly shared data. */ +#if PPP_STATS_SUPPORT + link_stats_valid = 0; +#endif /* PPP_STATS_SUPPORT */ +#if MPPE_SUPPORT + pcb->mppe_keys_set = 0; + memset(&pcb->mppe_comp, 0, sizeof(pcb->mppe_comp)); + memset(&pcb->mppe_decomp, 0, sizeof(pcb->mppe_decomp)); +#endif /* MPPE_SUPPORT */ +#if VJ_SUPPORT + vj_compress_init(&pcb->vj_comp); +#endif /* VJ_SUPPORT */ + + /* Start protocol */ + new_phase(pcb, PPP_PHASE_ESTABLISH); + lcp_open(pcb); + lcp_lowerup(pcb); + PPPDEBUG(LOG_DEBUG, ("ppp_start[%d]: finished\n", pcb->netif->num)); +} + +/** Called when link failed to setup */ +void ppp_link_failed(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_failed[%d]\n", pcb->netif->num)); + new_phase(pcb, PPP_PHASE_DEAD); + pcb->err_code = PPPERR_OPEN; + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); +} + +/** Called when link is normally down (i.e. it was asked to end) */ +void ppp_link_end(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_end[%d]\n", pcb->netif->num)); + new_phase(pcb, PPP_PHASE_DEAD); + if (pcb->err_code == PPPERR_NONE) { + pcb->err_code = PPPERR_CONNECT; + } + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); +} + +/* + * Pass the processed input packet to the appropriate handler. + * This function and all handlers run in the context of the tcpip_thread + */ +void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { + u16_t protocol; +#if PPP_DEBUG && PPP_PROTOCOLNAME + const char *pname; +#endif /* PPP_DEBUG && PPP_PROTOCOLNAME */ + + magic_randomize(); + + if (pb->len < 2) { + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: packet too short\n", pcb->netif->num)); + goto drop; + } + protocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; + +#if PRINTPKT_SUPPORT + ppp_dump_packet(pcb, "rcvd", (unsigned char *)pb->payload, pb->len); +#endif /* PRINTPKT_SUPPORT */ + + pbuf_header(pb, -(s16_t)sizeof(protocol)); + + LINK_STATS_INC(link.recv); + MIB2_STATS_NETIF_INC(pcb->netif, ifinucastpkts); + MIB2_STATS_NETIF_ADD(pcb->netif, ifinoctets, pb->tot_len); + + /* + * Toss all non-LCP packets unless LCP is OPEN. + */ + if (protocol != PPP_LCP && pcb->lcp_fsm.state != PPP_FSM_OPENED) { + ppp_dbglog("Discarded non-LCP packet when LCP not open"); + goto drop; + } + + /* + * Until we get past the authentication phase, toss all packets + * except LCP, LQR and authentication packets. + */ + if (pcb->phase <= PPP_PHASE_AUTHENTICATE + && !(protocol == PPP_LCP +#if LQR_SUPPORT + || protocol == PPP_LQR +#endif /* LQR_SUPPORT */ +#if PAP_SUPPORT + || protocol == PPP_PAP +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT + || protocol == PPP_CHAP +#endif /* CHAP_SUPPORT */ +#if EAP_SUPPORT + || protocol == PPP_EAP +#endif /* EAP_SUPPORT */ + )) { + ppp_dbglog("discarding proto 0x%x in phase %d", protocol, pcb->phase); + goto drop; + } + +#if CCP_SUPPORT +#if MPPE_SUPPORT + /* + * MPPE is required and unencrypted data has arrived (this + * should never happen!). We should probably drop the link if + * the protocol is in the range of what should be encrypted. + * At the least, we drop this packet. + */ + if (pcb->settings.require_mppe && protocol != PPP_COMP && protocol < 0x8000) { + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: MPPE required, received unencrypted data!\n", pcb->netif->num)); + goto drop; + } +#endif /* MPPE_SUPPORT */ + + if (protocol == PPP_COMP) { + u8_t *pl; + + switch (pcb->ccp_receive_method) { +#if MPPE_SUPPORT + case CI_MPPE: + if (mppe_decompress(pcb, &pcb->mppe_decomp, &pb) != ERR_OK) { + goto drop; + } + break; +#endif /* MPPE_SUPPORT */ + default: + PPPDEBUG(LOG_ERR, ("ppp_input[%d]: bad CCP receive method\n", pcb->netif->num)); + goto drop; /* Cannot really happen, we only negotiate what we are able to do */ + } + + /* Assume no PFC */ + if (pb->len < 2) { + goto drop; + } + + /* Extract and hide protocol (do PFC decompression if necessary) */ + pl = (u8_t*)pb->payload; + if (pl[0] & 0x01) { + protocol = pl[0]; + pbuf_header(pb, -(s16_t)1); + } else { + protocol = (pl[0] << 8) | pl[1]; + pbuf_header(pb, -(s16_t)2); + } + } +#endif /* CCP_SUPPORT */ + + switch(protocol) { + +#if PPP_IPV4_SUPPORT + case PPP_IP: /* Internet Protocol */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + ip4_input(pb, pcb->netif); + return; +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT + case PPP_IPV6: /* Internet Protocol Version 6 */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip6 in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + ip6_input(pb, pcb->netif); + return; +#endif /* PPP_IPV6_SUPPORT */ + +#if VJ_SUPPORT + case PPP_VJC_COMP: /* VJ compressed TCP */ + /* + * Clip off the VJ header and prepend the rebuilt TCP/IP header and + * pass the result to IP. + */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_comp in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + if (pcb->vj_enabled && vj_uncompress_tcp(&pb, &pcb->vj_comp) >= 0) { + ip4_input(pb, pcb->netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ compressed\n", pcb->netif->num)); + break; + + case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ + /* + * Process the TCP/IP header for VJ header compression and then pass + * the packet to IP. + */ + PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_un in pbuf len=%d\n", pcb->netif->num, pb->tot_len)); + if (pcb->vj_enabled && vj_uncompress_uncomp(pb, &pcb->vj_comp) >= 0) { + ip4_input(pb, pcb->netif); + return; + } + /* Something's wrong so drop it. */ + PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ uncompressed\n", pcb->netif->num)); + break; +#endif /* VJ_SUPPORT */ + + default: { + int i; + const struct protent *protp; + + /* + * Upcall the proper protocol input routine. + */ + for (i = 0; (protp = protocols[i]) != NULL; ++i) { + if (protp->protocol == protocol) { + pb = ppp_singlebuf(pb); + (*protp->input)(pcb, (u8_t*)pb->payload, pb->len); + goto out; + } +#if 0 /* UNUSED + * + * This is actually a (hacked?) way for the Linux kernel to pass a data + * packet to pppd. pppd in normal condition only do signaling + * (LCP, PAP, CHAP, IPCP, ...) and does not handle any data packet at all. + * + * We don't even need this interface, which is only there because of PPP + * interface limitation between Linux kernel and pppd. For MPPE, which uses + * CCP to negotiate although it is not really a (de)compressor, we added + * ccp_resetrequest() in CCP and MPPE input data flow is calling either + * ccp_resetrequest() or lcp_close() if the issue is, respectively, non-fatal + * or fatal, this is what ccp_datainput() really do. + */ + if (protocol == (protp->protocol & ~0x8000) + && protp->datainput != NULL) { + (*protp->datainput)(pcb, pb->payload, pb->len); + goto out; + } +#endif /* UNUSED */ + } + +#if PPP_DEBUG +#if PPP_PROTOCOLNAME + pname = protocol_name(protocol); + if (pname != NULL) { + ppp_warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); + } else +#endif /* PPP_PROTOCOLNAME */ + ppp_warn("Unsupported protocol 0x%x received", protocol); +#endif /* PPP_DEBUG */ + pbuf_header(pb, (s16_t)sizeof(protocol)); + lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len); + } + break; + } + +drop: + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pcb->netif, ifindiscards); + +out: + pbuf_free(pb); +} + +/* merge a pbuf chain into one pbuf */ +struct pbuf *ppp_singlebuf(struct pbuf *p) { + struct pbuf *q, *b; + u8_t *pl; + + if(p->tot_len == p->len) { + return p; + } + + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(!q) { + PPPDEBUG(LOG_ERR, + ("ppp_singlebuf: unable to alloc new buf (%d)\n", p->tot_len)); + return p; /* live dangerously */ + } + + for(b = p, pl = (u8_t*)q->payload; b != NULL; b = b->next) { + MEMCPY(pl, b->payload, b->len); + pl += b->len; + } + + pbuf_free(p); + + return q; +} + +/* + * Write a pbuf to a ppp link, only used from PPP functions + * to send PPP packets. + * + * IPv4 and IPv6 packets from lwIP are sent, respectively, + * with ppp_netif_output_ip4() and ppp_netif_output_ip6() + * functions (which are callbacks of the netif PPP interface). + */ +err_t ppp_write(ppp_pcb *pcb, struct pbuf *p) { +#if PRINTPKT_SUPPORT + ppp_dump_packet(pcb, "sent", (unsigned char *)p->payload+2, p->len-2); +#endif /* PRINTPKT_SUPPORT */ + return pcb->link_cb->write(pcb, pcb->link_ctx_cb, p); +} + +void ppp_link_terminated(ppp_pcb *pcb) { + PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]\n", pcb->netif->num)); + pcb->link_cb->disconnect(pcb, pcb->link_ctx_cb); + PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated[%d]: finished.\n", pcb->netif->num)); +} + + +/************************************************************************ + * Functions called by various PPP subsystems to configure + * the PPP interface or change the PPP phase. + */ + +/* + * new_phase - signal the start of a new phase of pppd's operation. + */ +void new_phase(ppp_pcb *pcb, int p) { + pcb->phase = p; + PPPDEBUG(LOG_DEBUG, ("ppp phase changed[%d]: phase=%d\n", pcb->netif->num, pcb->phase)); +#if PPP_NOTIFY_PHASE + if (pcb->notify_phase_cb != NULL) { + pcb->notify_phase_cb(pcb, p, pcb->ctx_cb); + } +#endif /* PPP_NOTIFY_PHASE */ +} + +/* + * ppp_send_config - configure the transmit-side characteristics of + * the ppp interface. + */ +int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { + LWIP_UNUSED_ARG(mtu); + /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */ + + if (pcb->link_cb->send_config) { + pcb->link_cb->send_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); + } + + PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num) ); + return 0; +} + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. + */ +int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) { + LWIP_UNUSED_ARG(mru); + + if (pcb->link_cb->recv_config) { + pcb->link_cb->recv_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp); + } + + PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num)); + return 0; +} + +#if PPP_IPV4_SUPPORT +/* + * sifaddr - Config the interface IP addresses and netmask. + */ +int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t netmask) { + ip4_addr_t ip, nm, gw; + + ip4_addr_set_u32(&ip, our_adr); + ip4_addr_set_u32(&nm, netmask); + ip4_addr_set_u32(&gw, his_adr); + netif_set_addr(pcb->netif, &ip, &nm, &gw); + return 1; +} + +/******************************************************************** + * + * cifaddr - Clear the interface IP addresses, and delete routes + * through the interface if possible. + */ +int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr) { + LWIP_UNUSED_ARG(our_adr); + LWIP_UNUSED_ARG(his_adr); + + netif_set_addr(pcb->netif, IP4_ADDR_ANY4, IP4_ADDR_BROADCAST, IP4_ADDR_ANY4); + return 1; +} + +#if 0 /* UNUSED - PROXY ARP */ +/******************************************************************** + * + * sifproxyarp - Make a proxy ARP entry for the peer. + */ + +int sifproxyarp(ppp_pcb *pcb, u32_t his_adr) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(his_adr); + return 0; +} + +/******************************************************************** + * + * cifproxyarp - Delete the proxy ARP entry for the peer. + */ + +int cifproxyarp(ppp_pcb *pcb, u32_t his_adr) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(his_adr); + return 0; +} +#endif /* UNUSED - PROXY ARP */ + +#if LWIP_DNS +/* + * sdns - Config the DNS servers + */ +int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { + ip_addr_t ns; + LWIP_UNUSED_ARG(pcb); + + ip_addr_set_ip4_u32(&ns, ns1); + dns_setserver(0, &ns); + ip_addr_set_ip4_u32(&ns, ns2); + dns_setserver(1, &ns); + return 1; +} + +/******************************************************************** + * + * cdns - Clear the DNS servers + */ +int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { + const ip_addr_t *nsa; + ip_addr_t nsb; + LWIP_UNUSED_ARG(pcb); + + nsa = dns_getserver(0); + ip_addr_set_ip4_u32(&nsb, ns1); + if (ip_addr_cmp(nsa, &nsb)) { + dns_setserver(0, IP_ADDR_ANY); + } + nsa = dns_getserver(1); + ip_addr_set_ip4_u32(&nsb, ns2); + if (ip_addr_cmp(nsa, &nsb)) { + dns_setserver(1, IP_ADDR_ANY); + } + return 1; +} +#endif /* LWIP_DNS */ + +#if VJ_SUPPORT +/******************************************************************** + * + * sifvjcomp - config tcp header compression + */ +int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid) { + pcb->vj_enabled = vjcomp; + pcb->vj_comp.compressSlot = cidcomp; + pcb->vj_comp.maxSlotIndex = maxcid; + PPPDEBUG(LOG_INFO, ("sifvjcomp[%d]: VJ compress enable=%d slot=%d max slot=%d\n", + pcb->netif->num, vjcomp, cidcomp, maxcid)); + return 0; +} +#endif /* VJ_SUPPORT */ + +/* + * sifup - Config the interface up and enable IP packets to pass. + */ +int sifup(ppp_pcb *pcb) { + pcb->if4_up = 1; + pcb->err_code = PPPERR_NONE; + netif_set_link_up(pcb->netif); + + PPPDEBUG(LOG_DEBUG, ("sifup[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return 1; +} + +/******************************************************************** + * + * sifdown - Disable the indicated protocol and config the interface + * down if there are no remaining protocols. + */ +int sifdown(ppp_pcb *pcb) { + + pcb->if4_up = 0; + + if (1 +#if PPP_IPV6_SUPPORT + /* set the interface down if IPv6 is down as well */ + && !pcb->if6_up +#endif /* PPP_IPV6_SUPPORT */ + ) { + /* make sure the netif link callback is called */ + netif_set_link_down(pcb->netif); + } + PPPDEBUG(LOG_DEBUG, ("sifdown[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + return 1; +} + +/******************************************************************** + * + * Return user specified netmask, modified by any mask we might determine + * for address `addr' (in network byte order). + * Here we scan through the system's list of interfaces, looking for + * any non-point-to-point interfaces which might appear to be on the same + * network as `addr'. If we find any, we OR in their netmask to the + * user-specified netmask. + */ +u32_t get_mask(u32_t addr) { +#if 0 + u32_t mask, nmask; + + addr = lwip_htonl(addr); + if (IP_CLASSA(addr)) { /* determine network mask for address class */ + nmask = IP_CLASSA_NET; + } else if (IP_CLASSB(addr)) { + nmask = IP_CLASSB_NET; + } else { + nmask = IP_CLASSC_NET; + } + + /* class D nets are disallowed by bad_ip_adrs */ + mask = PP_HTONL(0xffffff00UL) | lwip_htonl(nmask); + + /* XXX + * Scan through the system's network interfaces. + * Get each netmask and OR them into our mask. + */ + /* return mask; */ + return mask; +#endif /* 0 */ + LWIP_UNUSED_ARG(addr); + return IPADDR_BROADCAST; +} +#endif /* PPP_IPV4_SUPPORT */ + +#if PPP_IPV6_SUPPORT +#define IN6_LLADDR_FROM_EUI64(ip6, eui64) do { \ + ip6.addr[0] = PP_HTONL(0xfe800000); \ + ip6.addr[1] = 0; \ + eui64_copy(eui64, ip6.addr[2]); \ + } while (0) + +/******************************************************************** + * + * sif6addr - Config the interface with an IPv6 link-local address + */ +int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { + ip6_addr_t ip6; + LWIP_UNUSED_ARG(his_eui64); + + IN6_LLADDR_FROM_EUI64(ip6, our_eui64); + netif_ip6_addr_set(pcb->netif, 0, &ip6); + netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_PREFERRED); + /* FIXME: should we add an IPv6 static neighbor using his_eui64 ? */ + return 1; +} + +/******************************************************************** + * + * cif6addr - Remove IPv6 address from interface + */ +int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { + LWIP_UNUSED_ARG(our_eui64); + LWIP_UNUSED_ARG(his_eui64); + + netif_ip6_addr_set(pcb->netif, 0, IP6_ADDR_ANY6); + netif_ip6_addr_set_state(pcb->netif, 0, IP6_ADDR_INVALID); + return 1; +} + +/* + * sif6up - Config the interface up and enable IPv6 packets to pass. + */ +int sif6up(ppp_pcb *pcb) { + + pcb->if6_up = 1; + pcb->err_code = PPPERR_NONE; + netif_set_link_up(pcb->netif); + + PPPDEBUG(LOG_DEBUG, ("sif6up[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); + return 1; +} + +/******************************************************************** + * + * sif6down - Disable the indicated protocol and config the interface + * down if there are no remaining protocols. + */ +int sif6down(ppp_pcb *pcb) { + + pcb->if6_up = 0; + + if (1 +#if PPP_IPV4_SUPPORT + /* set the interface down if IPv4 is down as well */ + && !pcb->if4_up +#endif /* PPP_IPV4_SUPPORT */ + ) { + /* make sure the netif link callback is called */ + netif_set_link_down(pcb->netif); + } + PPPDEBUG(LOG_DEBUG, ("sif6down[%d]: err_code=%d\n", pcb->netif->num, pcb->err_code)); + return 1; +} +#endif /* PPP_IPV6_SUPPORT */ + +#if DEMAND_SUPPORT +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) { + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(proto); + LWIP_UNUSED_ARG(mode); + return 0; +} +#endif /* DEMAND_SUPPORT */ + +/* + * netif_set_mtu - set the MTU on the PPP network interface. + */ +void netif_set_mtu(ppp_pcb *pcb, int mtu) { + + pcb->netif->mtu = mtu; + PPPDEBUG(LOG_INFO, ("netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu)); +} + +/* + * netif_get_mtu - get PPP interface MTU + */ +int netif_get_mtu(ppp_pcb *pcb) { + + return pcb->netif->mtu; +} + +#if CCP_SUPPORT +#if 0 /* unused */ +/* + * ccp_test - whether a given compression method is acceptable for use. + */ +int +ccp_test(ppp_pcb *pcb, u_char *opt_ptr, int opt_len, int for_transmit) +{ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(opt_ptr); + LWIP_UNUSED_ARG(opt_len); + LWIP_UNUSED_ARG(for_transmit); + return -1; +} +#endif /* unused */ + +/* + * ccp_set - inform about the current state of CCP. + */ +void +ccp_set(ppp_pcb *pcb, u8_t isopen, u8_t isup, u8_t receive_method, u8_t transmit_method) +{ + LWIP_UNUSED_ARG(isopen); + LWIP_UNUSED_ARG(isup); + pcb->ccp_receive_method = receive_method; + pcb->ccp_transmit_method = transmit_method; + PPPDEBUG(LOG_DEBUG, ("ccp_set[%d]: is_open=%d, is_up=%d, receive_method=%u, transmit_method=%u\n", + pcb->netif->num, isopen, isup, receive_method, transmit_method)); +} + +void +ccp_reset_comp(ppp_pcb *pcb) +{ + switch (pcb->ccp_transmit_method) { +#if MPPE_SUPPORT + case CI_MPPE: + mppe_comp_reset(pcb, &pcb->mppe_comp); + break; +#endif /* MPPE_SUPPORT */ + default: + break; + } +} + +void +ccp_reset_decomp(ppp_pcb *pcb) +{ + switch (pcb->ccp_receive_method) { +#if MPPE_SUPPORT + case CI_MPPE: + mppe_decomp_reset(pcb, &pcb->mppe_decomp); + break; +#endif /* MPPE_SUPPORT */ + default: + break; + } +} + +#if 0 /* unused */ +/* + * ccp_fatal_error - returns 1 if decompression was disabled as a + * result of an error detected after decompression of a packet, + * 0 otherwise. This is necessary because of patent nonsense. + */ +int +ccp_fatal_error(ppp_pcb *pcb) +{ + LWIP_UNUSED_ARG(pcb); + return 1; +} +#endif /* unused */ +#endif /* CCP_SUPPORT */ + +#if PPP_IDLETIMELIMIT +/******************************************************************** + * + * get_idle_time - return how long the link has been idle. + */ +int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip) { + /* FIXME: add idle time support and make it optional */ + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(ip); + return 1; +} +#endif /* PPP_IDLETIMELIMIT */ + +#if DEMAND_SUPPORT +/******************************************************************** + * + * get_loop_output - get outgoing packets from the ppp device, + * and detect when we want to bring the real link up. + * Return value is 1 if we need to bring up the link, 0 otherwise. + */ +int get_loop_output(void) { + return 0; +} +#endif /* DEMAND_SUPPORT */ + +#if PPP_PROTOCOLNAME +/* List of protocol names, to make our messages a little more informative. */ +struct protocol_list { + u_short proto; + const char *name; +} const protocol_list[] = { + { 0x21, "IP" }, + { 0x23, "OSI Network Layer" }, + { 0x25, "Xerox NS IDP" }, + { 0x27, "DECnet Phase IV" }, + { 0x29, "Appletalk" }, + { 0x2b, "Novell IPX" }, + { 0x2d, "VJ compressed TCP/IP" }, + { 0x2f, "VJ uncompressed TCP/IP" }, + { 0x31, "Bridging PDU" }, + { 0x33, "Stream Protocol ST-II" }, + { 0x35, "Banyan Vines" }, + { 0x39, "AppleTalk EDDP" }, + { 0x3b, "AppleTalk SmartBuffered" }, + { 0x3d, "Multi-Link" }, + { 0x3f, "NETBIOS Framing" }, + { 0x41, "Cisco Systems" }, + { 0x43, "Ascom Timeplex" }, + { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, + { 0x47, "DCA Remote Lan" }, + { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, + { 0x4b, "SNA over 802.2" }, + { 0x4d, "SNA" }, + { 0x4f, "IP6 Header Compression" }, + { 0x51, "KNX Bridging Data" }, + { 0x53, "Encryption" }, + { 0x55, "Individual Link Encryption" }, + { 0x57, "IPv6" }, + { 0x59, "PPP Muxing" }, + { 0x5b, "Vendor-Specific Network Protocol" }, + { 0x61, "RTP IPHC Full Header" }, + { 0x63, "RTP IPHC Compressed TCP" }, + { 0x65, "RTP IPHC Compressed non-TCP" }, + { 0x67, "RTP IPHC Compressed UDP 8" }, + { 0x69, "RTP IPHC Compressed RTP 8" }, + { 0x6f, "Stampede Bridging" }, + { 0x73, "MP+" }, + { 0xc1, "NTCITS IPI" }, + { 0xfb, "single-link compression" }, + { 0xfd, "Compressed Datagram" }, + { 0x0201, "802.1d Hello Packets" }, + { 0x0203, "IBM Source Routing BPDU" }, + { 0x0205, "DEC LANBridge100 Spanning Tree" }, + { 0x0207, "Cisco Discovery Protocol" }, + { 0x0209, "Netcs Twin Routing" }, + { 0x020b, "STP - Scheduled Transfer Protocol" }, + { 0x020d, "EDP - Extreme Discovery Protocol" }, + { 0x0211, "Optical Supervisory Channel Protocol" }, + { 0x0213, "Optical Supervisory Channel Protocol" }, + { 0x0231, "Luxcom" }, + { 0x0233, "Sigma Network Systems" }, + { 0x0235, "Apple Client Server Protocol" }, + { 0x0281, "MPLS Unicast" }, + { 0x0283, "MPLS Multicast" }, + { 0x0285, "IEEE p1284.4 standard - data packets" }, + { 0x0287, "ETSI TETRA Network Protocol Type 1" }, + { 0x0289, "Multichannel Flow Treatment Protocol" }, + { 0x2063, "RTP IPHC Compressed TCP No Delta" }, + { 0x2065, "RTP IPHC Context State" }, + { 0x2067, "RTP IPHC Compressed UDP 16" }, + { 0x2069, "RTP IPHC Compressed RTP 16" }, + { 0x4001, "Cray Communications Control Protocol" }, + { 0x4003, "CDPD Mobile Network Registration Protocol" }, + { 0x4005, "Expand accelerator protocol" }, + { 0x4007, "ODSICP NCP" }, + { 0x4009, "DOCSIS DLL" }, + { 0x400B, "Cetacean Network Detection Protocol" }, + { 0x4021, "Stacker LZS" }, + { 0x4023, "RefTek Protocol" }, + { 0x4025, "Fibre Channel" }, + { 0x4027, "EMIT Protocols" }, + { 0x405b, "Vendor-Specific Protocol (VSP)" }, + { 0x8021, "Internet Protocol Control Protocol" }, + { 0x8023, "OSI Network Layer Control Protocol" }, + { 0x8025, "Xerox NS IDP Control Protocol" }, + { 0x8027, "DECnet Phase IV Control Protocol" }, + { 0x8029, "Appletalk Control Protocol" }, + { 0x802b, "Novell IPX Control Protocol" }, + { 0x8031, "Bridging NCP" }, + { 0x8033, "Stream Protocol Control Protocol" }, + { 0x8035, "Banyan Vines Control Protocol" }, + { 0x803d, "Multi-Link Control Protocol" }, + { 0x803f, "NETBIOS Framing Control Protocol" }, + { 0x8041, "Cisco Systems Control Protocol" }, + { 0x8043, "Ascom Timeplex" }, + { 0x8045, "Fujitsu LBLB Control Protocol" }, + { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, + { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, + { 0x804b, "SNA over 802.2 Control Protocol" }, + { 0x804d, "SNA Control Protocol" }, + { 0x804f, "IP6 Header Compression Control Protocol" }, + { 0x8051, "KNX Bridging Control Protocol" }, + { 0x8053, "Encryption Control Protocol" }, + { 0x8055, "Individual Link Encryption Control Protocol" }, + { 0x8057, "IPv6 Control Protocol" }, + { 0x8059, "PPP Muxing Control Protocol" }, + { 0x805b, "Vendor-Specific Network Control Protocol (VSNCP)" }, + { 0x806f, "Stampede Bridging Control Protocol" }, + { 0x8073, "MP+ Control Protocol" }, + { 0x80c1, "NTCITS IPI Control Protocol" }, + { 0x80fb, "Single Link Compression Control Protocol" }, + { 0x80fd, "Compression Control Protocol" }, + { 0x8207, "Cisco Discovery Protocol Control" }, + { 0x8209, "Netcs Twin Routing" }, + { 0x820b, "STP - Control Protocol" }, + { 0x820d, "EDPCP - Extreme Discovery Protocol Ctrl Prtcl" }, + { 0x8235, "Apple Client Server Protocol Control" }, + { 0x8281, "MPLSCP" }, + { 0x8285, "IEEE p1284.4 standard - Protocol Control" }, + { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, + { 0x8289, "Multichannel Flow Treatment Protocol" }, + { 0xc021, "Link Control Protocol" }, + { 0xc023, "Password Authentication Protocol" }, + { 0xc025, "Link Quality Report" }, + { 0xc027, "Shiva Password Authentication Protocol" }, + { 0xc029, "CallBack Control Protocol (CBCP)" }, + { 0xc02b, "BACP Bandwidth Allocation Control Protocol" }, + { 0xc02d, "BAP" }, + { 0xc05b, "Vendor-Specific Authentication Protocol (VSAP)" }, + { 0xc081, "Container Control Protocol" }, + { 0xc223, "Challenge Handshake Authentication Protocol" }, + { 0xc225, "RSA Authentication Protocol" }, + { 0xc227, "Extensible Authentication Protocol" }, + { 0xc229, "Mitsubishi Security Info Exch Ptcl (SIEP)" }, + { 0xc26f, "Stampede Bridging Authorization Protocol" }, + { 0xc281, "Proprietary Authentication Protocol" }, + { 0xc283, "Proprietary Authentication Protocol" }, + { 0xc481, "Proprietary Node ID Authentication Protocol" }, + { 0, NULL }, +}; + +/* + * protocol_name - find a name for a PPP protocol. + */ +const char * protocol_name(int proto) { + const struct protocol_list *lp; + + for (lp = protocol_list; lp->proto != 0; ++lp) { + if (proto == lp->proto) { + return lp->name; + } + } + return NULL; +} +#endif /* PPP_PROTOCOLNAME */ + +#if PPP_STATS_SUPPORT + +/* ---- Note on PPP Stats support ---- + * + * The one willing link stats support should add the get_ppp_stats() + * to fetch statistics from lwIP. + */ + +/* + * reset_link_stats - "reset" stats when link goes up. + */ +void reset_link_stats(int u) { + if (!get_ppp_stats(u, &old_link_stats)) { + return; + } + gettimeofday(&start_time, NULL); +} + +/* + * update_link_stats - get stats at link termination. + */ +void update_link_stats(int u) { + struct timeval now; + char numbuf[32]; + + if (!get_ppp_stats(u, &link_stats) || gettimeofday(&now, NULL) < 0) { + return; + } + link_connect_time = now.tv_sec - start_time.tv_sec; + link_stats_valid = 1; + + link_stats.bytes_in -= old_link_stats.bytes_in; + link_stats.bytes_out -= old_link_stats.bytes_out; + link_stats.pkts_in -= old_link_stats.pkts_in; + link_stats.pkts_out -= old_link_stats.pkts_out; +} + +void print_link_stats() { + /* + * Print connect time and statistics. + */ + if (link_stats_valid) { + int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ + info("Connect time %d.%d minutes.", t/10, t%10); + info("Sent %u bytes, received %u bytes.", link_stats.bytes_out, link_stats.bytes_in); + link_stats_valid = 0; + } +} +#endif /* PPP_STATS_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppapi.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppapi.c new file mode 100644 index 0000000000..947f7ba8c1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppapi.c @@ -0,0 +1,427 @@ +/** + * @file + * Point To Point Protocol Sequential API module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" + +#if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/pppapi.h" +#include "lwip/priv/tcpip_priv.h" +#include "netif/ppp/pppoe.h" +#include "netif/ppp/pppol2tp.h" +#include "netif/ppp/pppos.h" + +#if LWIP_MPU_COMPATIBLE +LWIP_MEMPOOL_DECLARE(PPPAPI_MSG, MEMP_NUM_PPP_API_MSG, sizeof(struct pppapi_msg), "PPPAPI_MSG") +#endif + +#define PPPAPI_VAR_REF(name) API_VAR_REF(name) +#define PPPAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct pppapi_msg, name) +#define PPPAPI_VAR_ALLOC(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, ERR_MEM) +#define PPPAPI_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC_POOL(struct pppapi_msg, PPPAPI_MSG, name, NULL) +#define PPPAPI_VAR_FREE(name) API_VAR_FREE_POOL(PPPAPI_MSG, name) + +/** + * Call ppp_set_default() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_set_default(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + ppp_set_default(msg->msg.ppp); + return ERR_OK; +} + +/** + * Call ppp_set_default() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_set_default(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_set_default, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +#if PPP_NOTIFY_PHASE +/** + * Call ppp_set_notify_phase_callback() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_set_notify_phase_callback(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + ppp_set_notify_phase_callback(msg->msg.ppp, msg->msg.msg.setnotifyphasecb.notify_phase_cb); + return ERR_OK; +} + +/** + * Call ppp_set_notify_phase_callback() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.setnotifyphasecb.notify_phase_cb = notify_phase_cb; + err = tcpip_api_call(pppapi_do_ppp_set_notify_phase_callback, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} +#endif /* PPP_NOTIFY_PHASE */ + + +#if PPPOS_SUPPORT +/** + * Call pppos_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppos_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppos_create(msg->msg.msg.serialcreate.pppif, msg->msg.msg.serialcreate.output_cb, + msg->msg.msg.serialcreate.link_status_cb, msg->msg.msg.serialcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppos_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.output_cb = output_cb; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.serialcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppos_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOS_SUPPORT */ + + +#if PPPOE_SUPPORT +/** + * Call pppoe_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppoe_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppoe_create(msg->msg.msg.ethernetcreate.pppif, msg->msg.msg.ethernetcreate.ethif, + msg->msg.msg.ethernetcreate.service_name, msg->msg.msg.ethernetcreate.concentrator_name, + msg->msg.msg.ethernetcreate.link_status_cb, msg->msg.msg.ethernetcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppoe_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppoe_create(struct netif *pppif, struct netif *ethif, const char *service_name, + const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, + void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ethif = ethif; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.service_name = service_name; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.concentrator_name = concentrator_name; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.ethernetcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppoe_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOE_SUPPORT */ + + +#if PPPOL2TP_SUPPORT +/** + * Call pppol2tp_create() inside the tcpip_thread context. + */ +static err_t +pppapi_do_pppol2tp_create(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + msg->msg.ppp = pppol2tp_create(msg->msg.msg.l2tpcreate.pppif, + msg->msg.msg.l2tpcreate.netif, API_EXPR_REF(msg->msg.msg.l2tpcreate.ipaddr), msg->msg.msg.l2tpcreate.port, +#if PPPOL2TP_AUTH_SUPPORT + msg->msg.msg.l2tpcreate.secret, + msg->msg.msg.l2tpcreate.secret_len, +#else /* PPPOL2TP_AUTH_SUPPORT */ + NULL, + 0, +#endif /* PPPOL2TP_AUTH_SUPPORT */ + msg->msg.msg.l2tpcreate.link_status_cb, msg->msg.msg.l2tpcreate.ctx_cb); + return ERR_OK; +} + +/** + * Call pppol2tp_create() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +ppp_pcb* +pppapi_pppol2tp_create(struct netif *pppif, struct netif *netif, ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb* result; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC_RETURN_NULL(msg); +#if !PPPOL2TP_AUTH_SUPPORT + LWIP_UNUSED_ARG(secret); + LWIP_UNUSED_ARG(secret_len); +#endif /* !PPPOL2TP_AUTH_SUPPORT */ + + PPPAPI_VAR_REF(msg).msg.ppp = NULL; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.pppif = pppif; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.netif = netif; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ipaddr = PPPAPI_VAR_REF(ipaddr); + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.port = port; +#if PPPOL2TP_AUTH_SUPPORT + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret = secret; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.link_status_cb = link_status_cb; + PPPAPI_VAR_REF(msg).msg.msg.l2tpcreate.ctx_cb = ctx_cb; + tcpip_api_call(pppapi_do_pppol2tp_create, &PPPAPI_VAR_REF(msg).call); + result = PPPAPI_VAR_REF(msg).msg.ppp; + PPPAPI_VAR_FREE(msg); + return result; +} +#endif /* PPPOL2TP_SUPPORT */ + + +/** + * Call ppp_connect() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_connect(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_connect(msg->msg.ppp, msg->msg.msg.connect.holdoff); +} + +/** + * Call ppp_connect() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_connect(ppp_pcb *pcb, u16_t holdoff) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.connect.holdoff = holdoff; + err = tcpip_api_call(pppapi_do_ppp_connect, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +#if PPP_SERVER +/** + * Call ppp_listen() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_listen(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_listen(msg->msg.ppp); +} + +/** + * Call ppp_listen() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_listen(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_listen, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} +#endif /* PPP_SERVER */ + + +/** + * Call ppp_close() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_close(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_close(msg->msg.ppp, msg->msg.msg.close.nocarrier); +} + +/** + * Call ppp_close() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_close(ppp_pcb *pcb, u8_t nocarrier) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.close.nocarrier = nocarrier; + err = tcpip_api_call(pppapi_do_ppp_close, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +/** + * Call ppp_free() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_free(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_free(msg->msg.ppp); +} + +/** + * Call ppp_free() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_free(ppp_pcb *pcb) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + err = tcpip_api_call(pppapi_do_ppp_free, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + + +/** + * Call ppp_ioctl() inside the tcpip_thread context. + */ +static err_t +pppapi_do_ppp_ioctl(struct tcpip_api_call_data *m) +{ + /* cast through void* to silence alignment warnings. + * We know it works because the structs have been instantiated as struct pppapi_msg */ + struct pppapi_msg *msg = (struct pppapi_msg *)(void*)m; + + return ppp_ioctl(msg->msg.ppp, msg->msg.msg.ioctl.cmd, msg->msg.msg.ioctl.arg); +} + +/** + * Call ppp_ioctl() in a thread-safe way by running that function inside the + * tcpip_thread context. + */ +err_t +pppapi_ioctl(ppp_pcb *pcb, u8_t cmd, void *arg) +{ + err_t err; + PPPAPI_VAR_DECLARE(msg); + PPPAPI_VAR_ALLOC(msg); + + PPPAPI_VAR_REF(msg).msg.ppp = pcb; + PPPAPI_VAR_REF(msg).msg.msg.ioctl.cmd = cmd; + PPPAPI_VAR_REF(msg).msg.msg.ioctl.arg = arg; + err = tcpip_api_call(pppapi_do_ppp_ioctl, &PPPAPI_VAR_REF(msg).call); + PPPAPI_VAR_FREE(msg); + return err; +} + +#endif /* LWIP_PPP_API */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppcrypt.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppcrypt.c new file mode 100644 index 0000000000..82d78c13ac --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppcrypt.c @@ -0,0 +1,66 @@ +/* + * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 + * + * Extracted from chap_ms.c by James Carlson. + * + * Copyright (c) 1995 Eric Rosenquist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not necessary */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/pppcrypt.h" + + +static u_char pppcrypt_get_7bits(u_char *input, int startBit) { + unsigned int word; + + word = (unsigned)input[startBit / 8] << 8; + word |= (unsigned)input[startBit / 8 + 1]; + + word >>= 15 - (startBit % 8 + 7); + + return word & 0xFE; +} + +/* IN 56 bit DES key missing parity bits + * OUT 64 bit DES key with parity bits added + */ +void pppcrypt_56_to_64_bit_key(u_char *key, u_char * des_key) { + des_key[0] = pppcrypt_get_7bits(key, 0); + des_key[1] = pppcrypt_get_7bits(key, 7); + des_key[2] = pppcrypt_get_7bits(key, 14); + des_key[3] = pppcrypt_get_7bits(key, 21); + des_key[4] = pppcrypt_get_7bits(key, 28); + des_key[5] = pppcrypt_get_7bits(key, 35); + des_key[6] = pppcrypt_get_7bits(key, 42); + des_key[7] = pppcrypt_get_7bits(key, 49); +} + +#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppoe.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppoe.c new file mode 100644 index 0000000000..eabfa4d041 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppoe.c @@ -0,0 +1,1191 @@ +/***************************************************************************** +* pppoe.c - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher +* Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "lwip/timeouts.h" +#include "lwip/memp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include "netif/ethernet.h" +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/pppoe.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") + +/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ +#define PPPOE_ADD_16(PTR, VAL) \ + *(PTR)++ = (u8_t)((VAL) / 256); \ + *(PTR)++ = (u8_t)((VAL) % 256) + +/* Add a complete PPPoE header to the buffer pointed to by PTR */ +#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ + *(PTR)++ = PPPOE_VERTYPE; \ + *(PTR)++ = (CODE); \ + PPPOE_ADD_16(PTR, SESS); \ + PPPOE_ADD_16(PTR, LEN) + +#define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */ +#define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */ +#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ +#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ + +#ifdef PPPOE_SERVER +#error "PPPOE_SERVER is not yet supported under lwIP!" +/* from if_spppsubr.c */ +#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ +#endif + +#define PPPOE_ERRORSTRING_LEN 64 + + +/* callbacks called from PPP core */ +static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); +static void pppoe_connect(ppp_pcb *ppp, void *ctx); +static void pppoe_disconnect(ppp_pcb *ppp, void *ctx); +static err_t pppoe_destroy(ppp_pcb *ppp, void *ctx); + +/* management routines */ +static void pppoe_abort_connect(struct pppoe_softc *); +#if 0 /* UNUSED */ +static void pppoe_clear_softc(struct pppoe_softc *, const char *); +#endif /* UNUSED */ + +/* internal timeout handling */ +static void pppoe_timeout(void *); + +/* sending actual protocol controll packets */ +static err_t pppoe_send_padi(struct pppoe_softc *); +static err_t pppoe_send_padr(struct pppoe_softc *); +#ifdef PPPOE_SERVER +static err_t pppoe_send_pado(struct pppoe_softc *); +static err_t pppoe_send_pads(struct pppoe_softc *); +#endif +static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); + +/* internal helper functions */ +static err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); +static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif); +static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif); + +/** linked list of created pppoe interfaces */ +static struct pppoe_softc *pppoe_softc_list; + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppoe_callbacks = { + pppoe_connect, +#if PPP_SERVER + NULL, +#endif /* PPP_SERVER */ + pppoe_disconnect, + pppoe_destroy, + pppoe_write, + pppoe_netif_output, + NULL, + NULL +}; + +/* + * Create a new PPP Over Ethernet (PPPoE) connection. + * + * Return 0 on success, an error code on failure. + */ +ppp_pcb *pppoe_create(struct netif *pppif, + struct netif *ethif, + const char *service_name, const char *concentrator_name, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + ppp_pcb *ppp; + struct pppoe_softc *sc; + LWIP_UNUSED_ARG(service_name); + LWIP_UNUSED_ARG(concentrator_name); + + sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF); + if (sc == NULL) { + return NULL; + } + + ppp = ppp_new(pppif, &pppoe_callbacks, sc, link_status_cb, ctx_cb); + if (ppp == NULL) { + LWIP_MEMPOOL_FREE(PPPOE_IF, sc); + return NULL; + } + + memset(sc, 0, sizeof(struct pppoe_softc)); + sc->pcb = ppp; + sc->sc_ethif = ethif; + /* put the new interface at the head of the list */ + sc->next = pppoe_softc_list; + pppoe_softc_list = sc; + return ppp; +} + +/* Called by PPP core */ +static err_t pppoe_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pbuf *ph; /* Ethernet + PPPoE header */ + err_t ret; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* skip address & flags */ + pbuf_header(p, -(s16_t)2); + + ph = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); + if(!ph) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + pbuf_header(ph, -(s16_t)PPPOE_HEADERLEN); /* hide PPPoE header */ + pbuf_cat(ph, p); +#if MIB2_STATS + tot_len = ph->tot_len; +#endif /* MIB2_STATS */ + + ret = pppoe_xmit(sc, ph); + if (ret != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ret; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Called by PPP core */ +static err_t pppoe_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pbuf *pb; + u8_t *pl; + err_t err; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_LINK, PPPOE_HEADERLEN + sizeof(protocol), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + pbuf_header(pb, -(s16_t)PPPOE_HEADERLEN); + + pl = (u8_t*)pb->payload; + PUTSHORT(protocol, pl); + + pbuf_chain(pb, p); +#if MIB2_STATS + tot_len = pb->tot_len; +#endif /* MIB2_STATS */ + + if( (err = pppoe_xmit(sc, pb)) != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return err; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +static err_t +pppoe_destroy(ppp_pcb *ppp, void *ctx) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + struct pppoe_softc **copp, *freep; + LWIP_UNUSED_ARG(ppp); + + sys_untimeout(pppoe_timeout, sc); + + /* remove interface from list */ + for (copp = &pppoe_softc_list; (freep = *copp); copp = &freep->next) { + if (freep == sc) { + *copp = freep->next; + break; + } + } + +#ifdef PPPOE_TODO + if (sc->sc_concentrator_name) { + mem_free(sc->sc_concentrator_name); + } + if (sc->sc_service_name) { + mem_free(sc->sc_service_name); + } +#endif /* PPPOE_TODO */ + LWIP_MEMPOOL_FREE(PPPOE_IF, sc); + + return ERR_OK; +} + +/* + * Find the interface handling the specified session. + * Note: O(number of sessions open), this is a client-side only, mean + * and lean implementation, so number of open sessions typically should + * be 1. + */ +static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) { + struct pppoe_softc *sc; + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc->sc_state == PPPOE_STATE_SESSION + && sc->sc_session == session + && sc->sc_ethif == rcvif) { + return sc; + } + } + return NULL; +} + +/* Check host unique token passed and return appropriate softc pointer, + * or NULL if token is bogus. */ +static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { + struct pppoe_softc *sc, *t; + + if (len != sizeof sc) { + return NULL; + } + MEMCPY(&t, token, len); + + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { + if (sc == t) { + break; + } + } + + if (sc == NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); + return NULL; + } + + /* should be safe to access *sc now */ + if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state)); + return NULL; + } + if (sc->sc_ethif != rcvif) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + return NULL; + } + return sc; +} + +/* analyze and handle a single received packet while not in session state */ +void +pppoe_disc_input(struct netif *netif, struct pbuf *pb) +{ + u16_t tag, len; + u16_t session, plen; + struct pppoe_softc *sc; +#if PPP_DEBUG + const char *err_msg = NULL; +#endif /* PPP_DEBUG */ + u8_t *ac_cookie; + u16_t ac_cookie_len; +#ifdef PPPOE_SERVER + u8_t *hunique; + size_t hunique_len; +#endif + struct pppoehdr *ph; + struct pppoetag pt; + int off, err; + struct eth_hdr *ethhdr; + + /* don't do anything if there is not a single PPPoE instance */ + if (pppoe_softc_list == NULL) { + pbuf_free(pb); + return; + } + + pb = ppp_singlebuf(pb); + + if (pb->len < sizeof(*ethhdr)) { + goto done; + } + ethhdr = (struct eth_hdr *)pb->payload; + off = sizeof(*ethhdr); + + ac_cookie = NULL; + ac_cookie_len = 0; +#ifdef PPPOE_SERVER + hunique = NULL; + hunique_len = 0; +#endif + session = 0; + if (pb->len - off < (u16_t)PPPOE_HEADERLEN) { + PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len)); + goto done; + } + + ph = (struct pppoehdr *) (ethhdr + 1); + if (ph->vertype != PPPOE_VERTYPE) { + PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype)); + goto done; + } + session = lwip_ntohs(ph->session); + plen = lwip_ntohs(ph->plen); + off += sizeof(*ph); + + if (plen + off > pb->len) { + PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n", + pb->len - off, plen)); + goto done; + } + if(pb->tot_len == pb->len) { + pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */ + } + tag = 0; + len = 0; + sc = NULL; + while (off + sizeof(pt) <= pb->len) { + MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); + tag = lwip_ntohs(pt.tag); + len = lwip_ntohs(pt.len); + if (off + sizeof(pt) + len > pb->len) { + PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len)); + goto done; + } + switch (tag) { + case PPPOE_TAG_EOL: + goto breakbreak; + case PPPOE_TAG_SNAME: + break; /* ignored */ + case PPPOE_TAG_ACNAME: + break; /* ignored */ + case PPPOE_TAG_HUNIQUE: + if (sc != NULL) { + break; + } +#ifdef PPPOE_SERVER + hunique = (u8_t*)pb->payload + off + sizeof(pt); + hunique_len = len; +#endif + sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); + break; + case PPPOE_TAG_ACCOOKIE: + if (ac_cookie == NULL) { + if (len > PPPOE_MAX_AC_COOKIE_LEN) { + PPPDEBUG(LOG_DEBUG, ("pppoe: AC cookie is too long: len = %d, max = %d\n", len, PPPOE_MAX_AC_COOKIE_LEN)); + goto done; + } + ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); + ac_cookie_len = len; + } + break; +#if PPP_DEBUG + case PPPOE_TAG_SNAME_ERR: + err_msg = "SERVICE NAME ERROR"; + break; + case PPPOE_TAG_ACSYS_ERR: + err_msg = "AC SYSTEM ERROR"; + break; + case PPPOE_TAG_GENERIC_ERR: + err_msg = "GENERIC ERROR"; + break; +#endif /* PPP_DEBUG */ + default: + break; + } +#if PPP_DEBUG + if (err_msg != NULL) { + char error_tmp[PPPOE_ERRORSTRING_LEN]; + u16_t error_len = LWIP_MIN(len, sizeof(error_tmp)-1); + strncpy(error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); + error_tmp[error_len] = '\0'; + if (sc) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": %s: %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err_msg, error_tmp)); + } else { + PPPDEBUG(LOG_DEBUG, ("pppoe: %s: %s\n", err_msg, error_tmp)); + } + } +#endif /* PPP_DEBUG */ + off += sizeof(pt) + len; + } + +breakbreak:; + switch (ph->code) { + case PPPOE_CODE_PADI: +#ifdef PPPOE_SERVER + /* + * got service name, concentrator name, and/or host unique. + * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. + */ + if (LIST_EMPTY(&pppoe_softc_list)) { + goto done; + } + LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { + continue; + } + if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { + continue; + } + if (sc->sc_state == PPPOE_STATE_INITIAL) { + break; + } + } + if (sc == NULL) { + /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */ + goto done; + } + if (hunique) { + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + } + sc->sc_hunique = mem_malloc(hunique_len); + if (sc->sc_hunique == NULL) { + goto done; + } + sc->sc_hunique_len = hunique_len; + MEMCPY(sc->sc_hunique, hunique, hunique_len); + } + MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); + sc->sc_state = PPPOE_STATE_PADO_SENT; + pppoe_send_pado(sc); + break; +#endif /* PPPOE_SERVER */ + case PPPOE_CODE_PADR: +#ifdef PPPOE_SERVER + /* + * get sc from ac_cookie if IFF_PASSIVE + */ + if (ac_cookie == NULL) { + /* be quiet if there is not a single pppoe instance */ + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n")); + goto done; + } + sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); + if (sc == NULL) { + /* be quiet if there is not a single pppoe instance */ + if (!LIST_EMPTY(&pppoe_softc_list)) { + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n")); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADO_SENT) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + goto done; + } + if (hunique) { + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + } + sc->sc_hunique = mem_malloc(hunique_len); + if (sc->sc_hunique == NULL) { + goto done; + } + sc->sc_hunique_len = hunique_len; + MEMCPY(sc->sc_hunique, hunique, hunique_len); + } + pppoe_send_pads(sc); + sc->sc_state = PPPOE_STATE_SESSION; + ppp_start(sc->pcb); /* notify upper layers */ + break; +#else + /* ignore, we are no access concentrator */ + goto done; +#endif /* PPPOE_SERVER */ + case PPPOE_CODE_PADO: + if (sc == NULL) { + /* be quiet if there is not a single pppoe instance */ + if (pppoe_softc_list != NULL) { + PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n")); + } + goto done; + } + if (sc->sc_state != PPPOE_STATE_PADI_SENT) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + goto done; + } + if (ac_cookie) { + sc->sc_ac_cookie_len = ac_cookie_len; + MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); + } + MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); + sys_untimeout(pppoe_timeout, sc); + sc->sc_padr_retried = 0; + sc->sc_state = PPPOE_STATE_PADR_SENT; + if ((err = pppoe_send_padr(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + break; + case PPPOE_CODE_PADS: + if (sc == NULL) { + goto done; + } + sc->sc_session = session; + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); + sc->sc_state = PPPOE_STATE_SESSION; + ppp_start(sc->pcb); /* notify upper layers */ + break; + case PPPOE_CODE_PADT: + /* Don't disconnect here, we let the LCP Echo/Reply find the fact + * that PPP session is down. Asking the PPP stack to end the session + * require strict checking about the PPP phase to prevent endless + * disconnection loops. + */ +#if 0 /* UNUSED */ + if (sc == NULL) { /* PADT frames are rarely sent with a hunique tag, this is actually almost always true */ + goto done; + } + pppoe_clear_softc(sc, "received PADT"); +#endif /* UNUSED */ + break; + default: + if(sc) { + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, + (u16_t)ph->code, session)); + } else { + PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session)); + } + break; + } + +done: + pbuf_free(pb); + return; +} + +void +pppoe_data_input(struct netif *netif, struct pbuf *pb) +{ + u16_t session, plen; + struct pppoe_softc *sc; + struct pppoehdr *ph; +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + u8_t shost[ETHER_ADDR_LEN]; +#endif + +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); +#endif + if (pbuf_header(pb, -(s16_t)sizeof(struct eth_hdr)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n")); + LINK_STATS_INC(link.lenerr); + goto drop; + } + + if (pb->len < sizeof(*ph)) { + PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n")); + goto drop; + } + ph = (struct pppoehdr *)pb->payload; + + if (ph->vertype != PPPOE_VERTYPE) { + PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype)); + goto drop; + } + if (ph->code != 0) { + goto drop; + } + + session = lwip_ntohs(ph->session); + sc = pppoe_find_softc_by_session(session, netif); + if (sc == NULL) { +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS + PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session)); + pppoe_send_padt(netif, session, shost); +#endif + goto drop; + } + + plen = lwip_ntohs(ph->plen); + + if (pbuf_header(pb, -(s16_t)(PPPOE_HEADERLEN)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); + LINK_STATS_INC(link.lenerr); + goto drop; + } + + PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, + pb->len, plen)); + + if (pb->tot_len < plen) { + goto drop; + } + + /* Dispatch the packet thereby consuming it. */ + ppp_input(sc->pcb, pb); + return; + +drop: + pbuf_free(pb); +} + +static err_t +pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) +{ + struct eth_hdr *ethhdr; + u16_t etype; + err_t res; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(pb, (s16_t)(sizeof(struct eth_hdr))) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + ethhdr = (struct eth_hdr *)pb->payload; + etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; + ethhdr->type = lwip_htons(etype); + MEMCPY(ðhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); + MEMCPY(ðhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr)); + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, + sc->sc_state, sc->sc_session, + sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], + pb->tot_len)); + + res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); + + pbuf_free(pb); + + return res; +} + +static err_t +pppoe_send_padi(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + int len; +#ifdef PPPOE_TODO + int l1 = 0, l2 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ + + /* calculate length of frame (excluding ethernet header + pppoe header) */ + len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { + l1 = (int)strlen(sc->sc_service_name); + len += l1; + } + if (sc->sc_concentrator_name != NULL) { + l2 = (int)strlen(sc->sc_concentrator_name); + len += 2 + 2 + l2; + } +#endif /* PPPOE_TODO */ + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else +#endif /* PPPOE_TODO */ + { + PPPOE_ADD_16(p, 0); + } +#ifdef PPPOE_TODO + if (sc->sc_concentrator_name != NULL) { + PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); + PPPOE_ADD_16(p, l2); + MEMCPY(p, sc->sc_concentrator_name, l2); + p += l2; + } +#endif /* PPPOE_TODO */ + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof sc); + + /* send pkt */ + return pppoe_output(sc, pb); +} + +static void +pppoe_timeout(void *arg) +{ + u32_t retry_wait; + int err; + struct pppoe_softc *sc = (struct pppoe_softc*)arg; + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + + switch (sc->sc_state) { + case PPPOE_STATE_PADI_SENT: + /* + * We have two basic ways of retrying: + * - Quick retry mode: try a few times in short sequence + * - Slow retry mode: we already had a connection successfully + * established and will try infinitely (without user + * intervention) + * We only enter slow retry mode if IFF_LINK1 (aka autodial) + * is not set. + */ + if (sc->sc_padi_retried < 0xff) { + sc->sc_padi_retried++; + } + if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { +#if 0 + if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { + /* slow retry mode */ + retry_wait = PPPOE_SLOW_RETRY; + } else +#endif + { + pppoe_abort_connect(sc); + return; + } + } + /* initialize for quick retry mode */ + retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); + if ((err = pppoe_send_padi(sc)) != 0) { + sc->sc_padi_retried--; + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(retry_wait, pppoe_timeout, sc); + break; + + case PPPOE_STATE_PADR_SENT: + sc->sc_padr_retried++; + if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + sc->sc_state = PPPOE_STATE_PADI_SENT; + sc->sc_padr_retried = 0; + if ((err = pppoe_send_padi(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); + return; + } + if ((err = pppoe_send_padr(sc)) != 0) { + sc->sc_padr_retried--; + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + break; + default: + return; /* all done, work in peace */ + } +} + +/* Start a connection (i.e. initiate discovery phase) */ +static void +pppoe_connect(ppp_pcb *ppp, void *ctx) +{ + err_t err; + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + lcp_options *lcp_wo; + lcp_options *lcp_ao; +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_options *ipcp_wo; + ipcp_options *ipcp_ao; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + sc->sc_session = 0; + sc->sc_ac_cookie_len = 0; + sc->sc_padi_retried = 0; + sc->sc_padr_retried = 0; + /* changed to real address later */ + MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +#ifdef PPPOE_SERVER + /* wait PADI if IFF_PASSIVE */ + if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { + return 0; + } +#endif + + lcp_wo = &ppp->lcp_wantoptions; + lcp_wo->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ + lcp_wo->neg_asyncmap = 0; + lcp_wo->neg_pcompression = 0; + lcp_wo->neg_accompression = 0; + lcp_wo->passive = 0; + lcp_wo->silent = 0; + + lcp_ao = &ppp->lcp_allowoptions; + lcp_ao->mru = sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ + lcp_ao->neg_asyncmap = 0; + lcp_ao->neg_pcompression = 0; + lcp_ao->neg_accompression = 0; + +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_wo = &ppp->ipcp_wantoptions; + ipcp_wo->neg_vj = 0; + ipcp_wo->old_vj = 0; + + ipcp_ao = &ppp->ipcp_allowoptions; + ipcp_ao->neg_vj = 0; + ipcp_ao->old_vj = 0; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + /* save state, in case we fail to send PADI */ + sc->sc_state = PPPOE_STATE_PADI_SENT; + if ((err = pppoe_send_padi(sc)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + } + sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); +} + +/* disconnect */ +static void +pppoe_disconnect(ppp_pcb *ppp, void *ctx) +{ + struct pppoe_softc *sc = (struct pppoe_softc *)ctx; + + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + if (sc->sc_state == PPPOE_STATE_SESSION) { + pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); + } + + /* stop any timer, disconnect can be called while initiating is in progress */ + sys_untimeout(pppoe_timeout, sc); + sc->sc_state = PPPOE_STATE_INITIAL; +#ifdef PPPOE_SERVER + if (sc->sc_hunique) { + mem_free(sc->sc_hunique); + sc->sc_hunique = NULL; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ + } + sc->sc_hunique_len = 0; /* probably not necessary, if state is initial we shouldn't have to access hunique anyway */ +#endif + ppp_link_end(ppp); /* notify upper layers */ + return; +} + +/* Connection attempt aborted */ +static void +pppoe_abort_connect(struct pppoe_softc *sc) +{ + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + sc->sc_state = PPPOE_STATE_INITIAL; + ppp_link_failed(sc->pcb); /* notify upper layers */ +} + +/* Send a PADR packet */ +static err_t +pppoe_send_padr(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; +#ifdef PPPOE_TODO + size_t l1 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ + + len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } +#endif /* PPPOE_TODO */ + if (sc->sc_ac_cookie_len > 0) { + len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ + } + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#ifdef PPPOE_TODO + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else +#endif /* PPPOE_TODO */ + { + PPPOE_ADD_16(p, 0); + } + if (sc->sc_ac_cookie_len > 0) { + PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); + PPPOE_ADD_16(p, sc->sc_ac_cookie_len); + MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); + p += sc->sc_ac_cookie_len; + } + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof sc); + + return pppoe_output(sc, pb); +} + +/* send a PADT packet */ +static err_t +pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) +{ + struct pbuf *pb; + struct eth_hdr *ethhdr; + err_t res; + u8_t *p; + + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + pbuf_header(pb, (s16_t)sizeof(struct eth_hdr)); + ethhdr = (struct eth_hdr *)pb->payload; + ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); + MEMCPY(ðhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); + MEMCPY(ðhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr)); + + p = (u8_t*)(ethhdr + 1); + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); + + res = outgoing_if->linkoutput(outgoing_if, pb); + + pbuf_free(pb); + + return res; +} + +#ifdef PPPOE_SERVER +static err_t +pppoe_send_pado(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len; + + /* calc length */ + len = 0; + /* include ac_cookie */ + len += 2 + 2 + sizeof(sc); + /* include hunique */ + len += 2 + 2 + sc->sc_hunique_len; + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); + PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); + PPPOE_ADD_16(p, sizeof(sc)); + MEMCPY(p, &sc, sizeof(sc)); + p += sizeof(sc); + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sc->sc_hunique_len); + MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); + return pppoe_output(sc, pb); +} + +static err_t +pppoe_send_pads(struct pppoe_softc *sc) +{ + struct pbuf *pb; + u8_t *p; + size_t len, l1 = 0; /* XXX: gcc */ + + sc->sc_session = mono_time.tv_sec % 0xff + 1; + /* calc length */ + len = 0; + /* include hunique */ + len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ + if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ + l1 = strlen(sc->sc_service_name); + len += l1; + } + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); + if (!pb) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); + PPPOE_ADD_16(p, PPPOE_TAG_SNAME); + if (sc->sc_service_name != NULL) { + PPPOE_ADD_16(p, l1); + MEMCPY(p, sc->sc_service_name, l1); + p += l1; + } else { + PPPOE_ADD_16(p, 0); + } + PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); + PPPOE_ADD_16(p, sc->sc_hunique_len); + MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); + return pppoe_output(sc, pb); +} +#endif + +static err_t +pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) +{ + u8_t *p; + size_t len; + + len = pb->tot_len; + + /* make room for PPPoE header - should not fail */ + if (pbuf_header(pb, (s16_t)(PPPOE_HEADERLEN)) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + + p = (u8_t*)pb->payload; + PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); + + return pppoe_output(sc, pb); +} + +#if 0 /*def PFIL_HOOKS*/ +static int +pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) +{ + struct pppoe_softc *sc; + int s; + + if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { + return 0; + } + + LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + if (sc->sc_ethif != ifp) { + continue; + } + if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { + sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); + PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n", + sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + } + sc->sc_ethif = NULL; + pppoe_clear_softc(sc, "ethernet interface detached"); + } + + return 0; +} +#endif + +#if 0 /* UNUSED */ +static void +pppoe_clear_softc(struct pppoe_softc *sc, const char *message) +{ + LWIP_UNUSED_ARG(message); + + /* stop timer */ + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + sc->sc_state = PPPOE_STATE_INITIAL; + ppp_link_end(sc->pcb); /* notify upper layers - /!\ dangerous /!\ - see pppoe_disc_input() */ +} +#endif /* UNUSED */ +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppol2tp.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppol2tp.c new file mode 100644 index 0000000000..d44471e25f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppol2tp.c @@ -0,0 +1,1131 @@ +/** + * @file + * Network Point to Point Protocol over Layer 2 Tunneling Protocol program file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/* + * L2TP Support status: + * + * Supported: + * - L2TPv2 (PPP over L2TP, a.k.a. UDP tunnels) + * - LAC + * + * Not supported: + * - LNS (require PPP server support) + * - L2TPv3 ethernet pseudowires + * - L2TPv3 VLAN pseudowire + * - L2TPv3 PPP pseudowires + * - L2TPv3 IP encapsulation + * - L2TPv3 IP pseudowire + * - L2TP tunnel switching - http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 + * - Multiple tunnels per UDP socket, as well as multiple sessions per tunnel + * - Hidden AVPs + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/memp.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/snmp.h" + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/lcp.h" +#include "netif/ppp/ipcp.h" +#include "netif/ppp/pppol2tp.h" +#include "netif/ppp/pppcrypt.h" +#include "netif/ppp/magic.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOL2TP_PCB, MEMP_NUM_PPPOL2TP_INTERFACES, sizeof(pppol2tp_pcb), "PPPOL2TP_PCB") + +/* callbacks called from PPP core */ +static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol); +static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx); /* Destroy a L2TP control block */ +static void pppol2tp_connect(ppp_pcb *ppp, void *ctx); /* Be a LAC, connect to a LNS. */ +static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx); /* Disconnect */ + + /* Prototypes for procedures local to this file. */ +static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr); +static void pppol2tp_timeout(void *arg); +static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); +static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp); +static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns); +static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb); +static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb); + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppol2tp_callbacks = { + pppol2tp_connect, +#if PPP_SERVER + NULL, +#endif /* PPP_SERVER */ + pppol2tp_disconnect, + pppol2tp_destroy, + pppol2tp_write, + pppol2tp_netif_output, + NULL, + NULL +}; + + +/* Create a new L2TP session. */ +ppp_pcb *pppol2tp_create(struct netif *pppif, + struct netif *netif, const ip_addr_t *ipaddr, u16_t port, + const u8_t *secret, u8_t secret_len, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { + ppp_pcb *ppp; + pppol2tp_pcb *l2tp; + struct udp_pcb *udp; +#if !PPPOL2TP_AUTH_SUPPORT + LWIP_UNUSED_ARG(secret); + LWIP_UNUSED_ARG(secret_len); +#endif /* !PPPOL2TP_AUTH_SUPPORT */ + + if (ipaddr == NULL) { + goto ipaddr_check_failed; + } + + l2tp = (pppol2tp_pcb *)LWIP_MEMPOOL_ALLOC(PPPOL2TP_PCB); + if (l2tp == NULL) { + goto memp_malloc_l2tp_failed; + } + + udp = udp_new_ip_type(IP_GET_TYPE(ipaddr)); + if (udp == NULL) { + goto udp_new_failed; + } + udp_recv(udp, pppol2tp_input, l2tp); + + ppp = ppp_new(pppif, &pppol2tp_callbacks, l2tp, link_status_cb, ctx_cb); + if (ppp == NULL) { + goto ppp_new_failed; + } + + memset(l2tp, 0, sizeof(pppol2tp_pcb)); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + l2tp->ppp = ppp; + l2tp->udp = udp; + l2tp->netif = netif; + ip_addr_copy(l2tp->remote_ip, *ipaddr); + l2tp->remote_port = port; +#if PPPOL2TP_AUTH_SUPPORT + l2tp->secret = secret; + l2tp->secret_len = secret_len; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return ppp; + +ppp_new_failed: + udp_remove(udp); +udp_new_failed: + LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); +memp_malloc_l2tp_failed: +ipaddr_check_failed: + return NULL; +} + +/* Called by PPP core */ +static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + struct pbuf *ph; /* UDP + L2TP header */ + err_t ret; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); + if(!ph) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + pbuf_header(ph, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); /* hide L2TP header */ + pbuf_cat(ph, p); +#if MIB2_STATS + tot_len = ph->tot_len; +#endif /* MIB2_STATS */ + + ret = pppol2tp_xmit(l2tp, ph); + if (ret != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ret; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, (u16_t)tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Called by PPP core */ +static err_t pppol2tp_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *p, u_short protocol) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + struct pbuf *pb; + u8_t *pl; + err_t err; +#if MIB2_STATS + u16_t tot_len; +#else /* MIB2_STATS */ + LWIP_UNUSED_ARG(ppp); +#endif /* MIB2_STATS */ + + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_TRANSPORT, PPPOL2TP_OUTPUT_DATA_HEADER_LEN + sizeof(protocol), PBUF_RAM); + if(!pb) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.proterr); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + pbuf_header(pb, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); + + pl = (u8_t*)pb->payload; + PUTSHORT(protocol, pl); + + pbuf_chain(pb, p); +#if MIB2_STATS + tot_len = pb->tot_len; +#endif /* MIB2_STATS */ + + if( (err = pppol2tp_xmit(l2tp, pb)) != ERR_OK) { + LINK_STATS_INC(link.err); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return err; + } + + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + return ERR_OK; +} + +/* Destroy a L2TP control block */ +static err_t pppol2tp_destroy(ppp_pcb *ppp, void *ctx) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + + sys_untimeout(pppol2tp_timeout, l2tp); + udp_remove(l2tp->udp); + LWIP_MEMPOOL_FREE(PPPOL2TP_PCB, l2tp); + return ERR_OK; +} + +/* Be a LAC, connect to a LNS. */ +static void pppol2tp_connect(ppp_pcb *ppp, void *ctx) { + err_t err; + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + lcp_options *lcp_wo; + lcp_options *lcp_ao; +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_options *ipcp_wo; + ipcp_options *ipcp_ao; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + l2tp->tunnel_port = l2tp->remote_port; + l2tp->our_ns = 0; + l2tp->peer_nr = 0; + l2tp->peer_ns = 0; + l2tp->source_tunnel_id = 0; + l2tp->remote_tunnel_id = 0; + l2tp->source_session_id = 0; + l2tp->remote_session_id = 0; + /* l2tp->*_retried are cleared when used */ + + lcp_wo = &ppp->lcp_wantoptions; + lcp_wo->mru = PPPOL2TP_DEFMRU; + lcp_wo->neg_asyncmap = 0; + lcp_wo->neg_pcompression = 0; + lcp_wo->neg_accompression = 0; + lcp_wo->passive = 0; + lcp_wo->silent = 0; + + lcp_ao = &ppp->lcp_allowoptions; + lcp_ao->mru = PPPOL2TP_DEFMRU; + lcp_ao->neg_asyncmap = 0; + lcp_ao->neg_pcompression = 0; + lcp_ao->neg_accompression = 0; + +#if PPP_IPV4_SUPPORT && VJ_SUPPORT + ipcp_wo = &ppp->ipcp_wantoptions; + ipcp_wo->neg_vj = 0; + ipcp_wo->old_vj = 0; + + ipcp_ao = &ppp->ipcp_allowoptions; + ipcp_ao->neg_vj = 0; + ipcp_ao->old_vj = 0; +#endif /* PPP_IPV4_SUPPORT && VJ_SUPPORT */ + + /* Listen to a random source port, we need to do that instead of using udp_connect() + * because the L2TP LNS might answer with its own random source port (!= 1701) + */ +#if LWIP_IPV6 + if (IP_IS_V6_VAL(l2tp->udp->local_ip)) { + udp_bind(l2tp->udp, IP6_ADDR_ANY, 0); + } else +#endif /* LWIP_IPV6 */ + udp_bind(l2tp->udp, IP_ADDR_ANY, 0); + +#if PPPOL2TP_AUTH_SUPPORT + /* Generate random vector */ + if (l2tp->secret != NULL) { + magic_random_bytes(l2tp->secret_rv, sizeof(l2tp->secret_rv)); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + do { + l2tp->remote_tunnel_id = magic(); + } while(l2tp->remote_tunnel_id == 0); + /* save state, in case we fail to send SCCRQ */ + l2tp->sccrq_retried = 0; + l2tp->phase = PPPOL2TP_STATE_SCCRQ_SENT; + if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); +} + +/* Disconnect */ +static void pppol2tp_disconnect(ppp_pcb *ppp, void *ctx) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb *)ctx; + + l2tp->our_ns++; + pppol2tp_send_stopccn(l2tp, l2tp->our_ns); + + /* stop any timer, disconnect can be called while initiating is in progress */ + sys_untimeout(pppol2tp_timeout, l2tp); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + ppp_link_end(ppp); /* notify upper layers */ +} + +/* UDP Callback for incoming IPv4 L2TP frames */ +static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; + u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; + u8_t *inp; + LWIP_UNUSED_ARG(pcb); + + /* we can't unbound a UDP pcb, thus we can still receive UDP frames after the link is closed */ + if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { + goto free_and_return; + } + + if (!ip_addr_cmp(&l2tp->remote_ip, addr)) { + goto free_and_return; + } + + /* discard packet if port mismatch, but only if we received a SCCRP */ + if (l2tp->phase > PPPOL2TP_STATE_SCCRQ_SENT && l2tp->tunnel_port != port) { + goto free_and_return; + } + + /* printf("-----------\nL2TP INPUT, %d\n", p->len); */ + + /* L2TP header */ + if (p->len < sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id) ) { + goto packet_too_short; + } + + inp = (u8_t*)p->payload; + GETSHORT(hflags, inp); + + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { + /* check mandatory flags for a control packet */ + if ( (hflags & PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY) != PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for control packet not set\n")); + goto free_and_return; + } + /* check forbidden flags for a control packet */ + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: forbidden header flags for control packet found\n")); + goto free_and_return; + } + } else { + /* check mandatory flags for a data packet */ + if ( (hflags & PPPOL2TP_HEADERFLAG_DATA_MANDATORY) != PPPOL2TP_HEADERFLAG_DATA_MANDATORY) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for data packet not set\n")); + goto free_and_return; + } + } + + /* Expected header size */ + hlen = sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id); + if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { + hlen += sizeof(len); + } + if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { + hlen += sizeof(ns) + sizeof(nr); + } + if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { + hlen += sizeof(offset); + } + if (p->len < hlen) { + goto packet_too_short; + } + + if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { + GETSHORT(len, inp); + if (p->len < len || len < hlen) { + goto packet_too_short; + } + } + GETSHORT(tunnel_id, inp); + GETSHORT(session_id, inp); + if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { + GETSHORT(ns, inp); + GETSHORT(nr, inp); + } + if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { + GETSHORT(offset, inp) + if (offset > 4096) { /* don't be fooled with large offset which might overflow hlen */ + PPPDEBUG(LOG_DEBUG, ("pppol2tp: strange packet received, offset=%d\n", offset)); + goto free_and_return; + } + hlen += offset; + if (p->len < hlen) { + goto packet_too_short; + } + INCPTR(offset, inp); + } + + /* printf("HLEN = %d\n", hlen); */ + + /* skip L2TP header */ + if (pbuf_header(p, -(s16_t)hlen) != 0) { + goto free_and_return; + } + + /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ + PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", + len, tunnel_id, session_id, ns, nr)); + + /* Control packet */ + if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { + pppol2tp_dispatch_control_packet(l2tp, port, p, ns, nr); + goto free_and_return; + } + + /* Data packet */ + if(l2tp->phase != PPPOL2TP_STATE_DATA) { + goto free_and_return; + } + if(tunnel_id != l2tp->remote_tunnel_id) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: tunnel ID mismatch, assigned=%d, received=%d\n", l2tp->remote_tunnel_id, tunnel_id)); + goto free_and_return; + } + if(session_id != l2tp->remote_session_id) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: session ID mismatch, assigned=%d, received=%d\n", l2tp->remote_session_id, session_id)); + goto free_and_return; + } + /* + * skip address & flags if necessary + * + * RFC 2661 does not specify whether the PPP frame in the L2TP payload should + * have a HDLC header or not. We handle both cases for compatibility. + */ + if (p->len >= 2) { + GETSHORT(hflags, inp); + if (hflags == 0xff03) { + pbuf_header(p, -(s16_t)2); + } + } + /* Dispatch the packet thereby consuming it. */ + ppp_input(l2tp->ppp, p); + return; + +packet_too_short: + PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); +free_and_return: + pbuf_free(p); +} + +/* L2TP Control packet entry point */ +static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, struct pbuf *p, u16_t ns, u16_t nr) { + u8_t *inp; + u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; + err_t err; +#if PPPOL2TP_AUTH_SUPPORT + lwip_md5_context md5_ctx; + u8_t md5_hash[16]; + u8_t challenge_id = 0; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + l2tp->peer_nr = nr; + l2tp->peer_ns = ns; + /* printf("L2TP CTRL INPUT, ns=%d, nr=%d, len=%d\n", ns, nr, p->len); */ + + /* Handle the special case of the ICCN acknowledge */ + if (l2tp->phase == PPPOL2TP_STATE_ICCN_SENT && l2tp->peer_nr > l2tp->our_ns) { + l2tp->phase = PPPOL2TP_STATE_DATA; + } + + /* ZLB packets */ + if (p->tot_len == 0) { + return; + } + + p = ppp_singlebuf(p); + inp = (u8_t*)p->payload; + /* Decode AVPs */ + while (p->len > 0) { + if (p->len < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype) ) { + goto packet_too_short; + } + GETSHORT(avpflags, inp); + avplen = avpflags & PPPOL2TP_AVPHEADERFLAG_LENGTHMASK; + /* printf("AVPLEN = %d\n", avplen); */ + if (p->len < avplen || avplen < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) { + goto packet_too_short; + } + GETSHORT(vendorid, inp); + GETSHORT(attributetype, inp); + avplen -= sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype); + + /* Message type must be the first AVP */ + if (messagetype == 0) { + if (attributetype != 0 || vendorid != 0 || avplen != sizeof(messagetype) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: message type must be the first AVP\n")); + return; + } + GETSHORT(messagetype, inp); + /* printf("Message type = %d\n", messagetype); */ + switch(messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + /* Only accept SCCRP packet if we sent a SCCRQ */ + if (l2tp->phase != PPPOL2TP_STATE_SCCRQ_SENT) { + goto send_zlb; + } + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + /* Only accept ICRP packet if we sent a IRCQ */ + if (l2tp->phase != PPPOL2TP_STATE_ICRQ_SENT) { + goto send_zlb; + } + break; + /* Stop Control Connection Notification */ + case PPPOL2TP_MESSAGETYPE_STOPCCN: + pppol2tp_send_zlb(l2tp, l2tp->our_ns); /* Ack the StopCCN before we switch to down state */ + if (l2tp->phase < PPPOL2TP_STATE_DATA) { + pppol2tp_abort_connect(l2tp); + } else if (l2tp->phase == PPPOL2TP_STATE_DATA) { + /* Don't disconnect here, we let the LCP Echo/Reply find the fact + * that PPP session is down. Asking the PPP stack to end the session + * require strict checking about the PPP phase to prevent endless + * disconnection loops. + */ + } + return; + default: + break; + } + goto nextavp; + } + + /* Skip proprietary L2TP extensions */ + if (vendorid != 0) { + goto skipavp; + } + + switch (messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + switch (attributetype) { + case PPPOL2TP_AVPTYPE_TUNNELID: + if (avplen != sizeof(l2tp->source_tunnel_id) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign tunnel ID length check failed\n")); + return; + } + GETSHORT(l2tp->source_tunnel_id, inp); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned tunnel ID %"U16_F"\n", l2tp->source_tunnel_id)); + goto nextavp; +#if PPPOL2TP_AUTH_SUPPORT + case PPPOL2TP_AVPTYPE_CHALLENGE: + if (avplen == 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Challenge length check failed\n")); + return; + } + if (l2tp->secret == NULL) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge from peer and no secret key available\n")); + pppol2tp_abort_connect(l2tp); + return; + } + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + challenge_id = PPPOL2TP_MESSAGETYPE_SCCCN; + lwip_md5_update(&md5_ctx, &challenge_id, 1); + lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); + lwip_md5_update(&md5_ctx, inp, avplen); + lwip_md5_finish(&md5_ctx, l2tp->challenge_hash); + lwip_md5_free(&md5_ctx); + l2tp->send_challenge = 1; + goto skipavp; + case PPPOL2TP_AVPTYPE_CHALLENGERESPONSE: + if (avplen != PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Challenge Response length check failed\n")); + return; + } + /* Generate hash of ID, secret, challenge */ + lwip_md5_init(&md5_ctx); + lwip_md5_starts(&md5_ctx); + challenge_id = PPPOL2TP_MESSAGETYPE_SCCRP; + lwip_md5_update(&md5_ctx, &challenge_id, 1); + lwip_md5_update(&md5_ctx, l2tp->secret, l2tp->secret_len); + lwip_md5_update(&md5_ctx, l2tp->secret_rv, sizeof(l2tp->secret_rv)); + lwip_md5_finish(&md5_ctx, md5_hash); + lwip_md5_free(&md5_ctx); + if ( memcmp(inp, md5_hash, sizeof(md5_hash)) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge response from peer and secret key do not match\n")); + pppol2tp_abort_connect(l2tp); + return; + } + goto skipavp; +#endif /* PPPOL2TP_AUTH_SUPPORT */ + default: + break; + } + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + switch (attributetype) { + case PPPOL2TP_AVPTYPE_SESSIONID: + if (avplen != sizeof(l2tp->source_session_id) ) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign session ID length check failed\n")); + return; + } + GETSHORT(l2tp->source_session_id, inp); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned session ID %"U16_F"\n", l2tp->source_session_id)); + goto nextavp; + default: + break; + } + break; + default: + break; + } + +skipavp: + INCPTR(avplen, inp); +nextavp: + /* printf("AVP Found, vendor=%d, attribute=%d, len=%d\n", vendorid, attributetype, avplen); */ + /* next AVP */ + if (pbuf_header(p, -(s16_t)(avplen + sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) ) != 0) { + return; + } + } + + switch(messagetype) { + /* Start Control Connection Reply */ + case PPPOL2TP_MESSAGETYPE_SCCRP: + do { + l2tp->remote_session_id = magic(); + } while(l2tp->remote_session_id == 0); + l2tp->tunnel_port = port; /* LNS server might have chosen its own local port */ + l2tp->icrq_retried = 0; + l2tp->phase = PPPOL2TP_STATE_ICRQ_SENT; + l2tp->our_ns++; + if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); + } + l2tp->our_ns++; + if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); + } + sys_untimeout(pppol2tp_timeout, l2tp); + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + /* Incoming Call Reply */ + case PPPOL2TP_MESSAGETYPE_ICRP: + l2tp->iccn_retried = 0; + l2tp->phase = PPPOL2TP_STATE_ICCN_SENT; + l2tp->our_ns++; + ppp_start(l2tp->ppp); /* notify upper layers */ + if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); + } + sys_untimeout(pppol2tp_timeout, l2tp); + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + /* Unhandled packet, send ZLB ACK */ + default: + goto send_zlb; + } + return; + +send_zlb: + pppol2tp_send_zlb(l2tp, l2tp->our_ns); + return; +packet_too_short: + PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); +} + +/* L2TP Timeout handler */ +static void pppol2tp_timeout(void *arg) { + pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; + err_t err; + u32_t retry_wait; + + PPPDEBUG(LOG_DEBUG, ("pppol2tp: timeout\n")); + + switch (l2tp->phase) { + case PPPOL2TP_STATE_SCCRQ_SENT: + /* backoff wait */ + if (l2tp->sccrq_retried < 0xff) { + l2tp->sccrq_retried++; + } + if (!l2tp->ppp->settings.persist && l2tp->sccrq_retried >= PPPOL2TP_MAXSCCRQ) { + pppol2tp_abort_connect(l2tp); + return; + } + retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); + PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); + if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { + l2tp->sccrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); + } + sys_timeout(retry_wait, pppol2tp_timeout, l2tp); + break; + + case PPPOL2TP_STATE_ICRQ_SENT: + l2tp->icrq_retried++; + if (l2tp->icrq_retried >= PPPOL2TP_MAXICRQ) { + pppol2tp_abort_connect(l2tp); + return; + } + PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); + if (l2tp->peer_nr <= l2tp->our_ns -1) { /* the SCCCN was not acknowledged */ + if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { + l2tp->icrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + } + } + if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { + l2tp->icrq_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + + case PPPOL2TP_STATE_ICCN_SENT: + l2tp->iccn_retried++; + if (l2tp->iccn_retried >= PPPOL2TP_MAXICCN) { + pppol2tp_abort_connect(l2tp); + return; + } + PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); + if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { + l2tp->iccn_retried--; + PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); + } + sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); + break; + + default: + return; /* all done, work in peace */ + } +} + +/* Connection attempt aborted */ +static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp) { + PPPDEBUG(LOG_DEBUG, ("pppol2tp: could not establish connection\n")); + l2tp->phase = PPPOL2TP_STATE_INITIAL; + ppp_link_failed(l2tp->ppp); /* notify upper layers */ +} + +/* Initiate a new tunnel */ +static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +8 +10 +10 +6+sizeof(PPPOL2TP_HOSTNAME)-1 +6+sizeof(PPPOL2TP_VENDORNAME)-1 +8 +8; +#if PPPOL2TP_AUTH_SUPPORT + if (l2tp->secret != NULL) { + len += 6 + sizeof(l2tp->secret_rv); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(0, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(0, p); /* NS Sequence number - to peer */ + PUTSHORT(0, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCRQ, p); /* Attribute value: Message type: SCCRQ */ + + /* AVP - L2TP Version */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_VERSION, p); /* Attribute type: Version */ + PUTSHORT(PPPOL2TP_VERSION, p); /* Attribute value: L2TP Version */ + + /* AVP - Framing capabilities */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES, p); /* Attribute type: Framing capabilities */ + PUTLONG(PPPOL2TP_FRAMINGCAPABILITIES, p); /* Attribute value: Framing capabilities */ + + /* AVP - Bearer capabilities */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_BEARERCAPABILITIES, p); /* Attribute type: Bearer capabilities */ + PUTLONG(PPPOL2TP_BEARERCAPABILITIES, p); /* Attribute value: Bearer capabilities */ + + /* AVP - Host name */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6+sizeof(PPPOL2TP_HOSTNAME)-1, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_HOSTNAME, p); /* Attribute type: Hostname */ + MEMCPY(p, PPPOL2TP_HOSTNAME, sizeof(PPPOL2TP_HOSTNAME)-1); /* Attribute value: Hostname */ + INCPTR(sizeof(PPPOL2TP_HOSTNAME)-1, p); + + /* AVP - Vendor name */ + PUTSHORT(6+sizeof(PPPOL2TP_VENDORNAME)-1, p); /* len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_VENDORNAME, p); /* Attribute type: Vendor name */ + MEMCPY(p, PPPOL2TP_VENDORNAME, sizeof(PPPOL2TP_VENDORNAME)-1); /* Attribute value: Vendor name */ + INCPTR(sizeof(PPPOL2TP_VENDORNAME)-1, p); + + /* AVP - Assign tunnel ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ + PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ + + /* AVP - Receive window size */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE, p); /* Attribute type: Receive window size */ + PUTSHORT(PPPOL2TP_RECEIVEWINDOWSIZE, p); /* Attribute value: Receive window size */ + +#if PPPOL2TP_AUTH_SUPPORT + /* AVP - Challenge */ + if (l2tp->secret != NULL) { + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->secret_rv), p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGE, p); /* Attribute type: Challenge */ + MEMCPY(p, l2tp->secret_rv, sizeof(l2tp->secret_rv)); /* Attribute value: Random vector */ + INCPTR(sizeof(l2tp->secret_rv), p); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Complete tunnel establishment */ +static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8; +#if PPPOL2TP_AUTH_SUPPORT + if (l2tp->send_challenge) { + len += 6 + sizeof(l2tp->challenge_hash); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCCN, p); /* Attribute value: Message type: SCCCN */ + +#if PPPOL2TP_AUTH_SUPPORT + /* AVP - Challenge response */ + if (l2tp->send_challenge) { + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->challenge_hash), p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGERESPONSE, p); /* Attribute type: Challenge response */ + MEMCPY(p, l2tp->challenge_hash, sizeof(l2tp->challenge_hash)); /* Attribute value: Computed challenge */ + INCPTR(sizeof(l2tp->challenge_hash), p); + } +#endif /* PPPOL2TP_AUTH_SUPPORT */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Initiate a new session */ +static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + u32_t serialnumber; + + /* calculate UDP packet length */ + len = 12 +8 +8 +10; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_ICRQ, p); /* Attribute value: Message type: ICRQ */ + + /* AVP - Assign session ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_SESSIONID, p); /* Attribute type: Session ID */ + PUTSHORT(l2tp->remote_session_id, p); /* Attribute value: Session ID */ + + /* AVP - Call Serial Number */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_CALLSERIALNUMBER, p); /* Attribute type: Serial number */ + serialnumber = magic(); + PUTLONG(serialnumber, p); /* Attribute value: Serial number */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Complete tunnel establishment */ +static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +10 +10; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(l2tp->source_session_id, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_ICCN, p); /* Attribute value: Message type: ICCN */ + + /* AVP - Framing type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGTYPE, p); /* Attribute type: Framing type */ + PUTLONG(PPPOL2TP_FRAMINGTYPE, p); /* Attribute value: Framing type */ + + /* AVP - TX Connect speed */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TXCONNECTSPEED, p); /* Attribute type: TX Connect speed */ + PUTLONG(PPPOL2TP_TXCONNECTSPEED, p); /* Attribute value: TX Connect speed */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Send a ZLB ACK packet */ +static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ + + return pppol2tp_udp_send(l2tp, pb); +} + +/* Send a StopCCN packet */ +static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns) { + struct pbuf *pb; + u8_t *p; + u16_t len; + + /* calculate UDP packet length */ + len = 12 +8 +8 +8; + + /* allocate a buffer */ + pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pb == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); + + p = (u8_t*)pb->payload; + /* fill in pkt */ + /* L2TP control header */ + PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); + PUTSHORT(len, p); /* Length */ + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(0, p); /* Session Id */ + PUTSHORT(ns, p); /* NS Sequence number - to peer */ + PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ + + /* AVP - Message type */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ + PUTSHORT(PPPOL2TP_MESSAGETYPE_STOPCCN, p); /* Attribute value: Message type: StopCCN */ + + /* AVP - Assign tunnel ID */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ + PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ + + /* AVP - Result code */ + PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ + PUTSHORT(0, p); /* Vendor ID */ + PUTSHORT(PPPOL2TP_AVPTYPE_RESULTCODE, p); /* Attribute type: Result code */ + PUTSHORT(PPPOL2TP_RESULTCODE, p); /* Attribute value: Result code */ + + return pppol2tp_udp_send(l2tp, pb); +} + +static err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { + u8_t *p; + + /* make room for L2TP header - should not fail */ + if (pbuf_header(pb, (s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN) != 0) { + /* bail out */ + PPPDEBUG(LOG_ERR, ("pppol2tp: pppol2tp_pcb: could not allocate room for L2TP header\n")); + LINK_STATS_INC(link.lenerr); + pbuf_free(pb); + return ERR_BUF; + } + + p = (u8_t*)pb->payload; + PUTSHORT(PPPOL2TP_HEADERFLAG_DATA_MANDATORY, p); + PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ + PUTSHORT(l2tp->source_session_id, p); /* Session Id */ + + return pppol2tp_udp_send(l2tp, pb); +} + +static err_t pppol2tp_udp_send(pppol2tp_pcb *l2tp, struct pbuf *pb) { + err_t err; + if (l2tp->netif) { + err = udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port, l2tp->netif); + } else { + err = udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->tunnel_port); + } + pbuf_free(pb); + return err; +} + +#endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppos.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppos.c new file mode 100644 index 0000000000..fb48df4eb8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/pppos.c @@ -0,0 +1,875 @@ +/** + * @file + * Network Point to Point Protocol over Serial file. + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PPPOS_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include + +#include "lwip/arch.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/priv/tcpip_priv.h" +#include "lwip/api.h" +#include "lwip/ip4.h" /* for ip4_input() */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppos.h" +#include "netif/ppp/vj.h" + +/* Memory pool */ +LWIP_MEMPOOL_DECLARE(PPPOS_PCB, MEMP_NUM_PPPOS_INTERFACES, sizeof(pppos_pcb), "PPPOS_PCB") + +/* callbacks called from PPP core */ +static err_t pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p); +static err_t pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol); +static void pppos_connect(ppp_pcb *ppp, void *ctx); +#if PPP_SERVER +static void pppos_listen(ppp_pcb *ppp, void *ctx); +#endif /* PPP_SERVER */ +static void pppos_disconnect(ppp_pcb *ppp, void *ctx); +static err_t pppos_destroy(ppp_pcb *ppp, void *ctx); +static void pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); +static void pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp); + +/* Prototypes for procedures local to this file. */ +#if PPP_INPROC_IRQ_SAFE +static void pppos_input_callback(void *arg); +#endif /* PPP_INPROC_IRQ_SAFE */ +static void pppos_input_free_current_packet(pppos_pcb *pppos); +static void pppos_input_drop(pppos_pcb *pppos); +static err_t pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs); +static err_t pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs); + +/* Callbacks structure for PPP core */ +static const struct link_callbacks pppos_callbacks = { + pppos_connect, +#if PPP_SERVER + pppos_listen, +#endif /* PPP_SERVER */ + pppos_disconnect, + pppos_destroy, + pppos_write, + pppos_netif_output, + pppos_send_config, + pppos_recv_config +}; + +/* PPP's Asynchronous-Control-Character-Map. The mask array is used + * to select the specific bit for a character. */ +#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & 1 << (c & 0x07)) + +#if PPP_FCS_TABLE +/* + * FCS lookup table as calculated by genfcstab. + */ +static const u16_t fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) +#else /* PPP_FCS_TABLE */ +/* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */ +#define PPP_FCS_POLYNOMIAL 0x8408 +static u16_t +ppp_get_fcs(u8_t byte) +{ + unsigned int octet; + int bit; + octet = byte; + for (bit = 8; bit-- > 0; ) { + octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1); + } + return octet & 0xffff; +} +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff)) +#endif /* PPP_FCS_TABLE */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ + +#if PPP_INPROC_IRQ_SAFE +#define PPPOS_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) +#define PPPOS_PROTECT(lev) SYS_ARCH_PROTECT(lev) +#define PPPOS_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) +#else +#define PPPOS_DECL_PROTECT(lev) +#define PPPOS_PROTECT(lev) +#define PPPOS_UNPROTECT(lev) +#endif /* PPP_INPROC_IRQ_SAFE */ + + +/* + * Create a new PPP connection using the given serial I/O device. + * + * Return 0 on success, an error code on failure. + */ +ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb, + ppp_link_status_cb_fn link_status_cb, void *ctx_cb) +{ + pppos_pcb *pppos; + ppp_pcb *ppp; + + pppos = (pppos_pcb *)LWIP_MEMPOOL_ALLOC(PPPOS_PCB); + if (pppos == NULL) { + return NULL; + } + + ppp = ppp_new(pppif, &pppos_callbacks, pppos, link_status_cb, ctx_cb); + if (ppp == NULL) { + LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); + return NULL; + } + + memset(pppos, 0, sizeof(pppos_pcb)); + pppos->ppp = ppp; + pppos->output_cb = output_cb; + return ppp; +} + +/* Called by PPP core */ +static err_t +pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + u8_t *s; + struct pbuf *nb; + u16_t n; + u16_t fcs_out; + err_t err; + LWIP_UNUSED_ARG(ppp); + + /* Grab an output buffer. */ + nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (nb == NULL) { + PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(p); + return ERR_MEM; + } + + /* If the link has been idle, we'll send a fresh flag character to + * flush any noise. */ + err = ERR_OK; + if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + } + + /* Load output buffer. */ + fcs_out = PPP_INITFCS; + s = (u8_t*)p->payload; + n = p->len; + while (n-- > 0) { + err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); + } + + err = pppos_output_last(pppos, err, nb, &fcs_out); + if (err == ERR_OK) { + PPPDEBUG(LOG_INFO, ("pppos_write[%d]: len=%d\n", ppp->netif->num, p->len)); + } else { + PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: output failed len=%d\n", ppp->netif->num, p->len)); + } + pbuf_free(p); + return err; +} + +/* Called by PPP core */ +static err_t +pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + struct pbuf *nb, *p; + u16_t fcs_out; + err_t err; + LWIP_UNUSED_ARG(ppp); + + /* Grab an output buffer. */ + nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); + if (nb == NULL) { + PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + return ERR_MEM; + } + + /* If the link has been idle, we'll send a fresh flag character to + * flush any noise. */ + err = ERR_OK; + if ((sys_now() - pppos->last_xmit) >= PPP_MAXIDLEFLAG) { + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + } + + fcs_out = PPP_INITFCS; + if (!pppos->accomp) { + err = pppos_output_append(pppos, err, nb, PPP_ALLSTATIONS, 1, &fcs_out); + err = pppos_output_append(pppos, err, nb, PPP_UI, 1, &fcs_out); + } + if (!pppos->pcomp || protocol > 0xFF) { + err = pppos_output_append(pppos, err, nb, (protocol >> 8) & 0xFF, 1, &fcs_out); + } + err = pppos_output_append(pppos, err, nb, protocol & 0xFF, 1, &fcs_out); + + /* Load packet. */ + for(p = pb; p; p = p->next) { + u16_t n = p->len; + u8_t *s = (u8_t*)p->payload; + + while (n-- > 0) { + err = pppos_output_append(pppos, err, nb, *s++, 1, &fcs_out); + } + } + + err = pppos_output_last(pppos, err, nb, &fcs_out); + if (err == ERR_OK) { + PPPDEBUG(LOG_INFO, ("pppos_netif_output[%d]: proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); + } else { + PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: output failed proto=0x%"X16_F", len = %d\n", ppp->netif->num, protocol, pb->tot_len)); + } + return err; +} + +static void +pppos_connect(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left over from last session? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + /* reset PPPoS control block to its initial state */ + memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); + + /* + * Default the in and out accm so that escape and flag characters + * are always escaped. + */ + pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ + pppos->out_accm[15] = 0x60; + PPPOS_PROTECT(lev); + pppos->open = 1; + PPPOS_UNPROTECT(lev); + + /* + * Start the connection and handle incoming events (packet or timeout). + */ + PPPDEBUG(LOG_INFO, ("pppos_connect: unit %d: connecting\n", ppp->netif->num)); + ppp_start(ppp); /* notify upper layers */ +} + +#if PPP_SERVER +static void +pppos_listen(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left over from last session? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + /* reset PPPoS control block to its initial state */ + memset(&pppos->last_xmit, 0, sizeof(pppos_pcb) - offsetof(pppos_pcb, last_xmit)); + + /* + * Default the in and out accm so that escape and flag characters + * are always escaped. + */ + pppos->in_accm[15] = 0x60; /* no need to protect since RX is not running */ + pppos->out_accm[15] = 0x60; + PPPOS_PROTECT(lev); + pppos->open = 1; + PPPOS_UNPROTECT(lev); + + /* + * Wait for something to happen. + */ + PPPDEBUG(LOG_INFO, ("pppos_listen: unit %d: listening\n", ppp->netif->num)); + ppp_start(ppp); /* notify upper layers */ +} +#endif /* PPP_SERVER */ + +static void +pppos_disconnect(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + + PPPOS_PROTECT(lev); + pppos->open = 0; + PPPOS_UNPROTECT(lev); + + /* If PPP_INPROC_IRQ_SAFE is used we cannot call + * pppos_input_free_current_packet() here because + * rx IRQ might still call pppos_input(). + */ +#if !PPP_INPROC_IRQ_SAFE + /* input pbuf left ? */ + pppos_input_free_current_packet(pppos); +#endif /* !PPP_INPROC_IRQ_SAFE */ + + ppp_link_end(ppp); /* notify upper layers */ +} + +static err_t +pppos_destroy(ppp_pcb *ppp, void *ctx) +{ + pppos_pcb *pppos = (pppos_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + +#if PPP_INPROC_IRQ_SAFE + /* input pbuf left ? */ + pppos_input_free_current_packet(pppos); +#endif /* PPP_INPROC_IRQ_SAFE */ + + LWIP_MEMPOOL_FREE(PPPOS_PCB, pppos); + return ERR_OK; +} + +#if !NO_SYS && !PPP_INPROC_IRQ_SAFE +/** Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. + * + * @param ppp PPP descriptor index, returned by pppos_create() + * @param s received data + * @param l length of received data + */ +err_t +pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l) +{ + struct pbuf *p; + err_t err; + + p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL); + if (!p) { + return ERR_MEM; + } + pbuf_take(p, s, l); + + err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys); + if (err != ERR_OK) { + pbuf_free(p); + } + return err; +} + +/* called from TCPIP thread */ +err_t pppos_input_sys(struct pbuf *p, struct netif *inp) { + ppp_pcb *ppp = (ppp_pcb*)inp->state; + struct pbuf *n; + + for (n = p; n; n = n->next) { + pppos_input(ppp, (u8_t*)n->payload, n->len); + } + pbuf_free(p); + return ERR_OK; +} +#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */ + +/** PPPoS input helper struct, must be packed since it is stored + * to pbuf->payload, which might be unaligned. */ +#if PPP_INPROC_IRQ_SAFE +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppos_input_header { + PACK_STRUCT_FIELD(ppp_pcb *ppp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#endif /* PPP_INPROC_IRQ_SAFE */ + +/** Pass received raw characters to PPPoS to be decoded. + * + * @param ppp PPP descriptor index, returned by pppos_create() + * @param s received data + * @param l length of received data + */ +void +pppos_input(ppp_pcb *ppp, u8_t *s, int l) +{ + pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb; + struct pbuf *next_pbuf; + u8_t cur_char; + u8_t escaped; + PPPOS_DECL_PROTECT(lev); + + PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l)); + while (l-- > 0) { + cur_char = *s++; + + PPPOS_PROTECT(lev); + /* ppp_input can disconnect the interface, we need to abort to prevent a memory + * leak if there are remaining bytes because pppos_connect and pppos_listen + * functions expect input buffer to be free. Furthermore there are no real + * reason to continue reading bytes if we are disconnected. + */ + if (!pppos->open) { + PPPOS_UNPROTECT(lev); + return; + } + escaped = ESCAPE_P(pppos->in_accm, cur_char); + PPPOS_UNPROTECT(lev); + /* Handle special characters. */ + if (escaped) { + /* Check for escape sequences. */ + /* XXX Note that this does not handle an escaped 0x5d character which + * would appear as an escape character. Since this is an ASCII ']' + * and there is no reason that I know of to escape it, I won't complicate + * the code to handle this case. GLL */ + if (cur_char == PPP_ESCAPE) { + pppos->in_escaped = 1; + /* Check for the flag character. */ + } else if (cur_char == PPP_FLAG) { + /* If this is just an extra flag character, ignore it. */ + if (pppos->in_state <= PDADDRESS) { + /* ignore it */; + /* If we haven't received the packet header, drop what has come in. */ + } else if (pppos->in_state < PDDATA) { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Dropping incomplete packet %d\n", + ppp->netif->num, pppos->in_state)); + LINK_STATS_INC(link.lenerr); + pppos_input_drop(pppos); + /* If the fcs is invalid, drop the packet. */ + } else if (pppos->in_fcs != PPP_GOODFCS) { + PPPDEBUG(LOG_INFO, + ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", + ppp->netif->num, pppos->in_fcs, pppos->in_protocol)); + /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ + LINK_STATS_INC(link.chkerr); + pppos_input_drop(pppos); + /* Otherwise it's a good packet so pass it on. */ + } else { + struct pbuf *inp; + /* Trim off the checksum. */ + if(pppos->in_tail->len > 2) { + pppos->in_tail->len -= 2; + + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + } + } else { + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + } + + pbuf_realloc(pppos->in_head, pppos->in_head->tot_len - 2); + } + + /* Dispatch the packet thereby consuming it. */ + inp = pppos->in_head; + /* Packet consumed, release our references. */ + pppos->in_head = NULL; + pppos->in_tail = NULL; +#if IP_FORWARD || LWIP_IPV6_FORWARD + /* hide the room for Ethernet forwarding header */ + pbuf_header(inp, -(s16_t)(PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN)); +#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ +#if PPP_INPROC_IRQ_SAFE + if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) { + PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num)); + pbuf_free(inp); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); + } +#else /* PPP_INPROC_IRQ_SAFE */ + ppp_input(ppp, inp); +#endif /* PPP_INPROC_IRQ_SAFE */ + } + + /* Prepare for a new packet. */ + pppos->in_fcs = PPP_INITFCS; + pppos->in_state = PDADDRESS; + pppos->in_escaped = 0; + /* Other characters are usually control characters that may have + * been inserted by the physical layer so here we just drop them. */ + } else { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Dropping ACCM char <%d>\n", ppp->netif->num, cur_char)); + } + /* Process other characters. */ + } else { + /* Unencode escaped characters. */ + if (pppos->in_escaped) { + pppos->in_escaped = 0; + cur_char ^= PPP_TRANS; + } + + /* Process character relative to current state. */ + switch(pppos->in_state) { + case PDIDLE: /* Idle state - waiting. */ + /* Drop the character if it's not 0xff + * we would have processed a flag character above. */ + if (cur_char != PPP_ALLSTATIONS) { + break; + } + /* no break */ + /* Fall through */ + + case PDSTART: /* Process start flag. */ + /* Prepare for a new packet. */ + pppos->in_fcs = PPP_INITFCS; + /* no break */ + /* Fall through */ + + case PDADDRESS: /* Process address field. */ + if (cur_char == PPP_ALLSTATIONS) { + pppos->in_state = PDCONTROL; + break; + } + /* no break */ + + /* Else assume compressed address and control fields so + * fall through to get the protocol... */ + case PDCONTROL: /* Process control field. */ + /* If we don't get a valid control code, restart. */ + if (cur_char == PPP_UI) { + pppos->in_state = PDPROTOCOL1; + break; + } + /* no break */ + +#if 0 + else { + PPPDEBUG(LOG_WARNING, + ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char)); + pppos->in_state = PDSTART; + } +#endif + case PDPROTOCOL1: /* Process protocol field 1. */ + /* If the lower bit is set, this is the end of the protocol + * field. */ + if (cur_char & 1) { + pppos->in_protocol = cur_char; + pppos->in_state = PDDATA; + } else { + pppos->in_protocol = (u16_t)cur_char << 8; + pppos->in_state = PDPROTOCOL2; + } + break; + case PDPROTOCOL2: /* Process protocol field 2. */ + pppos->in_protocol |= cur_char; + pppos->in_state = PDDATA; + break; + case PDDATA: /* Process data byte. */ + /* Make space to receive processed data. */ + if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) { + u16_t pbuf_alloc_len; + if (pppos->in_tail != NULL) { + pppos->in_tail->tot_len = pppos->in_tail->len; + if (pppos->in_tail != pppos->in_head) { + pbuf_cat(pppos->in_head, pppos->in_tail); + /* give up the in_tail reference now */ + pppos->in_tail = NULL; + } + } + /* If we haven't started a packet, we need a packet header. */ + pbuf_alloc_len = 0; +#if IP_FORWARD || LWIP_IPV6_FORWARD + /* If IP forwarding is enabled we are reserving PBUF_LINK_ENCAPSULATION_HLEN + * + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header + * space to be forwarded (to Ethernet for example). + */ + if (pppos->in_head == NULL) { + pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN; + } +#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ + next_pbuf = pbuf_alloc(PBUF_RAW, pbuf_alloc_len, PBUF_POOL); + if (next_pbuf == NULL) { + /* No free buffers. Drop the input packet and let the + * higher layers deal with it. Continue processing + * the received pbuf chain in case a new packet starts. */ + PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num)); + LINK_STATS_INC(link.memerr); + pppos_input_drop(pppos); + pppos->in_state = PDSTART; /* Wait for flag sequence. */ + break; + } + if (pppos->in_head == NULL) { + u8_t *payload = ((u8_t*)next_pbuf->payload) + pbuf_alloc_len; +#if PPP_INPROC_IRQ_SAFE + ((struct pppos_input_header*)payload)->ppp = ppp; + payload += sizeof(struct pppos_input_header); + next_pbuf->len += sizeof(struct pppos_input_header); +#endif /* PPP_INPROC_IRQ_SAFE */ + next_pbuf->len += sizeof(pppos->in_protocol); + *(payload++) = pppos->in_protocol >> 8; + *(payload) = pppos->in_protocol & 0xFF; + pppos->in_head = next_pbuf; + } + pppos->in_tail = next_pbuf; + } + /* Load character into buffer. */ + ((u8_t*)pppos->in_tail->payload)[pppos->in_tail->len++] = cur_char; + break; + default: + break; + } + + /* update the frame check sequence number. */ + pppos->in_fcs = PPP_FCS(pppos->in_fcs, cur_char); + } + } /* while (l-- > 0), all bytes processed */ +} + +#if PPP_INPROC_IRQ_SAFE +/* PPPoS input callback using one input pointer + */ +static void pppos_input_callback(void *arg) { + struct pbuf *pb = (struct pbuf*)arg; + ppp_pcb *ppp; + + ppp = ((struct pppos_input_header*)pb->payload)->ppp; + if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) { + LWIP_ASSERT("pbuf_header failed\n", 0); + goto drop; + } + + /* Dispatch the packet thereby consuming it. */ + ppp_input(ppp, pb); + return; + +drop: + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards); + pbuf_free(pb); +} +#endif /* PPP_INPROC_IRQ_SAFE */ + +static void +pppos_send_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) +{ + int i; + pppos_pcb *pppos = (pppos_pcb *)ctx; + LWIP_UNUSED_ARG(ppp); + + pppos->pcomp = pcomp; + pppos->accomp = accomp; + + /* Load the ACCM bits for the 32 control codes. */ + for (i = 0; i < 32/8; i++) { + pppos->out_accm[i] = (u8_t)((accm >> (8 * i)) & 0xFF); + } + + PPPDEBUG(LOG_INFO, ("pppos_send_config[%d]: out_accm=%X %X %X %X\n", + pppos->ppp->netif->num, + pppos->out_accm[0], pppos->out_accm[1], pppos->out_accm[2], pppos->out_accm[3])); +} + +static void +pppos_recv_config(ppp_pcb *ppp, void *ctx, u32_t accm, int pcomp, int accomp) +{ + int i; + pppos_pcb *pppos = (pppos_pcb *)ctx; + PPPOS_DECL_PROTECT(lev); + LWIP_UNUSED_ARG(ppp); + LWIP_UNUSED_ARG(pcomp); + LWIP_UNUSED_ARG(accomp); + + /* Load the ACCM bits for the 32 control codes. */ + PPPOS_PROTECT(lev); + for (i = 0; i < 32 / 8; i++) { + pppos->in_accm[i] = (u8_t)(accm >> (i * 8)); + } + PPPOS_UNPROTECT(lev); + + PPPDEBUG(LOG_INFO, ("pppos_recv_config[%d]: in_accm=%X %X %X %X\n", + pppos->ppp->netif->num, + pppos->in_accm[0], pppos->in_accm[1], pppos->in_accm[2], pppos->in_accm[3])); +} + +/* + * Drop the input packet. + */ +static void +pppos_input_free_current_packet(pppos_pcb *pppos) +{ + if (pppos->in_head != NULL) { + if (pppos->in_tail && (pppos->in_tail != pppos->in_head)) { + pbuf_free(pppos->in_tail); + } + pbuf_free(pppos->in_head); + pppos->in_head = NULL; + } + pppos->in_tail = NULL; +} + +/* + * Drop the input packet and increase error counters. + */ +static void +pppos_input_drop(pppos_pcb *pppos) +{ + if (pppos->in_head != NULL) { +#if 0 + PPPDEBUG(LOG_INFO, ("pppos_input_drop: %d:%.*H\n", pppos->in_head->len, min(60, pppos->in_head->len * 2), pppos->in_head->payload)); +#endif + PPPDEBUG(LOG_INFO, ("pppos_input_drop: pbuf len=%d, addr %p\n", pppos->in_head->len, (void*)pppos->in_head)); + } + pppos_input_free_current_packet(pppos); +#if VJ_SUPPORT + vj_uncompress_err(&pppos->ppp->vj_comp); +#endif /* VJ_SUPPORT */ + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(pppos->ppp->netif, ifindiscards); +} + +/* + * pppos_output_append - append given character to end of given pbuf. + * If out_accm is not 0 and the character needs to be escaped, do so. + * If pbuf is full, send the pbuf and reuse it. + * Return the current pbuf. + */ +static err_t +pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t accm, u16_t *fcs) +{ + if (err != ERR_OK) { + return err; + } + + /* Make sure there is room for the character and an escape code. + * Sure we don't quite fill the buffer if the character doesn't + * get escaped but is one character worth complicating this? */ + if ((PBUF_POOL_BUFSIZE - nb->len) < 2) { + u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb); + if (l != nb->len) { + return ERR_IF; + } + nb->len = 0; + } + + /* Update FCS before checking for special characters. */ + if (fcs) { + *fcs = PPP_FCS(*fcs, c); + } + + /* Copy to output buffer escaping special characters. */ + if (accm && ESCAPE_P(pppos->out_accm, c)) { + *((u8_t*)nb->payload + nb->len++) = PPP_ESCAPE; + *((u8_t*)nb->payload + nb->len++) = c ^ PPP_TRANS; + } else { + *((u8_t*)nb->payload + nb->len++) = c; + } + + return ERR_OK; +} + +static err_t +pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs) +{ + ppp_pcb *ppp = pppos->ppp; + + /* Add FCS and trailing flag. */ + err = pppos_output_append(pppos, err, nb, ~(*fcs) & 0xFF, 1, NULL); + err = pppos_output_append(pppos, err, nb, (~(*fcs) >> 8) & 0xFF, 1, NULL); + err = pppos_output_append(pppos, err, nb, PPP_FLAG, 0, NULL); + + if (err != ERR_OK) { + goto failed; + } + + /* Send remaining buffer if not empty */ + if (nb->len > 0) { + u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb); + if (l != nb->len) { + err = ERR_IF; + goto failed; + } + } + + pppos->last_xmit = sys_now(); + MIB2_STATS_NETIF_ADD(ppp->netif, ifoutoctets, nb->tot_len); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutucastpkts); + LINK_STATS_INC(link.xmit); + pbuf_free(nb); + return ERR_OK; + +failed: + pppos->last_xmit = 0; /* prepend PPP_FLAG to next packet */ + LINK_STATS_INC(link.err); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(ppp->netif, ifoutdiscards); + pbuf_free(nb); + return err; +} + +#endif /* PPP_SUPPORT && PPPOS_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/upap.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/upap.c new file mode 100644 index 0000000000..d00c2d76e5 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/upap.c @@ -0,0 +1,677 @@ +/* + * upap.c - User/Password Authentication Protocol. + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/* + * @todo: + */ + +#if 0 /* UNUSED */ +#include +#include +#endif /* UNUSED */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/upap.h" + +#if PPP_OPTIONS +/* + * Command-line options. + */ +static option_t pap_option_list[] = { + { "hide-password", o_bool, &hide_password, + "Don't output passwords to log", OPT_PRIO | 1 }, + { "show-password", o_bool, &hide_password, + "Show password string in debug log messages", OPT_PRIOSUB | 0 }, + + { "pap-restart", o_int, &upap[0].us_timeouttime, + "Set retransmit timeout for PAP", OPT_PRIO }, + { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, + "Set max number of transmissions for auth-reqs", OPT_PRIO }, + { "pap-timeout", o_int, &upap[0].us_reqtimeout, + "Set time limit for peer PAP authentication", OPT_PRIO }, + + { NULL } +}; +#endif /* PPP_OPTIONS */ + +/* + * Protocol entry points. + */ +static void upap_init(ppp_pcb *pcb); +static void upap_lowerup(ppp_pcb *pcb); +static void upap_lowerdown(ppp_pcb *pcb); +static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l); +static void upap_protrej(ppp_pcb *pcb); +#if PRINTPKT_SUPPORT +static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg); +#endif /* PRINTPKT_SUPPORT */ + +const struct protent pap_protent = { + PPP_PAP, + upap_init, + upap_input, + upap_protrej, + upap_lowerup, + upap_lowerdown, + NULL, + NULL, +#if PRINTPKT_SUPPORT + upap_printpkt, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_DATAINPUT + NULL, +#endif /* PPP_DATAINPUT */ +#if PRINTPKT_SUPPORT + "PAP", + NULL, +#endif /* PRINTPKT_SUPPORT */ +#if PPP_OPTIONS + pap_option_list, + NULL, +#endif /* PPP_OPTIONS */ +#if DEMAND_SUPPORT + NULL, + NULL +#endif /* DEMAND_SUPPORT */ +}; + +static void upap_timeout(void *arg); +#if PPP_SERVER +static void upap_reqtimeout(void *arg); +static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len); +#endif /* PPP_SERVER */ +static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len); +static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len); +static void upap_sauthreq(ppp_pcb *pcb); +#if PPP_SERVER +static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen); +#endif /* PPP_SERVER */ + + +/* + * upap_init - Initialize a UPAP unit. + */ +static void upap_init(ppp_pcb *pcb) { + pcb->upap.us_user = NULL; + pcb->upap.us_userlen = 0; + pcb->upap.us_passwd = NULL; + pcb->upap.us_passwdlen = 0; + pcb->upap.us_clientstate = UPAPCS_INITIAL; +#if PPP_SERVER + pcb->upap.us_serverstate = UPAPSS_INITIAL; +#endif /* PPP_SERVER */ + pcb->upap.us_id = 0; +} + + +/* + * upap_authwithpeer - Authenticate us with our peer (start client). + * + * Set new state and send authenticate's. + */ +void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) { + + if(!user || !password) + return; + + /* Save the username and password we're given */ + pcb->upap.us_user = user; + pcb->upap.us_userlen = LWIP_MIN(strlen(user), 0xff); + pcb->upap.us_passwd = password; + pcb->upap.us_passwdlen = LWIP_MIN(strlen(password), 0xff); + pcb->upap.us_transmits = 0; + + /* Lower layer up yet? */ + if (pcb->upap.us_clientstate == UPAPCS_INITIAL || + pcb->upap.us_clientstate == UPAPCS_PENDING) { + pcb->upap.us_clientstate = UPAPCS_PENDING; + return; + } + + upap_sauthreq(pcb); /* Start protocol */ +} + +#if PPP_SERVER +/* + * upap_authpeer - Authenticate our peer (start server). + * + * Set new state. + */ +void upap_authpeer(ppp_pcb *pcb) { + + /* Lower layer up yet? */ + if (pcb->upap.us_serverstate == UPAPSS_INITIAL || + pcb->upap.us_serverstate == UPAPSS_PENDING) { + pcb->upap.us_serverstate = UPAPSS_PENDING; + return; + } + + pcb->upap.us_serverstate = UPAPSS_LISTEN; + if (pcb->settings.pap_req_timeout > 0) + TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); +} +#endif /* PPP_SERVER */ + +/* + * upap_timeout - Retransmission timer for sending auth-reqs expired. + */ +static void upap_timeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) + return; + + if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) { + /* give up in disgust */ + ppp_error("No response to PAP authenticate-requests"); + pcb->upap.us_clientstate = UPAPCS_BADAUTH; + auth_withpeer_fail(pcb, PPP_PAP); + return; + } + + upap_sauthreq(pcb); /* Send Authenticate-Request */ +} + + +#if PPP_SERVER +/* + * upap_reqtimeout - Give up waiting for the peer to send an auth-req. + */ +static void upap_reqtimeout(void *arg) { + ppp_pcb *pcb = (ppp_pcb*)arg; + + if (pcb->upap.us_serverstate != UPAPSS_LISTEN) + return; /* huh?? */ + + auth_peer_fail(pcb, PPP_PAP); + pcb->upap.us_serverstate = UPAPSS_BADAUTH; +} +#endif /* PPP_SERVER */ + + +/* + * upap_lowerup - The lower layer is up. + * + * Start authenticating if pending. + */ +static void upap_lowerup(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_INITIAL) + pcb->upap.us_clientstate = UPAPCS_CLOSED; + else if (pcb->upap.us_clientstate == UPAPCS_PENDING) { + upap_sauthreq(pcb); /* send an auth-request */ + } + +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_INITIAL) + pcb->upap.us_serverstate = UPAPSS_CLOSED; + else if (pcb->upap.us_serverstate == UPAPSS_PENDING) { + pcb->upap.us_serverstate = UPAPSS_LISTEN; + if (pcb->settings.pap_req_timeout > 0) + TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); + } +#endif /* PPP_SERVER */ +} + + +/* + * upap_lowerdown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void upap_lowerdown(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ + UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */ +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0) + UNTIMEOUT(upap_reqtimeout, pcb); +#endif /* PPP_SERVER */ + + pcb->upap.us_clientstate = UPAPCS_INITIAL; +#if PPP_SERVER + pcb->upap.us_serverstate = UPAPSS_INITIAL; +#endif /* PPP_SERVER */ +} + + +/* + * upap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen. In any case, pretend lower layer went down. + */ +static void upap_protrej(ppp_pcb *pcb) { + + if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) { + ppp_error("PAP authentication failed due to protocol-reject"); + auth_withpeer_fail(pcb, PPP_PAP); + } +#if PPP_SERVER + if (pcb->upap.us_serverstate == UPAPSS_LISTEN) { + ppp_error("PAP authentication of peer failed (protocol-reject)"); + auth_peer_fail(pcb, PPP_PAP); + } +#endif /* PPP_SERVER */ + upap_lowerdown(pcb); +} + + +/* + * upap_input - Input UPAP packet. + */ +static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) { + u_char *inp; + u_char code, id; + int len; + + /* + * Parse header (code, id and length). + * If packet too short, drop it. + */ + inp = inpacket; + if (l < UPAP_HEADERLEN) { + UPAPDEBUG(("pap_input: rcvd short header.")); + return; + } + GETCHAR(code, inp); + GETCHAR(id, inp); + GETSHORT(len, inp); + if (len < UPAP_HEADERLEN) { + UPAPDEBUG(("pap_input: rcvd illegal length.")); + return; + } + if (len > l) { + UPAPDEBUG(("pap_input: rcvd short packet.")); + return; + } + len -= UPAP_HEADERLEN; + + /* + * Action depends on code. + */ + switch (code) { + case UPAP_AUTHREQ: +#if PPP_SERVER + upap_rauthreq(pcb, inp, id, len); +#endif /* PPP_SERVER */ + break; + + case UPAP_AUTHACK: + upap_rauthack(pcb, inp, id, len); + break; + + case UPAP_AUTHNAK: + upap_rauthnak(pcb, inp, id, len); + break; + + default: /* XXX Need code reject */ + break; + } +} + +#if PPP_SERVER +/* + * upap_rauth - Receive Authenticate. + */ +static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char ruserlen, rpasswdlen; + char *ruser; + char *rpasswd; + char rhostname[256]; + int retcode; + const char *msg; + int msglen; + + if (pcb->upap.us_serverstate < UPAPSS_LISTEN) + return; + + /* + * If we receive a duplicate authenticate-request, we are + * supposed to return the same status as for the first request. + */ + if (pcb->upap.us_serverstate == UPAPSS_OPEN) { + upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ + return; + } + if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) { + upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ + return; + } + + /* + * Parse user/passwd. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + GETCHAR(ruserlen, inp); + len -= sizeof (u_char) + ruserlen + sizeof (u_char); + if (len < 0) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + ruser = (char *) inp; + INCPTR(ruserlen, inp); + GETCHAR(rpasswdlen, inp); + if (len < rpasswdlen) { + UPAPDEBUG(("pap_rauth: rcvd short packet.")); + return; + } + + rpasswd = (char *) inp; + + /* + * Check the username and password given. + */ + retcode = UPAP_AUTHNAK; + if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) { + retcode = UPAP_AUTHACK; + } + BZERO(rpasswd, rpasswdlen); + +#if 0 /* UNUSED */ + /* + * Check remote number authorization. A plugin may have filled in + * the remote number or added an allowed number, and rather than + * return an authenticate failure, is leaving it for us to verify. + */ + if (retcode == UPAP_AUTHACK) { + if (!auth_number()) { + /* We do not want to leak info about the pap result. */ + retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */ + warn("calling number %q is not authorized", remote_number); + } + } + + msglen = strlen(msg); + if (msglen > 255) + msglen = 255; +#endif /* UNUSED */ + + upap_sresp(pcb, retcode, id, msg, msglen); + + /* Null terminate and clean remote name. */ + ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser); + + if (retcode == UPAP_AUTHACK) { + pcb->upap.us_serverstate = UPAPSS_OPEN; + ppp_notice("PAP peer authentication succeeded for %q", rhostname); + auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen); + } else { + pcb->upap.us_serverstate = UPAPSS_BADAUTH; + ppp_warn("PAP peer authentication failed for %q", rhostname); + auth_peer_fail(pcb, PPP_PAP); + } + + if (pcb->settings.pap_req_timeout > 0) + UNTIMEOUT(upap_reqtimeout, pcb); +} +#endif /* PPP_SERVER */ + +/* + * upap_rauthack - Receive Authenticate-Ack. + */ +static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char msglen; + char *msg; + LWIP_UNUSED_ARG(id); + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ + return; + + /* + * Parse message. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauthack: ignoring missing msg-length.")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(("pap_rauthack: rcvd short packet.")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + + pcb->upap.us_clientstate = UPAPCS_OPEN; + + auth_withpeer_success(pcb, PPP_PAP, 0); +} + + +/* + * upap_rauthnak - Receive Authenticate-Nak. + */ +static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) { + u_char msglen; + char *msg; + LWIP_UNUSED_ARG(id); + + if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ + return; + + /* + * Parse message. + */ + if (len < 1) { + UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length.")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(("pap_rauthnak: rcvd short packet.")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } + } + + pcb->upap.us_clientstate = UPAPCS_BADAUTH; + + ppp_error("PAP authentication failed"); + auth_withpeer_fail(pcb, PPP_PAP); +} + + +/* + * upap_sauthreq - Send an Authenticate-Request. + */ +static void upap_sauthreq(ppp_pcb *pcb) { + struct pbuf *p; + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + + pcb->upap.us_userlen + pcb->upap.us_passwdlen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(UPAP_AUTHREQ, outp); + PUTCHAR(++pcb->upap.us_id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(pcb->upap.us_userlen, outp); + MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen); + INCPTR(pcb->upap.us_userlen, outp); + PUTCHAR(pcb->upap.us_passwdlen, outp); + MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen); + + ppp_write(pcb, p); + + TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time); + ++pcb->upap.us_transmits; + pcb->upap.us_clientstate = UPAPCS_AUTHREQ; +} + +#if PPP_SERVER +/* + * upap_sresp - Send a response (ack or nak). + */ +static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) { + struct pbuf *p; + u_char *outp; + int outlen; + + outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; + p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); + if(NULL == p) + return; + if(p->tot_len != p->len) { + pbuf_free(p); + return; + } + + outp = (u_char*)p->payload; + MAKEHEADER(outp, PPP_PAP); + + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + PUTCHAR(msglen, outp); + MEMCPY(outp, msg, msglen); + + ppp_write(pcb, p); +} +#endif /* PPP_SERVER */ + +#if PRINTPKT_SUPPORT +/* + * upap_printpkt - print the contents of a PAP packet. + */ +static const char* const upap_codenames[] = { + "AuthReq", "AuthAck", "AuthNak" +}; + +static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) { + int code, id, len; + int mlen, ulen, wlen; + const u_char *user, *pwd, *msg; + const u_char *pstart; + + if (plen < UPAP_HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < UPAP_HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames)) + printer(arg, " %s", upap_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= UPAP_HEADERLEN; + switch (code) { + case UPAP_AUTHREQ: + if (len < 1) + break; + ulen = p[0]; + if (len < ulen + 2) + break; + wlen = p[ulen + 1]; + if (len < ulen + wlen + 2) + break; + user = (const u_char *) (p + 1); + pwd = (const u_char *) (p + ulen + 2); + p += ulen + wlen + 2; + len -= ulen + wlen + 2; + printer(arg, " user="); + ppp_print_string(user, ulen, printer, arg); + printer(arg, " password="); +/* FIXME: require ppp_pcb struct as printpkt() argument */ +#if 0 + if (!pcb->settings.hide_password) +#endif + ppp_print_string(pwd, wlen, printer, arg); +#if 0 + else + printer(arg, ""); +#endif + break; + case UPAP_AUTHACK: + case UPAP_AUTHNAK: + if (len < 1) + break; + mlen = p[0]; + if (len < mlen + 1) + break; + msg = (const u_char *) (p + 1); + p += mlen + 1; + len -= mlen + 1; + printer(arg, " "); + ppp_print_string(msg, mlen, printer, arg); + break; + default: + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; +} +#endif /* PRINTPKT_SUPPORT */ + +#endif /* PPP_SUPPORT && PAP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/utils.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/utils.c new file mode 100644 index 0000000000..008c63375a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/utils.c @@ -0,0 +1,959 @@ +/* + * utils.c - various utility functions used in pppd. + * + * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 3. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if 0 /* UNUSED */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SVR4 +#include +#endif +#endif /* UNUSED */ + +#include /* isdigit() */ + +#include "netif/ppp/ppp_impl.h" + +#include "netif/ppp/fsm.h" +#include "netif/ppp/lcp.h" + +#if defined(SUNOS4) +extern char *strerror(); +#endif + +static void ppp_logit(int level, const char *fmt, va_list args); +static void ppp_log_write(int level, char *buf); +#if PRINTPKT_SUPPORT +static void ppp_vslp_printer(void *arg, const char *fmt, ...); +static void ppp_format_packet(const u_char *p, int len, + void (*printer) (void *, const char *, ...), void *arg); + +struct buffer_info { + char *ptr; + int len; +}; +#endif /* PRINTPKT_SUPPORT */ + +/* + * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +size_t ppp_strlcpy(char *dest, const char *src, size_t len) { + size_t ret = strlen(src); + + if (len != 0) { + if (ret < len) + strcpy(dest, src); + else { + strncpy(dest, src, len - 1); + dest[len-1] = 0; + } + } + return ret; +} + +/* + * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +size_t ppp_strlcat(char *dest, const char *src, size_t len) { + size_t dlen = strlen(dest); + + return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0)); +} + + +/* + * ppp_slprintf - format a message into a buffer. Like sprintf except we + * also specify the length of the output buffer, and we handle + * %m (error message), %v (visible string), + * %q (quoted string), %t (current time) and %I (IP address) formats. + * Doesn't do floating-point formats. + * Returns the number of chars put into buf. + */ +int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) { + va_list args; + int n; + + va_start(args, fmt); + n = ppp_vslprintf(buf, buflen, fmt, args); + va_end(args); + return n; +} + +/* + * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args. + */ +#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) + +int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) { + int c, i, n; + int width, prec, fillch; + int base, len, neg, quoted; + unsigned long val = 0; + const char *f; + char *str, *buf0; + const unsigned char *p; + char num[32]; +#if 0 /* need port */ + time_t t; +#endif /* need port */ + u32_t ip; + static char hexchars[] = "0123456789abcdef"; +#if PRINTPKT_SUPPORT + struct buffer_info bufinfo; +#endif /* PRINTPKT_SUPPORT */ + + buf0 = buf; + --buflen; + while (buflen > 0) { + for (f = fmt; *f != '%' && *f != 0; ++f) + ; + if (f > fmt) { + len = f - fmt; + if (len > buflen) + len = buflen; + memcpy(buf, fmt, len); + buf += len; + buflen -= len; + fmt = f; + } + if (*fmt == 0) + break; + c = *++fmt; + width = 0; + prec = -1; + fillch = ' '; + if (c == '0') { + fillch = '0'; + c = *++fmt; + } + if (c == '*') { + width = va_arg(args, int); + c = *++fmt; + } else { + while (isdigit(c)) { + width = width * 10 + c - '0'; + c = *++fmt; + } + } + if (c == '.') { + c = *++fmt; + if (c == '*') { + prec = va_arg(args, int); + c = *++fmt; + } else { + prec = 0; + while (isdigit(c)) { + prec = prec * 10 + c - '0'; + c = *++fmt; + } + } + } + str = 0; + base = 0; + neg = 0; + ++fmt; + switch (c) { + case 'l': + c = *fmt++; + switch (c) { + case 'd': + val = va_arg(args, long); + if ((long)val < 0) { + neg = 1; + val = (unsigned long)-(long)val; + } + base = 10; + break; + case 'u': + val = va_arg(args, unsigned long); + base = 10; + break; + default: + OUTCHAR('%'); + OUTCHAR('l'); + --fmt; /* so %lz outputs %lz etc. */ + continue; + } + break; + case 'd': + i = va_arg(args, int); + if (i < 0) { + neg = 1; + val = -i; + } else + val = i; + base = 10; + break; + case 'u': + val = va_arg(args, unsigned int); + base = 10; + break; + case 'o': + val = va_arg(args, unsigned int); + base = 8; + break; + case 'x': + case 'X': + val = va_arg(args, unsigned int); + base = 16; + break; +#if 0 /* unused (and wrong on LLP64 systems) */ + case 'p': + val = (unsigned long) va_arg(args, void *); + base = 16; + neg = 2; + break; +#endif /* unused (and wrong on LLP64 systems) */ + case 's': + str = va_arg(args, char *); + break; + case 'c': + num[0] = va_arg(args, int); + num[1] = 0; + str = num; + break; +#if 0 /* do we always have strerror() in embedded ? */ + case 'm': + str = strerror(errno); + break; +#endif /* do we always have strerror() in embedded ? */ + case 'I': + ip = va_arg(args, u32_t); + ip = lwip_ntohl(ip); + ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, + (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + str = num; + break; +#if 0 /* need port */ + case 't': + time(&t); + str = ctime(&t); + str += 4; /* chop off the day name */ + str[15] = 0; /* chop off year and newline */ + break; +#endif /* need port */ + case 'v': /* "visible" string */ + case 'q': /* quoted string */ + quoted = c == 'q'; + p = va_arg(args, unsigned char *); + if (p == NULL) + p = (const unsigned char *)""; + if (fillch == '0' && prec >= 0) { + n = prec; + } else { + n = strlen((const char *)p); + if (prec >= 0 && n > prec) + n = prec; + } + while (n > 0 && buflen > 0) { + c = *p++; + --n; + if (!quoted && c >= 0x80) { + OUTCHAR('M'); + OUTCHAR('-'); + c -= 0x80; + } + if (quoted && (c == '"' || c == '\\')) + OUTCHAR('\\'); + if (c < 0x20 || (0x7f <= c && c < 0xa0)) { + if (quoted) { + OUTCHAR('\\'); + switch (c) { + case '\t': OUTCHAR('t'); break; + case '\n': OUTCHAR('n'); break; + case '\b': OUTCHAR('b'); break; + case '\f': OUTCHAR('f'); break; + default: + OUTCHAR('x'); + OUTCHAR(hexchars[c >> 4]); + OUTCHAR(hexchars[c & 0xf]); + } + } else { + if (c == '\t') + OUTCHAR(c); + else { + OUTCHAR('^'); + OUTCHAR(c ^ 0x40); + } + } + } else + OUTCHAR(c); + } + continue; +#if PRINTPKT_SUPPORT + case 'P': /* print PPP packet */ + bufinfo.ptr = buf; + bufinfo.len = buflen + 1; + p = va_arg(args, unsigned char *); + n = va_arg(args, int); + ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo); + buf = bufinfo.ptr; + buflen = bufinfo.len - 1; + continue; +#endif /* PRINTPKT_SUPPORT */ + case 'B': + p = va_arg(args, unsigned char *); + for (n = prec; n > 0; --n) { + c = *p++; + if (fillch == ' ') + OUTCHAR(' '); + OUTCHAR(hexchars[(c >> 4) & 0xf]); + OUTCHAR(hexchars[c & 0xf]); + } + continue; + default: + *buf++ = '%'; + if (c != '%') + --fmt; /* so %z outputs %z etc. */ + --buflen; + continue; + } + if (base != 0) { + str = num + sizeof(num); + *--str = 0; + while (str > num + neg) { + *--str = hexchars[val % base]; + val = val / base; + if (--prec <= 0 && val == 0) + break; + } + switch (neg) { + case 1: + *--str = '-'; + break; + case 2: + *--str = 'x'; + *--str = '0'; + break; + default: + break; + } + len = num + sizeof(num) - 1 - str; + } else { + len = strlen(str); + if (prec >= 0 && len > prec) + len = prec; + } + if (width > 0) { + if (width > buflen) + width = buflen; + if ((n = width - len) > 0) { + buflen -= n; + for (; n > 0; --n) + *buf++ = fillch; + } + } + if (len > buflen) + len = buflen; + memcpy(buf, str, len); + buf += len; + buflen -= len; + } + *buf = 0; + return buf - buf0; +} + +#if PRINTPKT_SUPPORT +/* + * vslp_printer - used in processing a %P format + */ +static void ppp_vslp_printer(void *arg, const char *fmt, ...) { + int n; + va_list pvar; + struct buffer_info *bi; + + va_start(pvar, fmt); + bi = (struct buffer_info *) arg; + n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar); + va_end(pvar); + + bi->ptr += n; + bi->len -= n; +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * log_packet - format a packet and log it. + */ + +void +log_packet(p, len, prefix, level) + u_char *p; + int len; + char *prefix; + int level; +{ + init_pr_log(prefix, level); + ppp_format_packet(p, len, pr_log, &level); + end_pr_log(); +} +#endif /* UNUSED */ + +#if PRINTPKT_SUPPORT +/* + * ppp_format_packet - make a readable representation of a packet, + * calling `printer(arg, format, ...)' to output it. + */ +static void ppp_format_packet(const u_char *p, int len, + void (*printer) (void *, const char *, ...), void *arg) { + int i, n; + u_short proto; + const struct protent *protp; + + if (len >= 2) { + GETSHORT(proto, p); + len -= 2; + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (proto == protp->protocol) + break; + if (protp != NULL) { + printer(arg, "[%s", protp->name); + n = (*protp->printpkt)(p, len, printer, arg); + printer(arg, "]"); + p += n; + len -= n; + } else { + for (i = 0; (protp = protocols[i]) != NULL; ++i) + if (proto == (protp->protocol & ~0x8000)) + break; + if (protp != 0 && protp->data_name != 0) { + printer(arg, "[%s data]", protp->data_name); + if (len > 8) + printer(arg, "%.8B ...", p); + else + printer(arg, "%.*B", len, p); + len = 0; + } else + printer(arg, "[proto=0x%x]", proto); + } + } + + if (len > 32) + printer(arg, "%.32B ...", p); + else + printer(arg, "%.*B", len, p); +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* UNUSED */ +/* + * init_pr_log, end_pr_log - initialize and finish use of pr_log. + */ + +static char line[256]; /* line to be logged accumulated here */ +static char *linep; /* current pointer within line */ +static int llevel; /* level for logging */ + +void +init_pr_log(prefix, level) + const char *prefix; + int level; +{ + linep = line; + if (prefix != NULL) { + ppp_strlcpy(line, prefix, sizeof(line)); + linep = line + strlen(line); + } + llevel = level; +} + +void +end_pr_log() +{ + if (linep != line) { + *linep = 0; + ppp_log_write(llevel, line); + } +} + +/* + * pr_log - printer routine for outputting to log + */ +void +pr_log (void *arg, const char *fmt, ...) +{ + int l, n; + va_list pvar; + char *p, *eol; + char buf[256]; + + va_start(pvar, fmt); + n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar); + va_end(pvar); + + p = buf; + eol = strchr(buf, '\n'); + if (linep != line) { + l = (eol == NULL)? n: eol - buf; + if (linep + l < line + sizeof(line)) { + if (l > 0) { + memcpy(linep, buf, l); + linep += l; + } + if (eol == NULL) + return; + p = eol + 1; + eol = strchr(p, '\n'); + } + *linep = 0; + ppp_log_write(llevel, line); + linep = line; + } + + while (eol != NULL) { + *eol = 0; + ppp_log_write(llevel, p); + p = eol + 1; + eol = strchr(p, '\n'); + } + + /* assumes sizeof(buf) <= sizeof(line) */ + l = buf + n - p; + if (l > 0) { + memcpy(line, p, n); + linep = line + l; + } +} +#endif /* UNUSED */ + +/* + * ppp_print_string - print a readable representation of a string using + * printer. + */ +void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) { + int c; + + printer(arg, "\""); + for (; len > 0; --len) { + c = *p++; + if (' ' <= c && c <= '~') { + if (c == '\\' || c == '"') + printer(arg, "\\"); + printer(arg, "%c", c); + } else { + switch (c) { + case '\n': + printer(arg, "\\n"); + break; + case '\r': + printer(arg, "\\r"); + break; + case '\t': + printer(arg, "\\t"); + break; + default: + printer(arg, "\\%.3o", (u8_t)c); + /* no break */ + } + } + } + printer(arg, "\""); +} + +/* + * ppp_logit - does the hard work for fatal et al. + */ +static void ppp_logit(int level, const char *fmt, va_list args) { + char buf[1024]; + + ppp_vslprintf(buf, sizeof(buf), fmt, args); + ppp_log_write(level, buf); +} + +static void ppp_log_write(int level, char *buf) { + LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */ + LWIP_UNUSED_ARG(buf); + PPPDEBUG(level, ("%s\n", buf) ); +#if 0 + if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { + int n = strlen(buf); + + if (n > 0 && buf[n-1] == '\n') + --n; + if (write(log_to_fd, buf, n) != n + || write(log_to_fd, "\n", 1) != 1) + log_to_fd = -1; + } +#endif +} + +/* + * ppp_fatal - log an error message and die horribly. + */ +void ppp_fatal(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_ERR, fmt, pvar); + va_end(pvar); + + LWIP_ASSERT("ppp_fatal", 0); /* as promised */ +} + +/* + * ppp_error - log an error message. + */ +void ppp_error(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_ERR, fmt, pvar); + va_end(pvar); +#if 0 /* UNUSED */ + ++error_count; +#endif /* UNUSED */ +} + +/* + * ppp_warn - log a warning message. + */ +void ppp_warn(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_WARNING, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_notice - log a notice-level message. + */ +void ppp_notice(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_NOTICE, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_info - log an informational message. + */ +void ppp_info(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_INFO, fmt, pvar); + va_end(pvar); +} + +/* + * ppp_dbglog - log a debug message. + */ +void ppp_dbglog(const char *fmt, ...) { + va_list pvar; + + va_start(pvar, fmt); + ppp_logit(LOG_DEBUG, fmt, pvar); + va_end(pvar); +} + +#if PRINTPKT_SUPPORT +/* + * ppp_dump_packet - print out a packet in readable form if it is interesting. + * Assumes len >= PPP_HDRLEN. + */ +void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) { + int proto; + + /* + * don't print data packets, i.e. IPv4, IPv6, VJ, and compressed packets. + */ + proto = (p[0] << 8) + p[1]; + if (proto < 0xC000 && (proto & ~0x8000) == proto) + return; + + /* + * don't print valid LCP echo request/reply packets if the link is up. + */ + if (proto == PPP_LCP && pcb->phase == PPP_PHASE_RUNNING && len >= 2 + HEADERLEN) { + unsigned char *lcp = p + 2; + int l = (lcp[2] << 8) + lcp[3]; + + if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP) + && l >= HEADERLEN && l <= len - 2) + return; + } + + ppp_dbglog("%s %P", tag, p, len); +} +#endif /* PRINTPKT_SUPPORT */ + +#if 0 /* Unused */ + +/* + * complete_read - read a full `count' bytes from fd, + * unless end-of-file or an error other than EINTR is encountered. + */ +ssize_t +complete_read(int fd, void *buf, size_t count) +{ + size_t done; + ssize_t nb; + char *ptr = buf; + + for (done = 0; done < count; ) { + nb = read(fd, ptr, count - done); + if (nb < 0) { + if (errno == EINTR) + continue; + return -1; + } + if (nb == 0) + break; + done += nb; + ptr += nb; + } + return done; +} + +/* Procedures for locking the serial device using a lock file. */ +#ifndef LOCK_DIR +#ifdef __linux__ +#define LOCK_DIR "/var/lock" +#else +#ifdef SVR4 +#define LOCK_DIR "/var/spool/locks" +#else +#define LOCK_DIR "/var/spool/lock" +#endif +#endif +#endif /* LOCK_DIR */ + +static char lock_file[MAXPATHLEN]; + +/* + * lock - create a lock file for the named device + */ +int +lock(dev) + char *dev; +{ +#ifdef LOCKLIB + int result; + + result = mklock (dev, (void *) 0); + if (result == 0) { + ppp_strlcpy(lock_file, dev, sizeof(lock_file)); + return 0; + } + + if (result > 0) + ppp_notice("Device %s is locked by pid %d", dev, result); + else + ppp_error("Can't create lock file %s", lock_file); + return -1; + +#else /* LOCKLIB */ + + char lock_buffer[12]; + int fd, pid, n; + +#ifdef SVR4 + struct stat sbuf; + + if (stat(dev, &sbuf) < 0) { + ppp_error("Can't get device number for %s: %m", dev); + return -1; + } + if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { + ppp_error("Can't lock %s: not a character device", dev); + return -1; + } + ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", + LOCK_DIR, major(sbuf.st_dev), + major(sbuf.st_rdev), minor(sbuf.st_rdev)); +#else + char *p; + char lockdev[MAXPATHLEN]; + + if ((p = strstr(dev, "dev/")) != NULL) { + dev = p + 4; + strncpy(lockdev, dev, MAXPATHLEN-1); + lockdev[MAXPATHLEN-1] = 0; + while ((p = strrchr(lockdev, '/')) != NULL) { + *p = '_'; + } + dev = lockdev; + } else + if ((p = strrchr(dev, '/')) != NULL) + dev = p + 1; + + ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev); +#endif + + while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { + if (errno != EEXIST) { + ppp_error("Can't create lock file %s: %m", lock_file); + break; + } + + /* Read the lock file to find out who has the device locked. */ + fd = open(lock_file, O_RDONLY, 0); + if (fd < 0) { + if (errno == ENOENT) /* This is just a timing problem. */ + continue; + ppp_error("Can't open existing lock file %s: %m", lock_file); + break; + } +#ifndef LOCK_BINARY + n = read(fd, lock_buffer, 11); +#else + n = read(fd, &pid, sizeof(pid)); +#endif /* LOCK_BINARY */ + close(fd); + fd = -1; + if (n <= 0) { + ppp_error("Can't read pid from lock file %s", lock_file); + break; + } + + /* See if the process still exists. */ +#ifndef LOCK_BINARY + lock_buffer[n] = 0; + pid = atoi(lock_buffer); +#endif /* LOCK_BINARY */ + if (pid == getpid()) + return 1; /* somebody else locked it for us */ + if (pid == 0 + || (kill(pid, 0) == -1 && errno == ESRCH)) { + if (unlink (lock_file) == 0) { + ppp_notice("Removed stale lock on %s (pid %d)", dev, pid); + continue; + } + ppp_warn("Couldn't remove stale lock on %s", dev); + } else + ppp_notice("Device %s is locked by pid %d", dev, pid); + break; + } + + if (fd < 0) { + lock_file[0] = 0; + return -1; + } + + pid = getpid(); +#ifndef LOCK_BINARY + ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); + write (fd, lock_buffer, 11); +#else + write(fd, &pid, sizeof (pid)); +#endif + close(fd); + return 0; + +#endif +} + +/* + * relock - called to update our lockfile when we are about to detach, + * thus changing our pid (we fork, the child carries on, and the parent dies). + * Note that this is called by the parent, with pid equal to the pid + * of the child. This avoids a potential race which would exist if + * we had the child rewrite the lockfile (the parent might die first, + * and another process could think the lock was stale if it checked + * between when the parent died and the child rewrote the lockfile). + */ +int +relock(pid) + int pid; +{ +#ifdef LOCKLIB + /* XXX is there a way to do this? */ + return -1; +#else /* LOCKLIB */ + + int fd; + char lock_buffer[12]; + + if (lock_file[0] == 0) + return -1; + fd = open(lock_file, O_WRONLY, 0); + if (fd < 0) { + ppp_error("Couldn't reopen lock file %s: %m", lock_file); + lock_file[0] = 0; + return -1; + } + +#ifndef LOCK_BINARY + ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); + write (fd, lock_buffer, 11); +#else + write(fd, &pid, sizeof(pid)); +#endif /* LOCK_BINARY */ + close(fd); + return 0; + +#endif /* LOCKLIB */ +} + +/* + * unlock - remove our lockfile + */ +void +unlock() +{ + if (lock_file[0]) { +#ifdef LOCKLIB + (void) rmlock(lock_file, (void *) 0); +#else + unlink(lock_file); +#endif + lock_file[0] = 0; + } +} + +#endif /* Unused */ + +#endif /* PPP_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/vj.c b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/vj.c new file mode 100644 index 0000000000..168c340055 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/ppp/vj.c @@ -0,0 +1,695 @@ +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * Initial distribution. + * + * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, + * so that the entire packet being decompressed doesn't have + * to be in contiguous memory (just the compressed header). + * + * Modified March 1998 by Guy Lancaster, glanca@gesn.com, + * for a 16 bit processor. + */ + +#include "netif/ppp/ppp_opts.h" +#if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "netif/ppp/ppp_impl.h" +#include "netif/ppp/pppdebug.h" + +#include "netif/ppp/vj.h" + +#include + +#if LINK_STATS +#define INCR(counter) ++comp->stats.counter +#else +#define INCR(counter) +#endif + +void +vj_compress_init(struct vjcompress *comp) +{ + u8_t i; + struct cstate *tstate = comp->tstate; + +#if MAX_SLOTS == 0 + memset((char *)comp, 0, sizeof(*comp)); +#endif + comp->maxSlotIndex = MAX_SLOTS - 1; + comp->compressSlot = 0; /* Disable slot ID compression by default. */ + for (i = MAX_SLOTS - 1; i > 0; --i) { + tstate[i].cs_id = i; + tstate[i].cs_next = &tstate[i - 1]; + } + tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; + tstate[0].cs_id = 0; + comp->last_cs = &tstate[0]; + comp->last_recv = 255; + comp->last_xmit = 255; + comp->flags = VJF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero. ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ + if ((u16_t)(n) >= 256) { \ + *cp++ = 0; \ + cp[1] = (u8_t)(n); \ + cp[0] = (u8_t)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u8_t)(n); \ + } \ +} +#define ENCODEZ(n) { \ + if ((u16_t)(n) >= 256 || (u16_t)(n) == 0) { \ + *cp++ = 0; \ + cp[1] = (u8_t)(n); \ + cp[0] = (u8_t)((n) >> 8); \ + cp += 2; \ + } else { \ + *cp++ = (u8_t)(n); \ + } \ +} + +#define DECODEL(f) { \ + if (*cp == 0) {\ + u32_t tmp_ = lwip_ntohl(f) + ((cp[1] << 8) | cp[2]); \ + (f) = lwip_htonl(tmp_); \ + cp += 3; \ + } else { \ + u32_t tmp_ = lwip_ntohl(f) + (u32_t)*cp++; \ + (f) = lwip_htonl(tmp_); \ + } \ +} + +#define DECODES(f) { \ + if (*cp == 0) {\ + u16_t tmp_ = lwip_ntohs(f) + (((u16_t)cp[1] << 8) | cp[2]); \ + (f) = lwip_htons(tmp_); \ + cp += 3; \ + } else { \ + u16_t tmp_ = lwip_ntohs(f) + (u16_t)*cp++; \ + (f) = lwip_htons(tmp_); \ + } \ +} + +#define DECODEU(f) { \ + if (*cp == 0) {\ + (f) = lwip_htons(((u16_t)cp[1] << 8) | cp[2]); \ + cp += 3; \ + } else { \ + (f) = lwip_htons((u16_t)*cp++); \ + } \ +} + +/* Helper structures for unaligned *u32_t and *u16_t accesses */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct vj_u32_t { + PACK_STRUCT_FIELD(u32_t v); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct vj_u16_t { + PACK_STRUCT_FIELD(u16_t v); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* + * vj_compress_tcp - Attempt to do Van Jacobson header compression on a + * packet. This assumes that nb and comp are not null and that the first + * buffer of the chain contains a valid IP header. + * Return the VJ type code indicating whether or not the packet was + * compressed. + */ +u8_t +vj_compress_tcp(struct vjcompress *comp, struct pbuf **pb) +{ + struct pbuf *np = *pb; + struct ip_hdr *ip = (struct ip_hdr *)np->payload; + struct cstate *cs = comp->last_cs->cs_next; + u16_t ilen = IPH_HL(ip); + u16_t hlen; + struct tcp_hdr *oth; + struct tcp_hdr *th; + u16_t deltaS, deltaA = 0; + u32_t deltaL; + u32_t changes = 0; + u8_t new_seq[16]; + u8_t *cp = new_seq; + + /* + * Check that the packet is IP proto TCP. + */ + if (IPH_PROTO(ip) != IP_PROTO_TCP) { + return (TYPE_IP); + } + + /* + * Bail if this is an IP fragment or if the TCP packet isn't + * `compressible' (i.e., ACK isn't set or some other control bit is + * set). + */ + if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || np->tot_len < 40) { + return (TYPE_IP); + } + th = (struct tcp_hdr *)&((struct vj_u32_t*)ip)[ilen]; + if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { + return (TYPE_IP); + } + + /* Check that the TCP/IP headers are contained in the first buffer. */ + hlen = ilen + TCPH_HDRLEN(th); + hlen <<= 2; + if (np->len < hlen) { + PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); + return (TYPE_IP); + } + + /* TCP stack requires that we don't change the packet payload, therefore we copy + * the whole packet before compression. */ + np = pbuf_alloc(PBUF_RAW, np->tot_len, PBUF_POOL); + if (!np) { + return (TYPE_IP); + } + + if (pbuf_copy(np, *pb) != ERR_OK) { + pbuf_free(np); + return (TYPE_IP); + } + + *pb = np; + ip = (struct ip_hdr *)np->payload; + + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need + * to locate (or create) the connection state. Special case the + * most recently used connection since it's most likely to be used + * again & we don't have to do any reordering if it's used. + */ + INCR(vjs_packets); + if (!ip4_addr_cmp(&ip->src, &cs->cs_ip.src) + || !ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + || (*(struct vj_u32_t*)th).v != (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { + /* + * Wasn't the first -- search for it. + * + * States are kept in a circularly linked list with + * last_cs pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + struct cstate *lcs; + struct cstate *lastcs = comp->last_cs; + + do { + lcs = cs; cs = cs->cs_next; + INCR(vjs_searches); + if (ip4_addr_cmp(&ip->src, &cs->cs_ip.src) + && ip4_addr_cmp(&ip->dest, &cs->cs_ip.dest) + && (*(struct vj_u32_t*)th).v == (((struct vj_u32_t*)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]).v) { + goto found; + } + } while (cs != lastcs); + + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * last_cs to update the lru linkage. + */ + INCR(vjs_misses); + comp->last_cs = lcs; + goto uncompressed; + + found: + /* + * Found it -- move to the front on the connection list. + */ + if (cs == lastcs) { + comp->last_cs = lcs; + } else { + lcs->cs_next = cs->cs_next; + cs->cs_next = lastcs->cs_next; + lastcs->cs_next = cs; + } + } + + oth = (struct tcp_hdr *)&((struct vj_u32_t*)&cs->cs_ip)[ilen]; + deltaS = ilen; + + /* + * Make sure that only what we expect to change changed. The first + * line of the `if' checks the IP protocol version, header length & + * type of service. The 2nd line checks the "Don't fragment" bit. + * The 3rd line checks the time-to-live and protocol (the protocol + * check is unnecessary but costless). The 4th line checks the TCP + * header length. The 5th line checks IP options, if any. The 6th + * line checks TCP options, if any. If any of these things are + * different between the previous & current datagram, we send the + * current datagram `uncompressed'. + */ + if ((((struct vj_u16_t*)ip)[0]).v != (((struct vj_u16_t*)&cs->cs_ip)[0]).v + || (((struct vj_u16_t*)ip)[3]).v != (((struct vj_u16_t*)&cs->cs_ip)[3]).v + || (((struct vj_u16_t*)ip)[4]).v != (((struct vj_u16_t*)&cs->cs_ip)[4]).v + || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth) + || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) + || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) { + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if (TCPH_FLAGS(th) & TCP_URG) { + deltaS = lwip_ntohs(th->urgp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->urgp != oth->urgp) { + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + + if ((deltaS = (u16_t)(lwip_ntohs(th->wnd) - lwip_ntohs(oth->wnd))) != 0) { + ENCODE(deltaS); + changes |= NEW_W; + } + + if ((deltaL = lwip_ntohl(th->ackno) - lwip_ntohl(oth->ackno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaA = (u16_t)deltaL; + ENCODE(deltaA); + changes |= NEW_A; + } + + if ((deltaL = lwip_ntohl(th->seqno) - lwip_ntohl(oth->seqno)) != 0) { + if (deltaL > 0xffff) { + goto uncompressed; + } + deltaS = (u16_t)deltaL; + ENCODE(deltaS); + changes |= NEW_S; + } + + switch(changes) { + case 0: + /* + * Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && + lwip_ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { + break; + } + /* no break */ + /* fall through */ + + case SPECIAL_I: + case SPECIAL_D: + /* + * actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + + case NEW_S|NEW_A: + if (deltaS == deltaA && deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == lwip_ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + default: + break; + } + + deltaS = (u16_t)(lwip_ntohs(IPH_ID(ip)) - lwip_ntohs(IPH_ID(&cs->cs_ip))); + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + if (TCPH_FLAGS(th) & TCP_PSH) { + changes |= TCP_PUSH_BIT; + } + /* + * Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = lwip_ntohs(th->chksum); + MEMCPY(&cs->cs_ip, ip, hlen); + + /* + * We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how + * many bytes of the original packet to toss so subtract the two to + * get the new packet size. + */ + deltaS = (u16_t)(cp - new_seq); + if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + if (pbuf_header(np, -(s16_t)hlen)){ + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + } + cp = (u8_t*)np->payload; + *cp++ = (u8_t)(changes | NEW_C); + *cp++ = cs->cs_id; + } else { + hlen -= deltaS + 3; + if (pbuf_header(np, -(s16_t)hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + } + cp = (u8_t*)np->payload; + *cp++ = (u8_t)changes; + } + *cp++ = (u8_t)(deltaA >> 8); + *cp++ = (u8_t)deltaA; + MEMCPY(cp, new_seq, deltaS); + INCR(vjs_compressed); + return (TYPE_COMPRESSED_TCP); + + /* + * Update connection state cs & send uncompressed packet (that is, + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + MEMCPY(&cs->cs_ip, ip, hlen); + IPH_PROTO_SET(ip, cs->cs_id); + comp->last_xmit = cs->cs_id; + return (TYPE_UNCOMPRESSED_TCP); +} + +/* + * Called when we may have missed a packet. + */ +void +vj_uncompress_err(struct vjcompress *comp) +{ + comp->flags |= VJF_TOSS; + INCR(vjs_errorin); +} + +/* + * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. + * Return 0 on success, -1 on failure. + */ +int +vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) +{ + u32_t hlen; + struct cstate *cs; + struct ip_hdr *ip; + + ip = (struct ip_hdr *)nb->payload; + hlen = IPH_HL(ip) << 2; + if (IPH_PROTO(ip) >= MAX_SLOTS + || hlen + sizeof(struct tcp_hdr) > nb->len + || (hlen += TCPH_HDRLEN(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2) + > nb->len + || hlen > MAX_HDR) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", + IPH_PROTO(ip), hlen, nb->len)); + comp->flags |= VJF_TOSS; + INCR(vjs_errorin); + return -1; + } + cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; + comp->flags &=~ VJF_TOSS; + IPH_PROTO_SET(ip, IP_PROTO_TCP); + MEMCPY(&cs->cs_ip, ip, hlen); + cs->cs_hlen = (u16_t)hlen; + INCR(vjs_uncompressedin); + return 0; +} + +/* + * Uncompress a packet of type TYPE_COMPRESSED_TCP. + * The packet is composed of a buffer chain and the first buffer + * must contain an accurate chain length. + * The first buffer must include the entire compressed TCP/IP header. + * This procedure replaces the compressed header with the uncompressed + * header and returns the length of the VJ header. + */ +int +vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) +{ + u8_t *cp; + struct tcp_hdr *th; + struct cstate *cs; + struct vj_u16_t *bp; + struct pbuf *n0 = *nb; + u32_t tmp; + u32_t vjlen, hlen, changes; + + INCR(vjs_compressedin); + cp = (u8_t*)n0->payload; + changes = *cp++; + if (changes & NEW_C) { + /* + * Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + if (*cp >= MAX_SLOTS) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); + goto bad; + } + + comp->flags &=~ VJF_TOSS; + comp->last_recv = *cp++; + } else { + /* + * this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. + */ + if (comp->flags & VJF_TOSS) { + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); + INCR(vjs_tossed); + return (-1); + } + } + cs = &comp->rstate[comp->last_recv]; + hlen = IPH_HL(&cs->cs_ip) << 2; + th = (struct tcp_hdr *)&((u8_t*)&cs->cs_ip)[hlen]; + th->chksum = lwip_htons((*cp << 8) | cp[1]); + cp += 2; + if (changes & TCP_PUSH_BIT) { + TCPH_SET_FLAG(th, TCP_PSH); + } else { + TCPH_UNSET_FLAG(th, TCP_PSH); + } + + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + u32_t i = lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + /* some compilers can't nest inline assembler.. */ + tmp = lwip_ntohl(th->ackno) + i; + th->ackno = lwip_htonl(tmp); + tmp = lwip_ntohl(th->seqno) + i; + th->seqno = lwip_htonl(tmp); + } + break; + + case SPECIAL_D: + /* some compilers can't nest inline assembler.. */ + tmp = lwip_ntohl(th->seqno) + lwip_ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + th->seqno = lwip_htonl(tmp); + break; + + default: + if (changes & NEW_U) { + TCPH_SET_FLAG(th, TCP_URG); + DECODEU(th->urgp); + } else { + TCPH_UNSET_FLAG(th, TCP_URG); + } + if (changes & NEW_W) { + DECODES(th->wnd); + } + if (changes & NEW_A) { + DECODEL(th->ackno); + } + if (changes & NEW_S) { + DECODEL(th->seqno); + } + break; + } + if (changes & NEW_I) { + DECODES(cs->cs_ip._id); + } else { + IPH_ID_SET(&cs->cs_ip, lwip_ntohs(IPH_ID(&cs->cs_ip)) + 1); + IPH_ID_SET(&cs->cs_ip, lwip_htons(IPH_ID(&cs->cs_ip))); + } + + /* + * At this point, cp points to the first byte of data in the + * packet. Fill in the IP total length and update the IP + * header checksum. + */ + vjlen = (u16_t)(cp - (u8_t*)n0->payload); + if (n0->len < vjlen) { + /* + * We must have dropped some characters (crc should detect + * this but the old slip framing won't) + */ + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", + n0->len, vjlen)); + goto bad; + } + +#if BYTE_ORDER == LITTLE_ENDIAN + tmp = n0->tot_len - vjlen + cs->cs_hlen; + IPH_LEN_SET(&cs->cs_ip, lwip_htons((u16_t)tmp)); +#else + IPH_LEN_SET(&cs->cs_ip, lwip_htons(n0->tot_len - vjlen + cs->cs_hlen)); +#endif + + /* recompute the ip header checksum */ + bp = (struct vj_u16_t*) &cs->cs_ip; + IPH_CHKSUM_SET(&cs->cs_ip, 0); + for (tmp = 0; hlen > 0; hlen -= 2) { + tmp += (*bp++).v; + } + tmp = (tmp & 0xffff) + (tmp >> 16); + tmp = (tmp & 0xffff) + (tmp >> 16); + IPH_CHKSUM_SET(&cs->cs_ip, (u16_t)(~tmp)); + + /* Remove the compressed header and prepend the uncompressed header. */ + if (pbuf_header(n0, -(s16_t)vjlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + goto bad; + } + + if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { + struct pbuf *np, *q; + u8_t *bufptr; + +#if IP_FORWARD + /* If IP forwarding is enabled we are using a PBUF_LINK packet type so + * the packet is being allocated with enough header space to be + * forwarded (to Ethernet for example). + */ + np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL); +#else /* IP_FORWARD */ + np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); +#endif /* IP_FORWARD */ + if(!np) { + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); + goto bad; + } + + if (pbuf_header(np, -(s16_t)cs->cs_hlen)) { + /* Can we cope with this failing? Just assert for now */ + LWIP_ASSERT("pbuf_header failed\n", 0); + goto bad; + } + + bufptr = (u8_t*)n0->payload; + for(q = np; q != NULL; q = q->next) { + MEMCPY(q->payload, bufptr, q->len); + bufptr += q->len; + } + + if(n0->next) { + pbuf_chain(np, n0->next); + pbuf_dechain(n0); + } + pbuf_free(n0); + n0 = np; + } + + if (pbuf_header(n0, (s16_t)cs->cs_hlen)) { + struct pbuf *np; + + LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); + np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); + if(!np) { + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); + goto bad; + } + pbuf_cat(np, n0); + n0 = np; + } + LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); + MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); + + *nb = n0; + + return vjlen; + +bad: + comp->flags |= VJF_TOSS; + INCR(vjs_errorin); + return (-1); +} + +#endif /* PPP_SUPPORT && VJ_SUPPORT */ diff --git a/Sming/third-party/lwip2/lwip2-src/src/netif/slipif.c b/Sming/third-party/lwip2/lwip2-src/src/netif/slipif.c new file mode 100644 index 0000000000..6eb83c35a4 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/src/netif/slipif.c @@ -0,0 +1,555 @@ +/** + * @file + * SLIP Interface + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is built upon the file: src/arch/rtxc/netif/sioslip.c + * + * Author: Magnus Ivarsson + * Simon Goldschmidt + */ + + +/** + * @defgroup slipif SLIP netif + * @ingroup addons + * + * This is an arch independent SLIP netif. The specific serial hooks must be + * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send + * + * Usage: This netif can be used in three ways:\n + * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() + * until data is received.\n + * 2) In your main loop, call slipif_poll() to check for new RX bytes, + * completed packets are fed into netif->input().\n + * 3) Call slipif_received_byte[s]() from your serial RX ISR and + * slipif_process_rxqueue() from your main loop. ISR level decodes + * packets and puts completed packets on a queue which is fed into + * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for + * pbuf_alloc to work on ISR level!). + * + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/sys.h" +#include "lwip/sio.h" + +#define SLIP_END 0xC0 /* 0300: start and end of every packet */ +#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ +#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ +#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ + +/** Maximum packet size that is received by this netif */ +#ifndef SLIP_MAX_SIZE +#define SLIP_MAX_SIZE 1500 +#endif + +/** Define this to the interface speed for SNMP + * (sio_fd is the sio_fd_t returned by sio_open). + * The default value of zero means 'unknown'. + */ +#ifndef SLIP_SIO_SPEED +#define SLIP_SIO_SPEED(sio_fd) 0 +#endif + +enum slipif_recv_state { + SLIP_RECV_NORMAL, + SLIP_RECV_ESCAPE +}; + +struct slipif_priv { + sio_fd_t sd; + /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ + struct pbuf *p, *q; + u8_t state; + u16_t i, recved; +#if SLIP_RX_FROM_ISR + struct pbuf *rxpackets; +#endif +}; + +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output(struct netif *netif, struct pbuf *p) +{ + struct slipif_priv *priv; + struct pbuf *q; + u16_t i; + u8_t c; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + LWIP_ASSERT("p != NULL", (p != NULL)); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); + priv = (struct slipif_priv *)netif->state; + + /* Send pbuf out on the serial I/O device. */ + /* Start with packet delimiter. */ + sio_send(SLIP_END, priv->sd); + + for (q = p; q != NULL; q = q->next) { + for (i = 0; i < q->len; i++) { + c = ((u8_t *)q->payload)[i]; + switch (c) { + case SLIP_END: + /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ + sio_send(SLIP_ESC, priv->sd); + sio_send(SLIP_ESC_END, priv->sd); + break; + case SLIP_ESC: + /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ + sio_send(SLIP_ESC, priv->sd); + sio_send(SLIP_ESC_ESC, priv->sd); + break; + default: + /* normal byte - no need for escaping */ + sio_send(c, priv->sd); + break; + } + } + } + /* End with packet delimiter. */ + sio_send(SLIP_END, priv->sd); + return ERR_OK; +} + +#if LWIP_IPV4 +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} +#endif /* LWIP_IPV4 */ + +#if LWIP_IPV6 +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chain packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} +#endif /* LWIP_IPV6 */ + +/** + * Handle the incoming SLIP stream character by character + * + * @param netif the lwip network interface structure for this slipif + * @param c received character (multiple calls to this function will + * return a complete packet, NULL is returned before - used for polling) + * @return The IP packet when SLIP_END is received + */ +static struct pbuf* +slipif_rxbyte(struct netif *netif, u8_t c) +{ + struct slipif_priv *priv; + struct pbuf *t; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + switch (priv->state) { + case SLIP_RECV_NORMAL: + switch (c) { + case SLIP_END: + if (priv->recved > 0) { + /* Received whole packet. */ + /* Trim the pbuf to the size of the received packet. */ + pbuf_realloc(priv->q, priv->recved); + + LINK_STATS_INC(link.recv); + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); + t = priv->q; + priv->p = priv->q = NULL; + priv->i = priv->recved = 0; + return t; + } + return NULL; + case SLIP_ESC: + priv->state = SLIP_RECV_ESCAPE; + return NULL; + default: + break; + } /* end switch (c) */ + break; + case SLIP_RECV_ESCAPE: + /* un-escape END or ESC bytes, leave other bytes + (although that would be a protocol error) */ + switch (c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + default: + break; + } + priv->state = SLIP_RECV_NORMAL; + break; + default: + break; + } /* end switch (priv->state) */ + + /* byte received, packet not yet completely received */ + if (priv->p == NULL) { + /* allocate a new pbuf */ + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); + priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL); + + if (priv->p == NULL) { + LINK_STATS_INC(link.drop); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); + /* don't process any further since we got no pbuf to receive to */ + return NULL; + } + + if (priv->q != NULL) { + /* 'chain' the pbuf to the existing chain */ + pbuf_cat(priv->q, priv->p); + } else { + /* p is the first pbuf in the chain */ + priv->q = priv->p; + } + } + + /* this automatically drops bytes if > SLIP_MAX_SIZE */ + if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { + ((u8_t *)priv->p->payload)[priv->i] = c; + priv->recved++; + priv->i++; + if (priv->i >= priv->p->len) { + /* on to the next pbuf */ + priv->i = 0; + if (priv->p->next != NULL && priv->p->next->len > 0) { + /* p is a chain, on to the next in the chain */ + priv->p = priv->p->next; + } else { + /* p is a single pbuf, set it to NULL so next time a new + * pbuf is allocated */ + priv->p = NULL; + } + } + } + return NULL; +} + +/** Like slipif_rxbyte, but passes completed packets to netif->input + * + * @param netif The lwip network interface structure for this slipif + * @param c received character + */ +static void +slipif_rxbyte_input(struct netif *netif, u8_t c) +{ + struct pbuf *p; + p = slipif_rxbyte(netif, c); + if (p != NULL) { + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } +} + +#if SLIP_USE_RX_THREAD +/** + * The SLIP input thread. + * + * Feed the IP layer with incoming packets + * + * @param nf the lwip network interface structure for this slipif + */ +static void +slipif_loop_thread(void *nf) +{ + u8_t c; + struct netif *netif = (struct netif *)nf; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + + while (1) { + if (sio_read(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); + } + } +} +#endif /* SLIP_USE_RX_THREAD */ + +/** + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + * + * @param netif the lwip network interface structure for this slipif + * @return ERR_OK if serial line could be opened, + * ERR_MEM if no memory could be allocated, + * ERR_IF is serial line couldn't be opened + * + * @note netif->num must contain the number of the serial port to open + * (0 by default). If netif->state is != NULL, it is interpreted as an + * u8_t pointer pointing to the serial port number instead of netif->num. + * + */ +err_t +slipif_init(struct netif *netif) +{ + struct slipif_priv *priv; + u8_t sio_num; + + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); + + /* Allocate private data */ + priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); + if (!priv) { + return ERR_MEM; + } + + netif->name[0] = 's'; + netif->name[1] = 'l'; +#if LWIP_IPV4 + netif->output = slipif_output_v4; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = slipif_output_v6; +#endif /* LWIP_IPV6 */ + netif->mtu = SLIP_MAX_SIZE; + + /* netif->state or netif->num contain the port number */ + if (netif->state != NULL) { + sio_num = *(u8_t*)netif->state; + } else { + sio_num = netif->num; + } + /* Try to open the serial port. */ + priv->sd = sio_open(sio_num); + if (!priv->sd) { + /* Opening the serial port failed. */ + mem_free(priv); + return ERR_IF; + } + + /* Initialize private data */ + priv->p = NULL; + priv->q = NULL; + priv->state = SLIP_RECV_NORMAL; + priv->i = 0; + priv->recved = 0; +#if SLIP_RX_FROM_ISR + priv->rxpackets = NULL; +#endif + + netif->state = priv; + + /* initialize the snmp variables and counters inside the struct netif */ + MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); + +#if SLIP_USE_RX_THREAD + /* Create a thread to poll the serial line. */ + sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, + SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); +#endif /* SLIP_USE_RX_THREAD */ + return ERR_OK; +} + +/** + * Polls the serial device and feeds the IP layer with incoming packets. + * + * @param netif The lwip network interface structure for this slipif + */ +void +slipif_poll(struct netif *netif) +{ + u8_t c; + struct slipif_priv *priv; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + while (sio_tryread(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); + } +} + +#if SLIP_RX_FROM_ISR +/** + * Feeds the IP layer with incoming packets that were receive + * + * @param netif The lwip network interface structure for this slipif + */ +void +slipif_process_rxqueue(struct netif *netif) +{ + struct slipif_priv *priv; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + SYS_ARCH_PROTECT(old_level); + while (priv->rxpackets != NULL) { + struct pbuf *p = priv->rxpackets; +#if SLIP_RX_QUEUE + /* dequeue packet */ + struct pbuf *q = p; + while ((q->len != q->tot_len) && (q->next != NULL)) { + q = q->next; + } + priv->rxpackets = q->next; + q->next = NULL; +#else /* SLIP_RX_QUEUE */ + priv->rxpackets = NULL; +#endif /* SLIP_RX_QUEUE */ + SYS_ARCH_UNPROTECT(old_level); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + SYS_ARCH_PROTECT(old_level); + } +} + +/** Like slipif_rxbyte, but queues completed packets. + * + * @param netif The lwip network interface structure for this slipif + * @param data Received serial byte + */ +static void +slipif_rxbyte_enqueue(struct netif *netif, u8_t data) +{ + struct pbuf *p; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + SYS_ARCH_DECL_PROTECT(old_level); + + p = slipif_rxbyte(netif, data); + if (p != NULL) { + SYS_ARCH_PROTECT(old_level); + if (priv->rxpackets != NULL) { +#if SLIP_RX_QUEUE + /* queue multiple pbufs */ + struct pbuf *q = p; + while (q->next != NULL) { + q = q->next; + } + q->next = p; + } else { +#else /* SLIP_RX_QUEUE */ + pbuf_free(priv->rxpackets); + } + { +#endif /* SLIP_RX_QUEUE */ + priv->rxpackets = p; + } + SYS_ARCH_UNPROTECT(old_level); + } +} + +/** + * Process a received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + */ +void +slipif_received_byte(struct netif *netif, u8_t data) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + slipif_rxbyte_enqueue(netif, data); +} + +/** + * Process multiple received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + * @param len Number of received characters + */ +void +slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) +{ + u8_t i; + u8_t *rxdata = data; + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + for (i = 0; i < len; i++, rxdata++) { + slipif_rxbyte_enqueue(netif, *rxdata); + } +} +#endif /* SLIP_RX_FROM_ISR */ diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/Makefile b/Sming/third-party/lwip2/lwip2-src/test/fuzz/Makefile new file mode 100644 index 0000000000..67ffb1957e --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/fuzz/Makefile @@ -0,0 +1,53 @@ +# +# Copyright (c) 2001, 2002 Swedish Institute of Computer Science. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +# OF SUCH DAMAGE. +# +# This file is part of the lwIP TCP/IP stack. +# +# Author: Adam Dunkels +# + +all compile: lwip_fuzz +.PHONY: all clean + +CC=afl-gcc +LDFLAGS=-lm +CFLAGS=-O0 + +CONTRIBDIR=../../../lwip-contrib +include $(CONTRIBDIR)/ports/unix/Common.mk + +clean: + rm -f *.o $(LWIPLIBCOMMON) lwip_fuzz *.s .depend* *.core core + +depend dep: .depend + +include .depend + +.depend: fuzz.c $(LWIPFILES) $(APPFILES) + $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend + +lwip_fuzz: .depend $(LWIPLIBCOMMON) fuzz.o + $(CC) $(CFLAGS) -o lwip_fuzz fuzz.o $(LWIPLIBCOMMON) $(LDFLAGS) diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/README b/Sming/third-party/lwip2/lwip2-src/test/fuzz/README new file mode 100644 index 0000000000..1d1e3d8deb --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/fuzz/README @@ -0,0 +1,34 @@ + +Fuzzing the lwIP stack (afl-fuzz requires linux/unix or similar) + +This directory contains a small app that reads Ethernet frames from stdin and +processes them. It is used together with the 'american fuzzy lop' tool (found +at http://lcamtuf.coredump.cx/afl/) and the sample inputs to test how +unexpected inputs are handled. The afl tool will read the known inputs, and +try to modify them to exercise as many code paths as possible, by instrumenting +the code and keeping track of which code is executed. + +Just running make will produce the test program. + +Then run afl with: + +afl-fuzz -i inputs/ -o output ./lwip_fuzz + +and it should start working. It will probably complain about CPU scheduler, +set AFL_SKIP_CPUFREQ=1 to ignore it. +If it complains about invalid "/proc/sys/kernel/core_pattern" setting, try +executing "sudo bash -c 'echo core > /proc/sys/kernel/core_pattern'". + +The input is split into different subdirectories since they test different +parts of the code, and since you want to run one instance of afl-fuzz on each +core. + +When afl finds a crash or a hang, the input that caused it will be placed in +the output directory. If you have hexdump and text2pcap tools installed, +running output_to_pcap.sh will create pcap files for each input +file to simplify viewing in wireshark. + +The lwipopts.h file needs to have checksum checking off, otherwise almost every +packet will be discarded because of that. The other options can be tuned to +expose different parts of the code. + diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/config.h b/Sming/third-party/lwip2/lwip2-src/test/fuzz/config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/fuzz.c b/Sming/third-party/lwip2/lwip2-src/test/fuzz/fuzz.c new file mode 100644 index 0000000000..a9157f1385 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/fuzz/fuzz.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#include "lwip/init.h" +#include "lwip/netif.h" +#include "netif/etharp.h" +#if LWIP_IPV6 +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#endif +#include +#include + +/* no-op send function */ +static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(p); + return ERR_OK; +} + +static err_t testif_init(struct netif *netif) +{ + netif->name[0] = 'f'; + netif->name[1] = 'z'; + netif->output = etharp_output; + netif->linkoutput = lwip_tx_func; + netif->mtu = 1500; + netif->hwaddr_len = 6; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; + + netif->hwaddr[0] = 0x00; + netif->hwaddr[1] = 0x23; + netif->hwaddr[2] = 0xC1; + netif->hwaddr[3] = 0xDE; + netif->hwaddr[4] = 0xD0; + netif->hwaddr[5] = 0x0D; + +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; + netif->ip6_autoconfig_enabled = 1; + netif_create_ip6_linklocal_address(netif, 1); + netif->flags |= NETIF_FLAG_MLD6; +#endif + + return ERR_OK; +} + +static void input_pkt(struct netif *netif, const u8_t *data, size_t len) +{ + struct pbuf *p, *q; + err_t err; + + LWIP_ASSERT("pkt too big", len <= 0xFFFF); + p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); + LWIP_ASSERT("alloc failed", p); + for(q = p; q != NULL; q = q->next) { + MEMCPY(q->payload, data, q->len); + data += q->len; + } + err = netif->input(p, netif); + if (err != ERR_OK) { + pbuf_free(p); + } +} + +int main(int argc, char** argv) +{ + struct netif net_test; + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + u8_t pktbuf[2000]; + size_t len; + + lwip_init(); + + IP4_ADDR(&addr, 172, 30, 115, 84); + IP4_ADDR(&netmask, 255, 255, 255, 0); + IP4_ADDR(&gw, 172, 30, 115, 1); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + +#if LWIP_IPV6 + nd6_tmr(); /* tick nd to join multicast groups */ +#endif + + if(argc > 1) { + FILE* f; + const char* filename; + printf("reading input from file... "); + fflush(stdout); + filename = argv[1]; + LWIP_ASSERT("invalid filename", filename != NULL); + f = fopen(filename, "rb"); + LWIP_ASSERT("open failed", f != NULL); + len = fread(pktbuf, 1, sizeof(pktbuf), f); + fclose(f); + printf("testing file: \"%s\"...\r\n", filename); + } else { + len = fread(pktbuf, 1, sizeof(pktbuf), stdin); + } + input_pkt(&net_test, pktbuf, len); + + return 0; +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/arp/arp_req.bin b/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/arp/arp_req.bin new file mode 100644 index 0000000000000000000000000000000000000000..b317334f9e2fbe8cffe7624e453ae4c782fc6de7 GIT binary patch literal 42 rcmezW9|SBI7#OrIIM^5%IT+Yj7#J;dymGZI*2opB0wsU|$O-`fG#Cph literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/icmp/icmp_ping.bin b/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/icmp/icmp_ping.bin new file mode 100644 index 0000000000000000000000000000000000000000..87e1ea795e571f48fd3611079ab8c5a972851db8 GIT binary patch literal 98 zcmZQjK6vi}uLT1GgSG_+gDV3=h@+zeg9GEPjceqJRe?B!gW xCQcB=ARs6tEFvluA!-=t)r`_Z(wL-Y+`C=4gfZ(6Egq+ literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/ipv6/neighbor_solicitation.bin b/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/ipv6/neighbor_solicitation.bin new file mode 100644 index 0000000000000000000000000000000000000000..d2f921c36371c68bd768f0d8e777c309cba5b908 GIT binary patch literal 86 zcmXpu{(tWRuLT1GgSJK6-2@=bpkVd?UjvB2z;OG;&z{&^`VZFo5;&6aLy_bQ3)2aa^qQJh;i1_w49hBb1rXm5m Zrwj~CEUa5tm^ip3+QQF(#2J~H*#Y7q5%>TA literal 0 HcmV?d00001 diff --git a/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/udp/udp_port_5000.bin b/Sming/third-party/lwip2/lwip2-src/test/fuzz/inputs/udp/udp_port_5000.bin new file mode 100644 index 0000000000000000000000000000000000000000..d77e26752b9c9163d7d404502df7b121f10520b5 GIT binary patch literal 50 zcmZQjK6vi}uLT1GgSG_+gDV4rN_v $1/$$.tmp + text2pcap $1/$$.tmp ${i}.pcap + fi +done +for i in `ls $1/hangs/id*` +do + PCAPNAME=`echo $i | grep pcap` + if [ -z "$PCAPNAME" ]; then + hexdump -C $i > $1/$$.tmp + text2pcap $1/$$.tmp ${i}.pcap + fi +done +rm -f $1/$$.tmp + +echo +echo "Created pcap files:" +ls $1/*/*.pcap diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.c b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.c new file mode 100644 index 0000000000..66b4877e3f --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.c @@ -0,0 +1,121 @@ +#include "test_mem.h" + +#include "lwip/mem.h" +#include "lwip/stats.h" + +#if !LWIP_STATS || !MEM_STATS +#error "This tests needs MEM-statistics enabled" +#endif +#if LWIP_DNS +#error "This test needs DNS turned off (as it mallocs on init)" +#endif + +/* Setups/teardown functions */ + +static void +mem_setup(void) +{ +} + +static void +mem_teardown(void) +{ +} + + +/* Test functions */ + +/** Call mem_malloc, mem_free and mem_trim and check stats */ +START_TEST(test_mem_one) +{ +#define SIZE1 16 +#define SIZE1_2 12 +#define SIZE2 16 + void *p1, *p2; + mem_size_t s1, s2; + LWIP_UNUSED_ARG(_i); + + fail_unless(lwip_stats.mem.used == 0); + + p1 = mem_malloc(SIZE1); + fail_unless(p1 != NULL); + fail_unless(lwip_stats.mem.used >= SIZE1); + s1 = lwip_stats.mem.used; + + p2 = mem_malloc(SIZE2); + fail_unless(p2 != NULL); + fail_unless(lwip_stats.mem.used >= SIZE2 + s1); + s2 = lwip_stats.mem.used; + + mem_trim(p1, SIZE1_2); + + mem_free(p2); + fail_unless(lwip_stats.mem.used <= s2 - SIZE2); + + mem_free(p1); + fail_unless(lwip_stats.mem.used == 0); +} +END_TEST + +static void malloc_keep_x(int x, int num, int size, int freestep) +{ + int i; + void* p[16]; + LWIP_ASSERT("invalid size", size >= 0 && size < (mem_size_t)-1); + memset(p, 0, sizeof(p)); + for(i = 0; i < num && i < 16; i++) { + p[i] = mem_malloc((mem_size_t)size); + fail_unless(p[i] != NULL); + } + for(i = 0; i < num && i < 16; i += freestep) { + if (i == x) { + continue; + } + mem_free(p[i]); + p[i] = NULL; + } + for(i = 0; i < num && i < 16; i++) { + if (i == x) { + continue; + } + if (p[i] != NULL) { + mem_free(p[i]); + p[i] = NULL; + } + } + fail_unless(p[x] != NULL); + mem_free(p[x]); +} + +START_TEST(test_mem_random) +{ + const int num = 16; + int x; + int size; + int freestep; + LWIP_UNUSED_ARG(_i); + + fail_unless(lwip_stats.mem.used == 0); + + for (x = 0; x < num; x++) { + for (size = 1; size < 32; size++) { + for (freestep = 1; freestep <= 3; freestep++) { + fail_unless(lwip_stats.mem.used == 0); + malloc_keep_x(x, num, size, freestep); + fail_unless(lwip_stats.mem.used == 0); + } + } + } +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +mem_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_mem_one), + TESTFUNC(test_mem_random) + }; + return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.h b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.h new file mode 100644 index 0000000000..325134c30a --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_mem.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_MEM_H +#define LWIP_HDR_TEST_MEM_H + +#include "../lwip_check.h" + +Suite *mem_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.c b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.c new file mode 100644 index 0000000000..9315c4c635 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.c @@ -0,0 +1,239 @@ +#include "test_pbuf.h" + +#include "lwip/pbuf.h" +#include "lwip/stats.h" + +#if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS +#error "This tests needs MEM- and MEMP-statistics enabled" +#endif +#if LWIP_DNS +#error "This test needs DNS turned off (as it mallocs on init)" +#endif +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE +#error "This test needs TCP OOSEQ queueing and window scaling enabled" +#endif + +/* Setups/teardown functions */ + +static void +pbuf_setup(void) +{ +} + +static void +pbuf_teardown(void) +{ +} + + +#define TESTBUFSIZE_1 65535 +#define TESTBUFSIZE_2 65530 +#define TESTBUFSIZE_3 50050 +static u8_t testbuf_1[TESTBUFSIZE_1]; +static u8_t testbuf_1a[TESTBUFSIZE_1]; +static u8_t testbuf_2[TESTBUFSIZE_2]; +static u8_t testbuf_2a[TESTBUFSIZE_2]; +static u8_t testbuf_3[TESTBUFSIZE_3]; +static u8_t testbuf_3a[TESTBUFSIZE_3]; + +/* Test functions */ + +/** Call pbuf_copy on a pbuf with zero length */ +START_TEST(test_pbuf_copy_zero_pbuf) +{ + struct pbuf *p1, *p2, *p3; + err_t err; + LWIP_UNUSED_ARG(_i); + + fail_unless(lwip_stats.mem.used == 0); + fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); + + p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM); + fail_unless(p1 != NULL); + fail_unless(p1->ref == 1); + + p2 = pbuf_alloc(PBUF_RAW, 2, PBUF_POOL); + fail_unless(p2 != NULL); + fail_unless(p2->ref == 1); + p2->len = p2->tot_len = 0; + + pbuf_cat(p1, p2); + fail_unless(p1->ref == 1); + fail_unless(p2->ref == 1); + + p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL); + err = pbuf_copy(p3, p1); + fail_unless(err == ERR_VAL); + + pbuf_free(p1); + pbuf_free(p3); + fail_unless(lwip_stats.mem.used == 0); + + fail_unless(lwip_stats.mem.used == 0); + fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); +} +END_TEST + +START_TEST(test_pbuf_split_64k_on_small_pbufs) +{ + struct pbuf *p, *rest=NULL; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL); + pbuf_split_64k(p, &rest); + fail_unless(p->tot_len == 1); + pbuf_free(p); +} +END_TEST + +START_TEST(test_pbuf_queueing_bigger_than_64k) +{ + int i; + err_t err; + struct pbuf *p1, *p2, *p3, *rest2=NULL, *rest3=NULL; + LWIP_UNUSED_ARG(_i); + + for(i = 0; i < TESTBUFSIZE_1; i++) { + testbuf_1[i] = (u8_t)rand(); + } + for(i = 0; i < TESTBUFSIZE_2; i++) { + testbuf_2[i] = (u8_t)rand(); + } + for(i = 0; i < TESTBUFSIZE_3; i++) { + testbuf_3[i] = (u8_t)rand(); + } + + p1 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_1, PBUF_POOL); + fail_unless(p1 != NULL); + p2 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_2, PBUF_POOL); + fail_unless(p2 != NULL); + p3 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_3, PBUF_POOL); + fail_unless(p3 != NULL); + err = pbuf_take(p1, testbuf_1, TESTBUFSIZE_1); + fail_unless(err == ERR_OK); + err = pbuf_take(p2, testbuf_2, TESTBUFSIZE_2); + fail_unless(err == ERR_OK); + err = pbuf_take(p3, testbuf_3, TESTBUFSIZE_3); + fail_unless(err == ERR_OK); + + pbuf_cat(p1, p2); + pbuf_cat(p1, p3); + + pbuf_split_64k(p1, &rest2); + fail_unless(p1->tot_len == TESTBUFSIZE_1); + fail_unless(rest2->tot_len == (u16_t)((TESTBUFSIZE_2+TESTBUFSIZE_3) & 0xFFFF)); + pbuf_split_64k(rest2, &rest3); + fail_unless(rest2->tot_len == TESTBUFSIZE_2); + fail_unless(rest3->tot_len == TESTBUFSIZE_3); + + pbuf_copy_partial(p1, testbuf_1a, TESTBUFSIZE_1, 0); + pbuf_copy_partial(rest2, testbuf_2a, TESTBUFSIZE_2, 0); + pbuf_copy_partial(rest3, testbuf_3a, TESTBUFSIZE_3, 0); + for(i = 0; i < TESTBUFSIZE_1; i++) + fail_unless(testbuf_1[i] == testbuf_1a[i]); + for(i = 0; i < TESTBUFSIZE_2; i++) + fail_unless(testbuf_2[i] == testbuf_2a[i]); + for(i = 0; i < TESTBUFSIZE_3; i++) + fail_unless(testbuf_3[i] == testbuf_3a[i]); + + pbuf_free(p1); + pbuf_free(rest2); + pbuf_free(rest3); +} +END_TEST + +/* Test for bug that writing with pbuf_take_at() did nothing + * and returned ERR_OK when writing at beginning of a pbuf + * in the chain. + */ +START_TEST(test_pbuf_take_at_edge) +{ + err_t res; + u8_t *out; + int i; + u8_t testdata[] = { 0x01, 0x08, 0x82, 0x02 }; + struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); + struct pbuf *q = p->next; + LWIP_UNUSED_ARG(_i); + /* alloc big enough to get a chain of pbufs */ + fail_if(p->tot_len == p->len); + memset(p->payload, 0, p->len); + memset(q->payload, 0, q->len); + + /* copy data to the beginning of first pbuf */ + res = pbuf_take_at(p, &testdata, sizeof(testdata), 0); + fail_unless(res == ERR_OK); + + out = (u8_t*)p->payload; + for (i = 0; i < (int)sizeof(testdata); i++) { + fail_unless(out[i] == testdata[i], + "Bad data at pos %d, was %02X, expected %02X", i, out[i], testdata[i]); + } + + /* copy data to the just before end of first pbuf */ + res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len - 1); + fail_unless(res == ERR_OK); + + out = (u8_t*)p->payload; + fail_unless(out[p->len - 1] == testdata[0], + "Bad data at pos %d, was %02X, expected %02X", p->len - 1, out[p->len - 1], testdata[0]); + out = (u8_t*)q->payload; + for (i = 1; i < (int)sizeof(testdata); i++) { + fail_unless(out[i-1] == testdata[i], + "Bad data at pos %d, was %02X, expected %02X", p->len - 1 + i, out[i-1], testdata[i]); + } + + /* copy data to the beginning of second pbuf */ + res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len); + fail_unless(res == ERR_OK); + + out = (u8_t*)p->payload; + for (i = 0; i < (int)sizeof(testdata); i++) { + fail_unless(out[i] == testdata[i], + "Bad data at pos %d, was %02X, expected %02X", p->len+i, out[i], testdata[i]); + } +} +END_TEST + +/* Verify pbuf_put_at()/pbuf_get_at() when using + * offsets equal to beginning of new pbuf in chain + */ +START_TEST(test_pbuf_get_put_at_edge) +{ + u8_t *out; + u8_t testdata = 0x01; + u8_t getdata; + struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL); + struct pbuf *q = p->next; + LWIP_UNUSED_ARG(_i); + /* alloc big enough to get a chain of pbufs */ + fail_if(p->tot_len == p->len); + memset(p->payload, 0, p->len); + memset(q->payload, 0, q->len); + + /* put byte at the beginning of second pbuf */ + pbuf_put_at(p, p->len, testdata); + + out = (u8_t*)q->payload; + fail_unless(*out == testdata, + "Bad data at pos %d, was %02X, expected %02X", p->len, *out, testdata); + + getdata = pbuf_get_at(p, p->len); + fail_unless(*out == getdata, + "pbuf_get_at() returned bad data at pos %d, was %02X, expected %02X", p->len, getdata, *out); +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +pbuf_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_pbuf_copy_zero_pbuf), + TESTFUNC(test_pbuf_split_64k_on_small_pbufs), + TESTFUNC(test_pbuf_queueing_bigger_than_64k), + TESTFUNC(test_pbuf_take_at_edge), + TESTFUNC(test_pbuf_get_put_at_edge) + }; + return create_suite("PBUF", tests, sizeof(tests)/sizeof(testfunc), pbuf_setup, pbuf_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.h b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.h new file mode 100644 index 0000000000..da7730a4c8 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/core/test_pbuf.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_PBUF_H +#define LWIP_HDR_TEST_PBUF_H + +#include "../lwip_check.h" + +Suite *pbuf_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.c b/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.c new file mode 100644 index 0000000000..47aaa08420 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.c @@ -0,0 +1,1024 @@ +#include "test_dhcp.h" + +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/prot/dhcp.h" +#include "lwip/etharp.h" +#include "netif/ethernet.h" + +struct netif net_test; + +static const u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +static const u8_t magic_cookie[] = { 0x63, 0x82, 0x53, 0x63 }; + +static u8_t dhcp_offer[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ + 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, /* From Remote host */ + 0x08, 0x00, /* Protocol: IP */ + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ + 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ + + 0x02, /* Type == Boot reply */ + 0x01, 0x06, /* Hw Ethernet, 6 bytes addrlen */ + 0x00, /* 0 hops */ + 0xAA, 0xAA, 0xAA, 0xAA, /* Transaction id, will be overwritten */ + 0x00, 0x00, /* 0 seconds elapsed */ + 0x00, 0x00, /* Flags (unicast) */ + 0x00, 0x00, 0x00, 0x00, /* Client ip */ + 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ + 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server ip */ + 0x00, 0x00, 0x00, 0x00, /* relay agent */ + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MAC addr + padding */ + + /* Empty server name and boot file name */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ + 0x35, 0x01, 0x02, /* Message type: Offer */ + 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Server identifier (IP) */ + 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ + 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ + 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Subnet mask */ + 0xff, /* End option */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ +}; + +static u8_t dhcp_ack[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ + 0x00, 0x0f, 0xEE, 0x30, 0xAB, 0x22, /* From remote host */ + 0x08, 0x00, /* Proto IP */ + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ + 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ + 0x02, /* Bootp reply */ + 0x01, 0x06, /* Hw type Eth, len 6 */ + 0x00, /* 0 hops */ + 0xAA, 0xAA, 0xAA, 0xAA, + 0x00, 0x00, /* 0 seconds elapsed */ + 0x00, 0x00, /* Flags (unicast) */ + 0x00, 0x00, 0x00, 0x00, /* Client IP */ + 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ + 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server IP */ + 0x00, 0x00, 0x00, 0x00, /* Relay agent */ + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Macaddr + padding */ + + /* Empty server name and boot file name */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ + 0x35, 0x01, 0x05, /* Dhcp message type ack */ + 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server identifier */ + 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ + 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ + 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Netmask */ + 0xff, /* End marker */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ +}; + +static const u8_t arpreply[] = { + 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* dst mac */ + 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* src mac */ + 0x08, 0x06, /* proto arp */ + 0x00, 0x01, /* hw eth */ + 0x08, 0x00, /* proto ip */ + 0x06, /* hw addr len 6 */ + 0x04, /* proto addr len 4 */ + 0x00, 0x02, /* arp reply */ + 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* sender mac */ + 0xc3, 0xaa, 0xbd, 0xc8, /* sender ip */ + 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* target mac */ + 0x00, 0x00, 0x00, 0x00, /* target ip */ +}; + +static int txpacket; +static enum tcase { + TEST_LWIP_DHCP, + TEST_LWIP_DHCP_NAK, + TEST_LWIP_DHCP_RELAY, + TEST_LWIP_DHCP_NAK_NO_ENDMARKER, + TEST_LWIP_DHCP_INVALID_OVERLOAD +} tcase; + +static int debug = 0; +static void setdebug(int a) {debug = a;} + +static int tick = 0; +static void tick_lwip(void) +{ + tick++; + if (tick % 5 == 0) { + dhcp_fine_tmr(); + } + if (tick % 600 == 0) { + dhcp_coarse_tmr(); + } +} + +static void send_pkt(struct netif *netif, const u8_t *data, size_t len) +{ + struct pbuf *p, *q; + LWIP_ASSERT("pkt too big", len <= 0xFFFF); + p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); + + if (debug) { + /* Dump data */ + u32_t i; + printf("RX data (len %d)", p->tot_len); + for (i = 0; i < len; i++) { + printf(" %02X", data[i]); + } + printf("\n"); + } + + fail_unless(p != NULL); + for(q = p; q != NULL; q = q->next) { + memcpy(q->payload, data, q->len); + data += q->len; + } + netif->input(p, netif); +} + +static err_t lwip_tx_func(struct netif *netif, struct pbuf *p); + +static err_t testif_init(struct netif *netif) +{ + netif->name[0] = 'c'; + netif->name[1] = 'h'; + netif->output = etharp_output; + netif->linkoutput = lwip_tx_func; + netif->mtu = 1500; + netif->hwaddr_len = 6; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; + + netif->hwaddr[0] = 0x00; + netif->hwaddr[1] = 0x23; + netif->hwaddr[2] = 0xC1; + netif->hwaddr[3] = 0xDE; + netif->hwaddr[4] = 0xD0; + netif->hwaddr[5] = 0x0D; + + return ERR_OK; +} + +static void dhcp_setup(void) +{ + txpacket = 0; +} + +static void dhcp_teardown(void) +{ +} + +static void check_pkt(struct pbuf *p, u32_t pos, const u8_t *mem, u32_t len) +{ + u8_t *data; + + fail_if((pos + len) > p->tot_len); + while (pos > p->len && p->next) { + pos -= p->len; + p = p->next; + } + fail_if(p == NULL); + fail_unless(pos + len <= p->len); /* All data we seek within same pbuf */ + + data = (u8_t*)p->payload; + fail_if(memcmp(&data[pos], mem, len), "data at pos %d, len %d in packet %d did not match", pos, len, txpacket); +} + +static void check_pkt_fuzzy(struct pbuf *p, u32_t startpos, const u8_t *mem, u32_t len) +{ + int found; + u32_t i; + u8_t *data; + + fail_if((startpos + len) > p->tot_len); + while (startpos > p->len && p->next) { + startpos -= p->len; + p = p->next; + } + fail_if(p == NULL); + fail_unless(startpos + len <= p->len); /* All data we seek within same pbuf */ + + found = 0; + data = (u8_t*)p->payload; + for (i = startpos; i <= (p->len - len); i++) { + if (memcmp(&data[i], mem, len) == 0) { + found = 1; + break; + } + } + fail_unless(found); +} + +static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) +{ + fail_unless(netif == &net_test); + txpacket++; + + if (debug) { + struct pbuf *pp = p; + /* Dump data */ + printf("TX data (pkt %d, len %d, tick %d)", txpacket, p->tot_len, tick); + do { + int i; + for (i = 0; i < pp->len; i++) { + printf(" %02X", ((u8_t *) pp->payload)[i]); + } + if (pp->next) { + pp = pp->next; + } + } while (pp->next); + printf("\n"); + } + + switch (tcase) { + case TEST_LWIP_DHCP: + switch (txpacket) { + case 1: + case 2: + { + const u8_t ipproto[] = { 0x08, 0x00 }; + const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ + const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ + + check_pkt(p, 42, bootp_start, sizeof(bootp_start)); + + check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); + + check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ + + check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); + + /* Check dchp message type, can be at different positions */ + if (txpacket == 1) { + u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; + check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); + } else if (txpacket == 2) { + u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; + u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* Ask for offered IP */ + + check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); + check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); + } + break; + } + case 3: + case 4: + case 5: + { + const u8_t arpproto[] = { 0x08, 0x06 }; + + check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ + break; + } + default: + fail(); + break; + } + break; + + case TEST_LWIP_DHCP_NAK: + { + const u8_t ipproto[] = { 0x08, 0x00 }; + const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ + const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8_t dhcp_nak_opt[] = { 0x35, 0x01, 0x04 }; + const u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* offered IP */ + + fail_unless(txpacket == 4); + check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ + + check_pkt(p, 42, bootp_start, sizeof(bootp_start)); + + check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); + + check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ + + check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); + + check_pkt_fuzzy(p, 282, dhcp_nak_opt, sizeof(dhcp_nak_opt)); /* NAK the ack */ + + check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); + break; + } + + case TEST_LWIP_DHCP_RELAY: + switch (txpacket) { + case 1: + case 2: + { + const u8_t ipproto[] = { 0x08, 0x00 }; + const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ + const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ + + check_pkt(p, 42, bootp_start, sizeof(bootp_start)); + + check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); + + check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ + + check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); + + /* Check dchp message type, can be at different positions */ + if (txpacket == 1) { + u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; + check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); + } else if (txpacket == 2) { + u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; + u8_t requested_ipaddr[] = { 0x32, 0x04, 0x4f, 0x8a, 0x33, 0x05 }; /* Ask for offered IP */ + + check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); + check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); + } + break; + } + case 3: + case 4: + case 5: + case 6: + { + const u8_t arpproto[] = { 0x08, 0x06 }; + + check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ + break; + } + case 7: + { + const u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab }; + const u8_t ipproto[] = { 0x08, 0x00 }; + const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ + const u8_t ipaddrs[] = { 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; + + check_pkt(p, 0, fake_arp, 6); /* eth level dest: broadcast */ + check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ + + check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ + + check_pkt(p, 42, bootp_start, sizeof(bootp_start)); + + check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); + + check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ + + check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); + + /* Check dchp message type, can be at different positions */ + check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); + break; + } + default: + fail(); + break; + } + break; + + default: + break; + } + + return ERR_OK; +} + +/* + * Test basic happy flow DHCP session. + * Validate that xid is checked. + */ +START_TEST(test_dhcp) +{ + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + int i; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + memcpy(&dhcp_offer[46], &xid, 4); + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + fail_unless(txpacket == 1, "TX %d packets, expected 1", txpacket); /* Nothing more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); /* DHCP request sent */ + xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + memcpy(&dhcp_ack[46], &xid, 4); + send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); + + fail_unless(txpacket == 2, "TX %d packets, still expected 2", txpacket); /* No more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ + send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); + + for (i = 0; i < 20; i++) { + tick_lwip(); + } + fail_unless(txpacket == 5, "TX %d packets, expected 5", txpacket); /* ARP requests sent */ + + /* Interface up */ + fail_unless(netif_is_up(&net_test)); + + /* Now it should have taken the IP */ + IP4_ADDR(&addr, 195, 170, 189, 200); + IP4_ADDR(&netmask, 255, 255, 255, 0); + IP4_ADDR(&gw, 195, 170, 189, 171); + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + netif_remove(&net_test); +} +END_TEST + +/* + * Test that IP address is not taken and NAK is sent if someone + * replies to ARP requests for the offered address. + */ +START_TEST(test_dhcp_nak) +{ + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + memcpy(&dhcp_offer[46], &xid, 4); + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + fail_unless(txpacket == 1); /* Nothing more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + fail_unless(txpacket == 2); /* DHCP request sent */ + xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + memcpy(&dhcp_ack[46], &xid, 4); + send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); + + fail_unless(txpacket == 2); /* No more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ + send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); + + fail_unless(txpacket == 3); /* ARP request sent */ + + tcase = TEST_LWIP_DHCP_NAK; /* Switch testcase */ + + /* Send arp reply, mark offered IP as taken */ + send_pkt(&net_test, arpreply, sizeof(arpreply)); + + fail_unless(txpacket == 4); /* DHCP nak sent */ + + netif_remove(&net_test); +} +END_TEST + +/* + * Test case based on captured data where + * replies are sent from a different IP than the + * one the client unicasted to. + */ +START_TEST(test_dhcp_relayed) +{ + u8_t relay_offer[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, + 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, + 0x08, 0x00, 0x45, 0x00, + 0x01, 0x38, 0xfd, 0x53, 0x00, 0x00, 0x40, 0x11, + 0x78, 0x46, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, + 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, + 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, + 0xb6, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, + 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, + 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, + 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, + 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, + 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, + 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x02, 0x36, + 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff + }; + + u8_t relay_ack1[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, + 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, + 0x01, 0x38, 0xfd, 0x55, 0x00, 0x00, 0x40, 0x11, + 0x78, 0x44, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, + 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, + 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, + 0xb6, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, + 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, + 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, + 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, + 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, + 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, + 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x05, 0x36, + 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff + }; + + u8_t relay_ack2[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, + 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, + 0x08, 0x00, 0x45, 0x00, + 0x01, 0x38, 0xfa, 0x18, 0x00, 0x00, 0x40, 0x11, + 0x7b, 0x81, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, + 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, + 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x49, 0x8b, + 0x6e, 0xab, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, + 0x33, 0x05, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, + 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, + 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, + 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, + 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, + 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, + 0x00, 0x00, 0x54, 0x60, 0x35, 0x01, 0x05, 0x36, + 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; + + const u8_t arp_resp[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* DEST */ + 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, /* SRC */ + 0x08, 0x06, /* Type: ARP */ + 0x00, 0x01, /* HW: Ethernet */ + 0x08, 0x00, /* PROTO: IP */ + 0x06, /* HW size */ + 0x04, /* PROTO size */ + 0x00, 0x02, /* OPCODE: Reply */ + + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, /* Target MAC */ + 0x4f, 0x8a, 0x32, 0x01, /* Target IP */ + + 0x00, 0x23, 0xc1, 0x00, 0x06, 0x50, /* src mac */ + 0x4f, 0x8a, 0x33, 0x05, /* src ip */ + + /* Padding follows.. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + int i; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP_RELAY; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + fail_unless(txpacket == 1); /* Nothing more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&relay_offer[46], &xid, 4); /* insert correct transaction id */ + send_pkt(&net_test, relay_offer, sizeof(relay_offer)); + + /* request sent? */ + fail_unless(txpacket == 2, "txpkt = %d, should be 2", txpacket); + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + memcpy(&relay_ack1[46], &xid, 4); /* insert transaction id */ + send_pkt(&net_test, relay_ack1, sizeof(relay_ack1)); + + for (i = 0; i < 25; i++) { + tick_lwip(); + } + fail_unless(txpacket == 5, "txpkt should be 5, is %d", txpacket); /* ARP requests sent */ + + /* Interface up */ + fail_unless(netif_is_up(&net_test)); + + /* Now it should have taken the IP */ + IP4_ADDR(&addr, 79, 138, 51, 5); + IP4_ADDR(&netmask, 255, 255, 254, 0); + IP4_ADDR(&gw, 79, 138, 50, 1); + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + fail_unless(txpacket == 5, "txpacket = %d", txpacket); + + for (i = 0; i < 108000 - 25; i++) { + tick_lwip(); + } + + fail_unless(netif_is_up(&net_test)); + fail_unless(txpacket == 6, "txpacket = %d", txpacket); + + /* We need to send arp response here.. */ + + send_pkt(&net_test, arp_resp, sizeof(arp_resp)); + + fail_unless(txpacket == 7, "txpacket = %d", txpacket); + fail_unless(netif_is_up(&net_test)); + + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + memcpy(&relay_ack2[46], &xid, 4); /* insert transaction id */ + send_pkt(&net_test, relay_ack2, sizeof(relay_ack2)); + + for (i = 0; i < 100000; i++) { + tick_lwip(); + } + + fail_unless(txpacket == 7, "txpacket = %d", txpacket); + + netif_remove(&net_test); + +} +END_TEST + +START_TEST(test_dhcp_nak_no_endmarker) +{ + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + + u8_t dhcp_nack_no_endmarker[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x54, 0x75, + 0xd0, 0x26, 0xd0, 0x0d, 0x08, 0x00, 0x45, 0x00, + 0x01, 0x15, 0x38, 0x86, 0x00, 0x00, 0xff, 0x11, + 0xc0, 0xa8, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x43, 0x00, 0x44, 0x01, 0x01, + 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x7a, 0xcb, + 0xba, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, + 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, + 0x53, 0x63, 0x35, 0x01, 0x06, 0x36, 0x04, 0xc0, + 0xa8, 0x01, 0x01, 0x31, 0xef, 0xad, 0x72, 0x31, + 0x43, 0x4e, 0x44, 0x30, 0x32, 0x35, 0x30, 0x43, + 0x52, 0x47, 0x44, 0x38, 0x35, 0x36, 0x3c, 0x08, + 0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, + 0x37, 0x0d, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, + 0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xfc, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x71, + 0xf3, 0x5b, 0xe2, 0x71, 0x2e, 0x01, 0x08, 0x03, + 0x04, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xeb, 0x1e, + 0x44, 0xec, 0xeb, 0x1e, 0x30, 0x37, 0x0c, 0x01, + 0x0f, 0x03, 0x06, 0x2c, 0x2e, 0x2f, 0x1f, 0x21, + 0x79, 0xf9, 0x2b, 0xff, 0x25, 0xc0, 0x09, 0xd6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP_NAK_NO_ENDMARKER; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + xid = netif_dhcp_data(&net_test)->xid; /* Write bad xid, not using htonl! */ + memcpy(&dhcp_offer[46], &xid, 4); + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + + fail_unless(txpacket == 1); /* Nothing more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ + send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); + + fail_unless(netif_dhcp_data(&net_test)->state == DHCP_STATE_REQUESTING); + + fail_unless(txpacket == 2); /* No more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + memcpy(&dhcp_nack_no_endmarker[46], &xid, 4); /* insert transaction id */ + send_pkt(&net_test, dhcp_nack_no_endmarker, sizeof(dhcp_nack_no_endmarker)); + + /* NAK should put us in another state for a while, no other way detecting it */ + fail_unless(netif_dhcp_data(&net_test)->state != DHCP_STATE_REQUESTING); + + netif_remove(&net_test); +} +END_TEST + +START_TEST(test_dhcp_invalid_overload) +{ + u8_t dhcp_offer_invalid_overload[] = { + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ + 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, /* From Remote host */ + 0x08, 0x00, /* Protocol: IP */ + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ + 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ + + 0x02, /* Type == Boot reply */ + 0x01, 0x06, /* Hw Ethernet, 6 bytes addrlen */ + 0x00, /* 0 hops */ + 0xAA, 0xAA, 0xAA, 0xAA, /* Transaction id, will be overwritten */ + 0x00, 0x00, /* 0 seconds elapsed */ + 0x00, 0x00, /* Flags (unicast) */ + 0x00, 0x00, 0x00, 0x00, /* Client ip */ + 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ + 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server ip */ + 0x00, 0x00, 0x00, 0x00, /* relay agent */ + 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MAC addr + padding */ + + /* Empty server name */ + 0x34, 0x01, 0x02, 0xff, /* Overload: SNAME + END */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Empty boot file name */ + 0x34, 0x01, 0x01, 0xff, /* Overload FILE + END */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ + 0x35, 0x01, 0x02, /* Message type: Offer */ + 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Server identifier (IP) */ + 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ + 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ + 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Subnet mask */ + 0x34, 0x01, 0x03, /* Overload: FILE + SNAME */ + 0xff, /* End option */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ + }; + ip4_addr_t addr; + ip4_addr_t netmask; + ip4_addr_t gw; + u32_t xid; + LWIP_UNUSED_ARG(_i); + + tcase = TEST_LWIP_DHCP_INVALID_OVERLOAD; + setdebug(0); + + IP4_ADDR(&addr, 0, 0, 0, 0); + IP4_ADDR(&netmask, 0, 0, 0, 0); + IP4_ADDR(&gw, 0, 0, 0, 0); + + netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); + netif_set_up(&net_test); + + dhcp_start(&net_test); + + fail_unless(txpacket == 1); /* DHCP discover sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); + memcpy(&dhcp_offer_invalid_overload[46], &xid, 4); /* insert correct transaction id */ + dhcp_offer_invalid_overload[311] = 3; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 2; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 1; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer_invalid_overload)); + /* IP addresses should be zero */ + fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(ip4_addr_t))); + fail_if(memcmp(&netmask, &net_test.netmask, sizeof(ip4_addr_t))); + fail_if(memcmp(&gw, &net_test.gw, sizeof(ip4_addr_t))); + fail_unless(txpacket == 1); /* Nothing more sent */ + + dhcp_offer_invalid_overload[311] = 0; + send_pkt(&net_test, dhcp_offer_invalid_overload, sizeof(dhcp_offer)); + + fail_unless(netif_dhcp_data(&net_test)->state == DHCP_STATE_REQUESTING); + + fail_unless(txpacket == 2); /* No more sent */ + xid = htonl(netif_dhcp_data(&net_test)->xid); /* xid updated */ + + netif_remove(&net_test); +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +dhcp_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_dhcp), + TESTFUNC(test_dhcp_nak), + TESTFUNC(test_dhcp_relayed), + TESTFUNC(test_dhcp_nak_no_endmarker), + TESTFUNC(test_dhcp_invalid_overload) + }; + return create_suite("DHCP", tests, sizeof(tests)/sizeof(testfunc), dhcp_setup, dhcp_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.h b/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.h new file mode 100644 index 0000000000..0d88fa1b69 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/dhcp/test_dhcp.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_DHCP_H +#define LWIP_HDR_TEST_DHCP_H + +#include "../lwip_check.h" + +Suite* dhcp_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.c b/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.c new file mode 100644 index 0000000000..59d73b9b45 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.c @@ -0,0 +1,269 @@ +#include "test_etharp.h" + +#include "lwip/udp.h" +#include "lwip/etharp.h" +#include "netif/ethernet.h" +#include "lwip/stats.h" + +#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS +#error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled" +#endif +#if !ETHARP_SUPPORT_STATIC_ENTRIES +#error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled" +#endif + +static struct netif test_netif; +static ip4_addr_t test_ipaddr, test_netmask, test_gw; +struct eth_addr test_ethaddr = {{1,1,1,1,1,1}}; +struct eth_addr test_ethaddr2 = {{1,1,1,1,1,2}}; +struct eth_addr test_ethaddr3 = {{1,1,1,1,1,3}}; +struct eth_addr test_ethaddr4 = {{1,1,1,1,1,4}}; +static int linkoutput_ctr; + +/* Helper functions */ +static void +etharp_remove_all(void) +{ + int i; + /* call etharp_tmr often enough to have all entries cleaned */ + for(i = 0; i < 0xff; i++) { + etharp_tmr(); + } +} + +static err_t +default_netif_linkoutput(struct netif *netif, struct pbuf *p) +{ + fail_unless(netif == &test_netif); + fail_unless(p != NULL); + linkoutput_ctr++; + return ERR_OK; +} + +static err_t +default_netif_init(struct netif *netif) +{ + fail_unless(netif != NULL); + netif->linkoutput = default_netif_linkoutput; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + netif->hwaddr_len = ETHARP_HWADDR_LEN; + return ERR_OK; +} + +static void +default_netif_add(void) +{ + IP4_ADDR(&test_gw, 192,168,0,1); + IP4_ADDR(&test_ipaddr, 192,168,0,1); + IP4_ADDR(&test_netmask, 255,255,0,0); + + fail_unless(netif_default == NULL); + netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask, + &test_gw, NULL, default_netif_init, NULL)); + netif_set_up(&test_netif); +} + +static void +default_netif_remove(void) +{ + fail_unless(netif_default == &test_netif); + netif_remove(&test_netif); +} + +static void +create_arp_response(ip4_addr_t *adr) +{ + int k; + struct eth_hdr *ethhdr; + struct etharp_hdr *etharphdr; + struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM); + if(p == NULL) { + FAIL_RET(); + } + ethhdr = (struct eth_hdr*)p->payload; + etharphdr = (struct etharp_hdr*)(ethhdr + 1); + + ethhdr->dest = test_ethaddr; + ethhdr->src = test_ethaddr2; + ethhdr->type = htons(ETHTYPE_ARP); + + etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1); + etharphdr->proto = htons(ETHTYPE_IP); + etharphdr->hwlen = ETHARP_HWADDR_LEN; + etharphdr->protolen = sizeof(ip4_addr_t); + etharphdr->opcode = htons(ARP_REPLY); + + SMEMCPY(ðarphdr->sipaddr, adr, sizeof(ip4_addr_t)); + SMEMCPY(ðarphdr->dipaddr, &test_ipaddr, sizeof(ip4_addr_t)); + + k = 6; + while(k > 0) { + k--; + /* Write the ARP MAC-Addresses */ + etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k]; + etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k]; + /* Write the Ethernet MAC-Addresses */ + ethhdr->dest.addr[k] = test_ethaddr.addr[k]; + ethhdr->src.addr[k] = test_ethaddr2.addr[k]; + } + + ethernet_input(p, &test_netif); +} + +/* Setups/teardown functions */ + +static void +etharp_setup(void) +{ + etharp_remove_all(); + default_netif_add(); +} + +static void +etharp_teardown(void) +{ + etharp_remove_all(); + default_netif_remove(); +} + + +/* Test functions */ + +START_TEST(test_etharp_table) +{ +#if ETHARP_SUPPORT_STATIC_ENTRIES + err_t err; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + s8_t idx; + const ip4_addr_t *unused_ipaddr; + struct eth_addr *unused_ethaddr; + struct udp_pcb* pcb; + LWIP_UNUSED_ARG(_i); + + if (netif_default != &test_netif) { + fail("This test needs a default netif"); + } + + linkoutput_ctr = 0; + + pcb = udp_new(); + fail_unless(pcb != NULL); + if (pcb != NULL) { + ip4_addr_t adrs[ARP_TABLE_SIZE + 2]; + int i; + for(i = 0; i < ARP_TABLE_SIZE + 2; i++) { + IP4_ADDR(&adrs[i], 192,168,0,i+2); + } + /* fill ARP-table with dynamic entries */ + for(i = 0; i < ARP_TABLE_SIZE; i++) { + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); + fail_unless(p != NULL); + if (p != NULL) { + err_t err2; + ip_addr_t dst; + ip_addr_copy_from_ip4(dst, adrs[i]); + err2 = udp_sendto(pcb, p, &dst, 123); + fail_unless(err2 == ERR_OK); + /* etharp request sent? */ + fail_unless(linkoutput_ctr == (2*i) + 1); + pbuf_free(p); + + /* create an ARP response */ + create_arp_response(&adrs[i]); + /* queued UDP packet sent? */ + fail_unless(linkoutput_ctr == (2*i) + 2); + + idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == i); + etharp_tmr(); + } + } + linkoutput_ctr = 0; +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* create one static entry */ + err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3); + fail_unless(err == ERR_OK); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == 0); + fail_unless(linkoutput_ctr == 0); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + + linkoutput_ctr = 0; + /* fill ARP-table with dynamic entries */ + for(i = 0; i < ARP_TABLE_SIZE; i++) { + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); + fail_unless(p != NULL); + if (p != NULL) { + err_t err2; + ip_addr_t dst; + ip_addr_copy_from_ip4(dst, adrs[i]); + err2 = udp_sendto(pcb, p, &dst, 123); + fail_unless(err2 == ERR_OK); + /* etharp request sent? */ + fail_unless(linkoutput_ctr == (2*i) + 1); + pbuf_free(p); + + /* create an ARP response */ + create_arp_response(&adrs[i]); + /* queued UDP packet sent? */ + fail_unless(linkoutput_ctr == (2*i) + 2); + + idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); + if (i < ARP_TABLE_SIZE - 1) { + fail_unless(idx == i+1); + } else { + /* the last entry must not overwrite the static entry! */ + fail_unless(idx == 1); + } + etharp_tmr(); + } + } +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* create a second static entry */ + err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4); + fail_unless(err == ERR_OK); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == 0); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == 2); + /* and remove it again */ + err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]); + fail_unless(err == ERR_OK); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == 0); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == -1); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + + /* check that static entries don't time out */ + etharp_remove_all(); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == 0); + +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the first static entry */ + err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]); + fail_unless(err == ERR_OK); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == -1); + idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); + fail_unless(idx == -1); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + + udp_remove(pcb); + } +} +END_TEST + + +/** Create the suite including all tests for this module */ +Suite * +etharp_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_etharp_table) + }; + return create_suite("ETHARP", tests, sizeof(tests)/sizeof(testfunc), etharp_setup, etharp_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.h b/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.h new file mode 100644 index 0000000000..2dd772d8d0 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/etharp/test_etharp.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_ETHARP_H +#define LWIP_HDR_TEST_ETHARP_H + +#include "../lwip_check.h" + +Suite* etharp_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_check.h b/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_check.h new file mode 100644 index 0000000000..0c218d1d16 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_check.h @@ -0,0 +1,37 @@ +#ifndef LWIP_HDR_LWIP_CHECK_H +#define LWIP_HDR_LWIP_CHECK_H + +/* Common header file for lwIP unit tests using the check framework */ + +#include +#include +#include + +#define FAIL_RET() do { fail(); return; } while(0) +#define EXPECT(x) fail_unless(x) +#define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0) +#define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0) +#define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL) + +typedef struct { + TFun func; + const char *name; +} testfunc; + +#define TESTFUNC(x) {(x), "" # x "" } + +/* Modified function from check.h, supplying function name */ +#define tcase_add_named_test(tc,tf) \ + _tcase_add_test((tc),(tf).func,(tf).name,0, 0, 0, 1) + +/** typedef for a function returning a test suite */ +typedef Suite* (suite_getter_fn)(void); + +/** Create a test suite */ +Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown); + +#ifdef LWIP_UNITTESTS_LIB +int lwip_unittests_run(void) +#endif + +#endif /* LWIP_HDR_LWIP_CHECK_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_unittests.c b/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_unittests.c new file mode 100644 index 0000000000..46fd4308e1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/lwip_unittests.c @@ -0,0 +1,70 @@ +#include "lwip_check.h" + +#include "udp/test_udp.h" +#include "tcp/test_tcp.h" +#include "tcp/test_tcp_oos.h" +#include "core/test_mem.h" +#include "core/test_pbuf.h" +#include "etharp/test_etharp.h" +#include "dhcp/test_dhcp.h" +#include "mdns/test_mdns.h" + +#include "lwip/init.h" + +Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown) +{ + size_t i; + Suite *s = suite_create(name); + + for(i = 0; i < num_tests; i++) { + TCase *tc_core = tcase_create(name); + if ((setup != NULL) || (teardown != NULL)) { + tcase_add_checked_fixture(tc_core, setup, teardown); + } + tcase_add_named_test(tc_core, tests[i]); + suite_add_tcase(s, tc_core); + } + return s; +} + +#ifdef LWIP_UNITTESTS_LIB +int lwip_unittests_run(void) +#else +int main(void) +#endif +{ + int number_failed; + SRunner *sr; + size_t i; + suite_getter_fn* suites[] = { + udp_suite, + tcp_suite, + tcp_oos_suite, + mem_suite, + pbuf_suite, + etharp_suite, + dhcp_suite, + mdns_suite + }; + size_t num = sizeof(suites)/sizeof(void*); + LWIP_ASSERT("No suites defined", num > 0); + + lwip_init(); + + sr = srunner_create((suites[0])()); + for(i = 1; i < num; i++) { + srunner_add_suite(sr, ((suite_getter_fn*)suites[i])()); + } + +#ifdef LWIP_UNITTESTS_NOFORK + srunner_set_fork_status(sr, CK_NOFORK); +#endif +#ifdef LWIP_UNITTESTS_FORK + srunner_set_fork_status(sr, CK_FORK); +#endif + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/lwipopts.h b/Sming/third-party/lwip2/lwip2-src/test/unit/lwipopts.h new file mode 100644 index 0000000000..25252b426c --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/lwipopts.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_LWIPOPTS_H +#define LWIP_HDR_LWIPOPTS_H + +/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ +#define NO_SYS 1 +#define SYS_LIGHTWEIGHT_PROT 0 +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 + +/* Enable DHCP to test it, disable UDP checksum to easier inject packets */ +#define LWIP_DHCP 1 + +/* Minimal changes to opt.h required for tcp unit tests: */ +#define MEM_SIZE 16000 +#define TCP_SND_QUEUELEN 40 +#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN +#define TCP_SND_BUF (12 * TCP_MSS) +#define TCP_WND (10 * TCP_MSS) +#define LWIP_WND_SCALE 1 +#define TCP_RCV_SCALE 0 +#define PBUF_POOL_SIZE 400 /* pbuf tests need ~200KByte */ + +/* Enable IGMP and MDNS for MDNS tests */ +#define LWIP_IGMP 1 +#define LWIP_MDNS_RESPONDER 1 +#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER) + +/* Minimal changes to opt.h required for etharp unit tests: */ +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 + +#endif /* LWIP_HDR_LWIPOPTS_H */ diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.c b/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.c new file mode 100644 index 0000000000..ca9be64ea1 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.c @@ -0,0 +1,915 @@ +/* + * Copyright (c) 2015 Verisure Innovation AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Erik Ekman + * + */ + +#include "test_mdns.h" + +#include "lwip/pbuf.h" +#include "lwip/apps/mdns.h" +#include "lwip/apps/mdns_priv.h" + +START_TEST(readname_basic) +{ + static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == sizeof(data)); + fail_unless(domain.length == sizeof(data)); + fail_if(memcmp(&domain.name, data, sizeof(data))); +} +END_TEST + +START_TEST(readname_anydata) +{ + static const u8_t data[] = { 0x05, 0x00, 0xFF, 0x08, 0xc0, 0x0f, 0x04, 0x7f, 0x80, 0x82, 0x88, 0x00 }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == sizeof(data)); + fail_unless(domain.length == sizeof(data)); + fail_if(memcmp(&domain.name, data, sizeof(data))); +} +END_TEST + +START_TEST(readname_short_buf) +{ + static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a' }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_long_label) +{ + static const u8_t data[] = { + 0x05, 'm', 'u', 'l', 't', 'i', + 0x52, 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_overflow) +{ + static const u8_t data[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_jump_earlier) +{ + static const u8_t data[] = { + /* Some padding needed, not supported to jump to bytes containing dns header */ + /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 10 */ 0x0f, 0x0e, 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab, + /* 20 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x0c + }; + static const u8_t fullname[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 20, &domain); + pbuf_free(p); + fail_unless(offset == sizeof(data)); + fail_unless(domain.length == sizeof(fullname)); + + fail_if(memcmp(&domain.name, fullname, sizeof(fullname))); +} +END_TEST + +START_TEST(readname_jump_earlier_jump) +{ + static const u8_t data[] = { + /* Some padding needed, not supported to jump to bytes containing dns header */ + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x0a, 0xf2, + /* 0x10 */ 0x04, 'c', 'a', 's', 't', 0x00, 0xc0, 0x10, + /* 0x18 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x16 + }; + static const u8_t fullname[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0x18, &domain); + pbuf_free(p); + fail_unless(offset == sizeof(data)); + fail_unless(domain.length == sizeof(fullname)); + + fail_if(memcmp(&domain.name, fullname, sizeof(fullname))); +} +END_TEST + +START_TEST(readname_jump_maxdepth) +{ + static const u8_t data[] = { + /* Some padding needed, not supported to jump to bytes containing dns header */ + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x0a, 0xf2, + /* 0x10 */ 0x04, 'n', 'a', 'm', 'e', 0xc0, 0x27, 0x03, + /* 0x18 */ 0x03, 'd', 'n', 's', 0xc0, 0x10, 0xc0, 0x10, + /* 0x20 */ 0x04, 'd', 'e', 'e', 'p', 0xc0, 0x18, 0x00, + /* 0x28 */ 0x04, 'c', 'a', 's', 't', 0xc0, 0x20, 0xb0, + /* 0x30 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x28 + }; + static const u8_t fullname[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', + 0x04, 'd', 'e', 'e', 'p', 0x03, 'd', 'n', 's', + 0x04, 'n', 'a', 'm', 'e', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0x30, &domain); + pbuf_free(p); + fail_unless(offset == sizeof(data)); + fail_unless(domain.length == sizeof(fullname)); + + fail_if(memcmp(&domain.name, fullname, sizeof(fullname))); +} +END_TEST + +START_TEST(readname_jump_later) +{ + static const u8_t data[] = { + /* 0x00 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10, 0x00, 0x01, 0x40, + /* 0x10 */ 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab + }; + static const u8_t fullname[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == 13); + fail_unless(domain.length == sizeof(fullname)); + + fail_if(memcmp(&domain.name, fullname, sizeof(fullname))); +} +END_TEST + +START_TEST(readname_half_jump) +{ + static const u8_t data[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_jump_toolong) +{ + static const u8_t data[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc2, 0x10, 0x00, 0x01, 0x40 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 0, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_jump_loop_label) +{ + static const u8_t data[] = { + /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 10, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(readname_jump_loop_jump) +{ + static const u8_t data[] = { + /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x15 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + offset = mdns_readname(p, 10, &domain); + pbuf_free(p); + fail_unless(offset == MDNS_READNAME_ERROR); +} +END_TEST + +START_TEST(add_label_basic) +{ + static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 }; + struct mdns_domain domain; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + fail_unless(domain.length == sizeof(data)); + fail_if(memcmp(&domain.name, data, sizeof(data))); +} +END_TEST + +START_TEST(add_label_long_label) +{ + static const char *toolong = "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-"; + struct mdns_domain domain; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, toolong, (u8_t)strlen(toolong)); + fail_unless(res == ERR_VAL); +} +END_TEST + +START_TEST(add_label_full) +{ + static const char *label = "0123456789abcdef0123456789abcdef"; + struct mdns_domain domain; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 33); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 66); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 99); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 132); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 165); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 198); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 231); + res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label)); + fail_unless(res == ERR_VAL); + fail_unless(domain.length == 231); + res = mdns_domain_add_label(&domain, label, 25); + fail_unless(res == ERR_VAL); + fail_unless(domain.length == 231); + res = mdns_domain_add_label(&domain, label, 24); + fail_unless(res == ERR_VAL); + fail_unless(domain.length == 231); + res = mdns_domain_add_label(&domain, label, 23); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 255); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + fail_unless(domain.length == 256); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_VAL); + fail_unless(domain.length == 256); +} +END_TEST + +START_TEST(domain_eq_basic) +{ + static const u8_t data[] = { + 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 + }; + struct mdns_domain domain1, domain2; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain1, 0, sizeof(domain1)); + res = mdns_domain_add_label(&domain1, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, NULL, 0); + fail_unless(res == ERR_OK); + fail_unless(domain1.length == sizeof(data)); + + memset(&domain2, 0, sizeof(domain2)); + res = mdns_domain_add_label(&domain2, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, NULL, 0); + fail_unless(res == ERR_OK); + + fail_unless(mdns_domain_eq(&domain1, &domain2)); +} +END_TEST + +START_TEST(domain_eq_diff) +{ + struct mdns_domain domain1, domain2; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain1, 0, sizeof(domain1)); + res = mdns_domain_add_label(&domain1, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, "base", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, NULL, 0); + fail_unless(res == ERR_OK); + + memset(&domain2, 0, sizeof(domain2)); + res = mdns_domain_add_label(&domain2, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, NULL, 0); + fail_unless(res == ERR_OK); + + fail_if(mdns_domain_eq(&domain1, &domain2)); +} +END_TEST + +START_TEST(domain_eq_case) +{ + struct mdns_domain domain1, domain2; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain1, 0, sizeof(domain1)); + res = mdns_domain_add_label(&domain1, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, NULL, 0); + fail_unless(res == ERR_OK); + + memset(&domain2, 0, sizeof(domain2)); + res = mdns_domain_add_label(&domain2, "MulTI", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, "casT", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, NULL, 0); + fail_unless(res == ERR_OK); + + fail_unless(mdns_domain_eq(&domain1, &domain2)); +} +END_TEST + +START_TEST(domain_eq_anydata) +{ + static const u8_t data1[] = { 0x05, 0xcc, 0xdc, 0x00, 0xa0 }; + static const u8_t data2[] = { 0x7f, 0x8c, 0x01, 0xff, 0xcf }; + struct mdns_domain domain1, domain2; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain1, 0, sizeof(domain1)); + res = mdns_domain_add_label(&domain1, (const char*)data1, sizeof(data1)); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, "cast", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, (const char*)data2, sizeof(data2)); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, NULL, 0); + fail_unless(res == ERR_OK); + + memset(&domain2, 0, sizeof(domain2)); + res = mdns_domain_add_label(&domain2, (const char*)data1, sizeof(data1)); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, "casT", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, (const char*)data2, sizeof(data2)); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, NULL, 0); + fail_unless(res == ERR_OK); + + fail_unless(mdns_domain_eq(&domain1, &domain2)); +} +END_TEST + +START_TEST(domain_eq_length) +{ + struct mdns_domain domain1, domain2; + err_t res; + LWIP_UNUSED_ARG(_i); + + memset(&domain1, 0, sizeof(domain1)); + memset(domain1.name, 0xAA, sizeof(MDNS_DOMAIN_MAXLEN)); + res = mdns_domain_add_label(&domain1, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain1, "cast", 4); + fail_unless(res == ERR_OK); + + memset(&domain2, 0, sizeof(domain2)); + memset(domain2.name, 0xBB, sizeof(MDNS_DOMAIN_MAXLEN)); + res = mdns_domain_add_label(&domain2, "multi", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain2, "cast", 4); + fail_unless(res == ERR_OK); + + fail_unless(mdns_domain_eq(&domain1, &domain2)); +} +END_TEST + +START_TEST(compress_full_match) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 0 bytes, then a jump to addr 2 */ + fail_unless(length == 0); + fail_unless(offset == 2); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_full_match_subset) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x02, 'g', 'o', 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 0 bytes, then a jump to addr 5 */ + fail_unless(length == 0); + fail_unless(offset == 5); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_full_match_jump) +{ + static const u8_t data[] = { + /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + /* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00, + /* 0x20 */ 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0xc0, 0x15 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 0x20; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 0 bytes, then a jump to addr 0x20 */ + fail_unless(length == 0); + fail_unless(offset == 0x20); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_no_match) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x04, 'l', 'w', 'i', 'p', 0x05, 'w', 'i', 'k', 'i', 'a', 0x03, 'c', 'o', 'm', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + /* Write all bytes, no jump */ + fail_unless(length == domain.length); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_2nd_label) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "lwip", 4); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 5 bytes, then a jump to addr 9 */ + fail_unless(length == 5); + fail_unless(offset == 9); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_2nd_label_short) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 5 bytes, then a jump to addr 7 */ + fail_unless(length == 7); + fail_unless(offset == 7); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_jump_to_jump) +{ + static const u8_t data[] = { + /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + /* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00, + /* 0x20 */ 0x07, 'b', 'a', 'n', 'a', 'n', 'a', 's', 0xc0, 0x15 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 0x20; + length = mdns_compress_domain(p, &offset, &domain); + /* Dont compress if jump would be to a jump */ + fail_unless(length == domain.length); + + offset = 0x10; + length = mdns_compress_domain(p, &offset, &domain); + /* Write 7 bytes, then a jump to addr 0x15 */ + fail_unless(length == 7); + fail_unless(offset == 0x15); + + pbuf_free(p); +} +END_TEST + +START_TEST(compress_long_match) +{ + static const u8_t data[] = { + 0x00, 0x00, + 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x03, 'c', 'o', 'm', 0x00 + }; + struct pbuf *p; + struct mdns_domain domain; + u16_t offset; + u16_t length; + err_t res; + LWIP_UNUSED_ARG(_i); + + p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM); + p->payload = (void *)(size_t)data; + fail_if(p == NULL); + + memset(&domain, 0, sizeof(domain)); + res = mdns_domain_add_label(&domain, "foobar", 6); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, "local", 5); + fail_unless(res == ERR_OK); + res = mdns_domain_add_label(&domain, NULL, 0); + fail_unless(res == ERR_OK); + + offset = 2; + length = mdns_compress_domain(p, &offset, &domain); + fail_unless(length == domain.length); + + pbuf_free(p); +} +END_TEST + +Suite* mdns_suite(void) +{ + testfunc tests[] = { + TESTFUNC(readname_basic), + TESTFUNC(readname_anydata), + TESTFUNC(readname_short_buf), + TESTFUNC(readname_long_label), + TESTFUNC(readname_overflow), + TESTFUNC(readname_jump_earlier), + TESTFUNC(readname_jump_earlier_jump), + TESTFUNC(readname_jump_maxdepth), + TESTFUNC(readname_jump_later), + TESTFUNC(readname_half_jump), + TESTFUNC(readname_jump_toolong), + TESTFUNC(readname_jump_loop_label), + TESTFUNC(readname_jump_loop_jump), + + TESTFUNC(add_label_basic), + TESTFUNC(add_label_long_label), + TESTFUNC(add_label_full), + + TESTFUNC(domain_eq_basic), + TESTFUNC(domain_eq_diff), + TESTFUNC(domain_eq_case), + TESTFUNC(domain_eq_anydata), + TESTFUNC(domain_eq_length), + + TESTFUNC(compress_full_match), + TESTFUNC(compress_full_match_subset), + TESTFUNC(compress_full_match_jump), + TESTFUNC(compress_no_match), + TESTFUNC(compress_2nd_label), + TESTFUNC(compress_2nd_label_short), + TESTFUNC(compress_jump_to_jump), + TESTFUNC(compress_long_match), + }; + return create_suite("MDNS", tests, sizeof(tests)/sizeof(testfunc), NULL, NULL); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.h b/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.h new file mode 100644 index 0000000000..c3df339140 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/mdns/test_mdns.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_MDNS_H__ +#define LWIP_HDR_TEST_MDNS_H__ + +#include "../lwip_check.h" + +Suite* mdns_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.c b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.c new file mode 100644 index 0000000000..64121ca8f3 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.c @@ -0,0 +1,314 @@ +#include "tcp_helper.h" + +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" +#include "lwip/pbuf.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip_addr.h" + +#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS +#error "This tests needs TCP- and MEMP-statistics enabled" +#endif + +/** Remove all pcbs on the given list. */ +static void +tcp_remove(struct tcp_pcb* pcb_list) +{ + struct tcp_pcb *pcb = pcb_list; + struct tcp_pcb *pcb2; + + while(pcb != NULL) { + pcb2 = pcb; + pcb = pcb->next; + tcp_abort(pcb2); + } +} + +/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */ +void +tcp_remove_all(void) +{ + tcp_remove(tcp_listen_pcbs.pcbs); + tcp_remove(tcp_active_pcbs); + tcp_remove(tcp_tw_pcbs); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_SEG) == 0); + fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); +} + +/** Create a TCP segment usable for passing to tcp_input */ +static struct pbuf* +tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, + u16_t src_port, u16_t dst_port, void* data, size_t data_len, + u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) +{ + struct pbuf *p, *q; + struct ip_hdr* iphdr; + struct tcp_hdr* tcphdr; + u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); + LWIP_ASSERT("data_len too big", data_len <= 0xFFFF); + + p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); + EXPECT_RETNULL(p != NULL); + /* first pbuf must be big enough to hold the headers */ + EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); + if (data_len > 0) { + /* first pbuf must be big enough to hold at least 1 data byte, too */ + EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); + } + + for(q = p; q != NULL; q = q->next) { + memset(q->payload, 0, q->len); + } + + iphdr = (struct ip_hdr*)p->payload; + /* fill IP header */ + iphdr->dest.addr = ip_2_ip4(dst_ip)->addr; + iphdr->src.addr = ip_2_ip4(src_ip)->addr; + IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); + IPH_TOS_SET(iphdr, 0); + IPH_LEN_SET(iphdr, htons(p->tot_len)); + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + + /* let p point to TCP header */ + pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); + + tcphdr = (struct tcp_hdr*)p->payload; + tcphdr->src = htons(src_port); + tcphdr->dest = htons(dst_port); + tcphdr->seqno = htonl(seqno); + tcphdr->ackno = htonl(ackno); + TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); + TCPH_FLAGS_SET(tcphdr, headerflags); + tcphdr->wnd = htons(wnd); + + if (data_len > 0) { + /* let p point to TCP data */ + pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); + /* copy data */ + pbuf_take(p, data, (u16_t)data_len); + /* let p point to TCP header again */ + pbuf_header(p, sizeof(struct tcp_hdr)); + } + + /* calculate checksum */ + + tcphdr->chksum = ip_chksum_pseudo(p, + IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); + + pbuf_header(p, sizeof(struct ip_hdr)); + + return p; +} + +/** Create a TCP segment usable for passing to tcp_input */ +struct pbuf* +tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, + u16_t src_port, u16_t dst_port, void* data, size_t data_len, + u32_t seqno, u32_t ackno, u8_t headerflags) +{ + return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data, + data_len, seqno, ackno, headerflags, TCP_WND); +} + +/** Create a TCP segment usable for passing to tcp_input + * - IP-addresses, ports, seqno and ackno are taken from pcb + * - seqno and ackno can be altered with an offset + */ +struct pbuf* +tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, + u32_t ackno_offset, u8_t headerflags) +{ + return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, + data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); +} + +/** Create a TCP segment usable for passing to tcp_input + * - IP-addresses, ports, seqno and ackno are taken from pcb + * - seqno and ackno can be altered with an offset + * - TCP window can be adjusted + */ +struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, + u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd) +{ + return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, + data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd); +} + +/** Safely bring a tcp_pcb into the requested state */ +void +tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, + ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port) +{ + u32_t iss; + + /* @todo: are these all states? */ + /* @todo: remove from previous list */ + pcb->state = state; + + iss = tcp_next_iss(pcb); + pcb->snd_wl2 = iss; + pcb->snd_nxt = iss; + pcb->lastack = iss; + pcb->snd_lbb = iss; + + if (state == ESTABLISHED) { + TCP_REG(&tcp_active_pcbs, pcb); + ip_addr_copy(pcb->local_ip, *local_ip); + pcb->local_port = local_port; + ip_addr_copy(pcb->remote_ip, *remote_ip); + pcb->remote_port = remote_port; + } else if(state == LISTEN) { + TCP_REG(&tcp_listen_pcbs.pcbs, pcb); + ip_addr_copy(pcb->local_ip, *local_ip); + pcb->local_port = local_port; + } else if(state == TIME_WAIT) { + TCP_REG(&tcp_tw_pcbs, pcb); + ip_addr_copy(pcb->local_ip, *local_ip); + pcb->local_port = local_port; + ip_addr_copy(pcb->remote_ip, *remote_ip); + pcb->remote_port = remote_port; + } else { + fail(); + } +} + +void +test_tcp_counters_err(void* arg, err_t err) +{ + struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; + EXPECT_RET(arg != NULL); + counters->err_calls++; + counters->last_err = err; +} + +static void +test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p) +{ + struct pbuf* q; + u32_t i, received; + if(counters->expected_data == NULL) { + /* no data to compare */ + return; + } + EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len); + received = counters->recved_bytes; + for(q = p; q != NULL; q = q->next) { + char *data = (char*)q->payload; + for(i = 0; i < q->len; i++) { + EXPECT_RET(data[i] == counters->expected_data[received]); + received++; + } + } + EXPECT(received == counters->recved_bytes + p->tot_len); +} + +err_t +test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) +{ + struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; + EXPECT_RETX(arg != NULL, ERR_OK); + EXPECT_RETX(pcb != NULL, ERR_OK); + EXPECT_RETX(err == ERR_OK, ERR_OK); + + if (p != NULL) { + if (counters->close_calls == 0) { + counters->recv_calls++; + test_tcp_counters_check_rxdata(counters, p); + counters->recved_bytes += p->tot_len; + } else { + counters->recv_calls_after_close++; + counters->recved_bytes_after_close += p->tot_len; + } + pbuf_free(p); + } else { + counters->close_calls++; + } + EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0); + return ERR_OK; +} + +/** Allocate a pcb and set up the test_tcp_counters_* callbacks */ +struct tcp_pcb* +test_tcp_new_counters_pcb(struct test_tcp_counters* counters) +{ + struct tcp_pcb* pcb = tcp_new(); + if (pcb != NULL) { + /* set up args and callbacks */ + tcp_arg(pcb, counters); + tcp_recv(pcb, test_tcp_counters_recv); + tcp_err(pcb, test_tcp_counters_err); + pcb->snd_wnd = TCP_WND; + pcb->snd_wnd_max = TCP_WND; + } + return pcb; +} + +/** Calls tcp_input() after adjusting current_iphdr_dest */ +void test_tcp_input(struct pbuf *p, struct netif *inp) +{ + struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; + /* these lines are a hack, don't use them as an example :-) */ + ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest); + ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src); + ip_current_netif() = inp; + ip_data.current_ip4_header = iphdr; + + /* since adding IPv6, p->payload must point to tcp header, not ip header */ + pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); + + tcp_input(p, inp); + + ip_addr_set_zero(ip_current_dest_addr()); + ip_addr_set_zero(ip_current_src_addr()); + ip_current_netif() = NULL; + ip_data.current_ip4_header = NULL; +} + +static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, + const ip4_addr_t *ipaddr) +{ + struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; + LWIP_UNUSED_ARG(ipaddr); + if (txcounters != NULL) + { + txcounters->num_tx_calls++; + txcounters->num_tx_bytes += p->tot_len; + if (txcounters->copy_tx_packets) { + struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + err_t err; + EXPECT(p_copy != NULL); + err = pbuf_copy(p_copy, p); + EXPECT(err == ERR_OK); + if (txcounters->tx_packets == NULL) { + txcounters->tx_packets = p_copy; + } else { + pbuf_cat(txcounters->tx_packets, p_copy); + } + } + } + return ERR_OK; +} + +void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, + ip_addr_t *ip_addr, ip_addr_t *netmask) +{ + struct netif *n; + memset(netif, 0, sizeof(struct netif)); + if (txcounters != NULL) { + memset(txcounters, 0, sizeof(struct test_tcp_txcounters)); + netif->state = txcounters; + } + netif->output = test_tcp_netif_output; + netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; + ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask)); + ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr)); + for (n = netif_list; n != NULL; n = n->next) { + if (n == netif) { + return; + } + } + netif->next = NULL; + netif_list = netif; +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.h b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.h new file mode 100644 index 0000000000..04974818e7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/tcp_helper.h @@ -0,0 +1,52 @@ +#ifndef LWIP_HDR_TCP_HELPER_H +#define LWIP_HDR_TCP_HELPER_H + +#include "../lwip_check.h" +#include "lwip/arch.h" +#include "lwip/tcp.h" +#include "lwip/netif.h" + +/* counters used for test_tcp_counters_* callback functions */ +struct test_tcp_counters { + u32_t recv_calls; + u32_t recved_bytes; + u32_t recv_calls_after_close; + u32_t recved_bytes_after_close; + u32_t close_calls; + u32_t err_calls; + err_t last_err; + char* expected_data; + u32_t expected_data_len; +}; + +struct test_tcp_txcounters { + u32_t num_tx_calls; + u32_t num_tx_bytes; + u8_t copy_tx_packets; + struct pbuf *tx_packets; +}; + +/* Helper functions */ +void tcp_remove_all(void); + +struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, + u16_t src_port, u16_t dst_port, void* data, size_t data_len, + u32_t seqno, u32_t ackno, u8_t headerflags); +struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, + u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags); +struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, + u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd); +void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, + ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port); +void test_tcp_counters_err(void* arg, err_t err); +err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); + +struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters); + +void test_tcp_input(struct pbuf *p, struct netif *inp); + +void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, + ip_addr_t *ip_addr, ip_addr_t *netmask); + + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.c b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.c new file mode 100644 index 0000000000..d99b807d96 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.c @@ -0,0 +1,744 @@ +#include "test_tcp.h" + +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" +#include "tcp_helper.h" +#include "lwip/inet_chksum.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */ +#endif + +#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS +#error "This tests needs TCP- and MEMP-statistics enabled" +#endif +#if TCP_SND_BUF <= TCP_WND +#error "This tests needs TCP_SND_BUF to be > TCP_WND" +#endif + +static u8_t test_tcp_timer; + +/* our own version of tcp_tmr so we can reset fast/slow timer state */ +static void +test_tcp_tmr(void) +{ + tcp_fasttmr(); + if (++test_tcp_timer & 1) { + tcp_slowtmr(); + } +} + +/* Setups/teardown functions */ + +static void +tcp_setup(void) +{ + /* reset iss to default (6510) */ + tcp_ticks = 0; + tcp_ticks = 0 - (tcp_next_iss(NULL) - 6510); + tcp_next_iss(NULL); + tcp_ticks = 0; + + test_tcp_timer = 0; + tcp_remove_all(); +} + +static void +tcp_teardown(void) +{ + netif_list = NULL; + netif_default = NULL; + tcp_remove_all(); +} + + +/* Test functions */ + +/** Call tcp_new() and tcp_abort() and test memp stats */ +START_TEST(test_tcp_new_abort) +{ + struct tcp_pcb* pcb; + LWIP_UNUSED_ARG(_i); + + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + + pcb = tcp_new(); + fail_unless(pcb != NULL); + if (pcb != NULL) { + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); + } +} +END_TEST + +/** Create an ESTABLISHED pcb and check if receive callback is called */ +START_TEST(test_tcp_recv_inseq) +{ + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + char data[] = {1, 2, 3, 4}; + ip_addr_t remote_ip, local_ip, netmask; + u16_t data_len; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + struct test_tcp_txcounters txcounters; + LWIP_UNUSED_ARG(_i); + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + data_len = sizeof(data); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = data_len; + counters.expected_data = data; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + + /* create a segment */ + p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); + EXPECT(p != NULL); + if (p != NULL) { + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 1); + EXPECT(counters.recved_bytes == data_len); + EXPECT(counters.err_calls == 0); + } + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +/** Check that we handle malformed tcp headers, and discard the pbuf(s) */ +START_TEST(test_tcp_malformed_header) +{ + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + char data[] = {1, 2, 3, 4}; + ip_addr_t remote_ip, local_ip, netmask; + u16_t data_len, chksum; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + struct test_tcp_txcounters txcounters; + struct tcp_hdr *hdr; + LWIP_UNUSED_ARG(_i); + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + data_len = sizeof(data); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = data_len; + counters.expected_data = data; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + + /* create a segment */ + p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); + + pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); + + hdr = (struct tcp_hdr *)p->payload; + TCPH_HDRLEN_FLAGS_SET(hdr, 15, 0x3d1); + + hdr->chksum = 0; + + chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &remote_ip, &local_ip); + + hdr->chksum = chksum; + + pbuf_header(p, sizeof(struct ip_hdr)); + + EXPECT(p != NULL); + EXPECT(p->next == NULL); + if (p != NULL) { + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + } + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + + +/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. + * At the end, send more data. */ +START_TEST(test_tcp_fast_retx_recover) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + char data1[] = { 1, 2, 3, 4}; + char data2[] = { 5, 6, 7, 8}; + char data3[] = { 9, 10, 11, 12}; + char data4[] = {13, 14, 15, 16}; + char data5[] = {17, 18, 19, 20}; + char data6[TCP_MSS] = {21, 22, 23, 24}; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; + LWIP_UNUSED_ARG(_i); + + /* initialize local vars */ + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = pcb->snd_wnd; + + /* send data1 */ + err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(txcounters.num_tx_calls == 1); + EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); + memset(&txcounters, 0, sizeof(txcounters)); + /* "recv" ACK for data1 */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &netif); + EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(pcb->unacked == NULL); + /* send data2 */ + err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT_RET(txcounters.num_tx_calls == 1); + EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); + memset(&txcounters, 0, sizeof(txcounters)); + /* duplicate ACK for data1 (data2 is lost) */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &netif); + EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(pcb->dupacks == 1); + /* send data3 */ + err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /* nagle enabled, no tx calls */ + EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(txcounters.num_tx_bytes == 0); + memset(&txcounters, 0, sizeof(txcounters)); + /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &netif); + EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(pcb->dupacks == 2); + /* queue data4, don't send it (unsent-oversize is != 0) */ + err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &netif); + /*EXPECT_RET(txcounters.num_tx_calls == 1);*/ + EXPECT_RET(pcb->dupacks == 3); + memset(&txcounters, 0, sizeof(txcounters)); + /* @todo: check expected data?*/ + + /* send data5, not output yet */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + /*err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK);*/ + EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(txcounters.num_tx_bytes == 0); + memset(&txcounters, 0, sizeof(txcounters)); + { + int i = 0; + do + { + err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY); + i++; + }while(err == ERR_OK); + EXPECT_RET(err != ERR_OK); + } + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /*EXPECT_RET(txcounters.num_tx_calls == 0); + EXPECT_RET(txcounters.num_tx_bytes == 0);*/ + memset(&txcounters, 0, sizeof(txcounters)); + + /* send even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /* ...and even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /* ...and even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /* ...and even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + + /* send ACKs for data2 and data3 */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK); + EXPECT_RET(p != NULL); + test_tcp_input(p, &netif); + /*EXPECT_RET(txcounters.num_tx_calls == 0);*/ + + /* ...and even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + /* ...and even more data */ + err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + +#if 0 + /* create expected segment */ + p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); + EXPECT_RET(p != NULL); + if (p != NULL) { + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT_RET(counters.close_calls == 0); + EXPECT_RET(counters.recv_calls == 1); + EXPECT_RET(counters.recved_bytes == data_len); + EXPECT_RET(counters.err_calls == 0); + } +#endif + /* make sure the pcb is freed */ + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +static u8_t tx_data[TCP_WND*2]; + +static void +check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected) +{ + struct tcp_seg *s = segs; + int i; + for (i = 0; i < num_expected; i++, s = s->next) { + EXPECT_RET(s != NULL); + EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i])); + } + EXPECT(s == NULL); +} + +/** Send data with sequence numbers that wrap around the u32_t range. + * Then, provoke fast retransmission by duplicate ACKs and check that all + * segment lists are still properly sorted. */ +START_TEST(test_tcp_fast_rexmit_wraparound) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; +#define SEQNO1 (0xFFFFFF00 - TCP_MSS) +#define ISS 6510 + u16_t i, sent_total = 0; + u32_t seqnos[] = { + SEQNO1, + SEQNO1 + (1 * TCP_MSS), + SEQNO1 + (2 * TCP_MSS), + SEQNO1 + (3 * TCP_MSS), + SEQNO1 + (4 * TCP_MSS), + SEQNO1 + (5 * TCP_MSS)}; + LWIP_UNUSED_ARG(_i); + + for (i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (u8_t)i; + } + + /* initialize local vars */ + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + + /* create and initialize the pcb */ + tcp_ticks = SEQNO1 - ISS; + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = 2*TCP_MSS; + /* start in congestion advoidance */ + pcb->ssthresh = pcb->cwnd; + + /* send 6 mss-sized segments */ + for (i = 0; i < 6; i++) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + sent_total += TCP_MSS; + } + check_seqnos(pcb->unsent, 6, seqnos); + EXPECT(pcb->unacked == NULL); + err = tcp_output(pcb); + EXPECT(txcounters.num_tx_calls == 2); + EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); + memset(&txcounters, 0, sizeof(txcounters)); + + check_seqnos(pcb->unacked, 2, seqnos); + check_seqnos(pcb->unsent, 4, &seqnos[2]); + + /* ACK the first segment */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK); + test_tcp_input(p, &netif); + /* ensure this didn't trigger a retransmission. Only one + segment should be transmitted because cwnd opened up by + TCP_MSS and a fraction since we are in congestion avoidance */ + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + check_seqnos(pcb->unacked, 2, &seqnos[1]); + check_seqnos(pcb->unsent, 3, &seqnos[3]); + + /* 3 dupacks */ + EXPECT(pcb->dupacks == 0); + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(pcb->dupacks == 1); + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(pcb->dupacks == 2); + /* 3rd dupack -> fast rexmit */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(pcb->dupacks == 3); + EXPECT(txcounters.num_tx_calls == 4); + memset(&txcounters, 0, sizeof(txcounters)); + EXPECT(pcb->unsent == NULL); + check_seqnos(pcb->unacked, 5, &seqnos[1]); + + /* make sure the pcb is freed */ + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +/** Send data with sequence numbers that wrap around the u32_t range. + * Then, provoke RTO retransmission and check that all + * segment lists are still properly sorted. */ +START_TEST(test_tcp_rto_rexmit_wraparound) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; +#define SEQNO1 (0xFFFFFF00 - TCP_MSS) +#define ISS 6510 + u16_t i, sent_total = 0; + u32_t seqnos[] = { + SEQNO1, + SEQNO1 + (1 * TCP_MSS), + SEQNO1 + (2 * TCP_MSS), + SEQNO1 + (3 * TCP_MSS), + SEQNO1 + (4 * TCP_MSS), + SEQNO1 + (5 * TCP_MSS)}; + LWIP_UNUSED_ARG(_i); + + for (i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (u8_t)i; + } + + /* initialize local vars */ + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + + /* create and initialize the pcb */ + tcp_ticks = 0; + tcp_ticks = 0 - tcp_next_iss(NULL); + tcp_ticks = SEQNO1 - tcp_next_iss(NULL); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = 2*TCP_MSS; + + /* send 6 mss-sized segments */ + for (i = 0; i < 6; i++) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + sent_total += TCP_MSS; + } + check_seqnos(pcb->unsent, 6, seqnos); + EXPECT(pcb->unacked == NULL); + err = tcp_output(pcb); + EXPECT(txcounters.num_tx_calls == 2); + EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); + memset(&txcounters, 0, sizeof(txcounters)); + + check_seqnos(pcb->unacked, 2, seqnos); + check_seqnos(pcb->unsent, 4, &seqnos[2]); + + /* call the tcp timer some times */ + for (i = 0; i < 10; i++) { + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 0); + } + /* 11th call to tcp_tmr: RTO rexmit fires */ + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 1); + check_seqnos(pcb->unacked, 1, seqnos); + check_seqnos(pcb->unsent, 5, &seqnos[1]); + + /* fake greater cwnd */ + pcb->cwnd = pcb->snd_wnd; + /* send more data */ + err = tcp_output(pcb); + EXPECT(err == ERR_OK); + /* check queues are sorted */ + EXPECT(pcb->unsent == NULL); + check_seqnos(pcb->unacked, 6, seqnos); + + /* make sure the pcb is freed */ + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. + * At the end, send more data. */ +static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; + u16_t sent_total, i; + u8_t expected = 0xFE; + + for (i = 0; i < sizeof(tx_data); i++) { + u8_t d = (u8_t)i; + if (d == 0xFE) { + d = 0xF0; + } + tx_data[i] = d; + } + if (zero_window_probe_from_unsent) { + tx_data[TCP_WND] = expected; + } else { + tx_data[0] = expected; + } + + /* initialize local vars */ + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + memset(&txcounters, 0, sizeof(txcounters)); + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = pcb->snd_wnd; + + /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */ + sent_total = 0; + if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) { + u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS; + err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + sent_total += initial_data_len; + } + for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + } + EXPECT(sent_total == (TCP_WND - TCP_MSS)); + + /* now ACK the packet before the first */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + /* ensure this didn't trigger a retransmission */ + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + + EXPECT(pcb->persist_backoff == 0); + /* send the last packet, now a complete window has been sent */ + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + sent_total += TCP_MSS; + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + EXPECT(pcb->persist_backoff == 0); + + if (zero_window_probe_from_unsent) { + /* ACK all data but close the TX window */ + p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0); + test_tcp_input(p, &netif); + /* ensure this didn't trigger any transmission */ + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + EXPECT(pcb->persist_backoff == 1); + } + + /* send one byte more (out of window) -> persist timer starts */ + err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + memset(&txcounters, 0, sizeof(txcounters)); + if (!zero_window_probe_from_unsent) { + /* no persist timer unless a zero window announcement has been received */ + EXPECT(pcb->persist_backoff == 0); + } else { + EXPECT(pcb->persist_backoff == 1); + + /* call tcp_timer some more times to let persist timer count up */ + for (i = 0; i < 4; i++) { + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + } + + /* this should trigger the zero-window-probe */ + txcounters.copy_tx_packets = 1; + test_tcp_tmr(); + txcounters.copy_tx_packets = 0; + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == 1 + 40U); + EXPECT(txcounters.tx_packets != NULL); + if (txcounters.tx_packets != NULL) { + u8_t sent; + u16_t ret; + ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); + EXPECT(ret == 1); + EXPECT(sent == expected); + } + if (txcounters.tx_packets != NULL) { + pbuf_free(txcounters.tx_packets); + txcounters.tx_packets = NULL; + } + } + + /* make sure the pcb is freed */ + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} + +START_TEST(test_tcp_tx_full_window_lost_from_unsent) +{ + LWIP_UNUSED_ARG(_i); + test_tcp_tx_full_window_lost(1); +} +END_TEST + +START_TEST(test_tcp_tx_full_window_lost_from_unacked) +{ + LWIP_UNUSED_ARG(_i); + test_tcp_tx_full_window_lost(0); +} +END_TEST + +/** Create the suite including all tests for this module */ +Suite * +tcp_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_tcp_new_abort), + TESTFUNC(test_tcp_recv_inseq), + TESTFUNC(test_tcp_malformed_header), + TESTFUNC(test_tcp_fast_retx_recover), + TESTFUNC(test_tcp_fast_rexmit_wraparound), + TESTFUNC(test_tcp_rto_rexmit_wraparound), + TESTFUNC(test_tcp_tx_full_window_lost_from_unacked), + TESTFUNC(test_tcp_tx_full_window_lost_from_unsent) + }; + return create_suite("TCP", tests, sizeof(tests)/sizeof(testfunc), tcp_setup, tcp_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.h b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.h new file mode 100644 index 0000000000..f28ee56530 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_TCP_H +#define LWIP_HDR_TEST_TCP_H + +#include "../lwip_check.h" + +Suite *tcp_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.c b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.c new file mode 100644 index 0000000000..be61172251 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.c @@ -0,0 +1,1049 @@ +#include "test_tcp_oos.h" + +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" +#include "tcp_helper.h" + +#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS +#error "This tests needs TCP- and MEMP-statistics enabled" +#endif +#if !TCP_QUEUE_OOSEQ +#error "This tests needs TCP_QUEUE_OOSEQ enabled" +#endif + +/** CHECK_SEGMENTS_ON_OOSEQ: + * 1: check count, seqno and len of segments on pcb->ooseq (strict) + * 0: only check that bytes are received in correct order (less strict) */ +#define CHECK_SEGMENTS_ON_OOSEQ 1 + +#if CHECK_SEGMENTS_ON_OOSEQ +#define EXPECT_OOSEQ(x) EXPECT(x) +#else +#define EXPECT_OOSEQ(x) +#endif + +/* helper functions */ + +/** Get the numbers of segments on the ooseq list */ +static int tcp_oos_count(struct tcp_pcb* pcb) +{ + int num = 0; + struct tcp_seg* seg = pcb->ooseq; + while(seg != NULL) { + num++; + seg = seg->next; + } + return num; +} + +#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) +/** Get the numbers of pbufs on the ooseq list */ +static int tcp_oos_pbuf_count(struct tcp_pcb* pcb) +{ + int num = 0; + struct tcp_seg* seg = pcb->ooseq; + while(seg != NULL) { + num += pbuf_clen(seg->p); + seg = seg->next; + } + return num; +} +#endif + +/** Get the seqno of a segment (by index) on the ooseq list + * + * @param pcb the pcb to check for ooseq segments + * @param seg_index index of the segment on the ooseq list + * @return seqno of the segment + */ +static u32_t +tcp_oos_seg_seqno(struct tcp_pcb* pcb, int seg_index) +{ + int num = 0; + struct tcp_seg* seg = pcb->ooseq; + + /* then check the actual segment */ + while(seg != NULL) { + if(num == seg_index) { + return seg->tcphdr->seqno; + } + num++; + seg = seg->next; + } + fail(); + return 0; +} + +/** Get the tcplen (datalen + SYN/FIN) of a segment (by index) on the ooseq list + * + * @param pcb the pcb to check for ooseq segments + * @param seg_index index of the segment on the ooseq list + * @return tcplen of the segment + */ +static int +tcp_oos_seg_tcplen(struct tcp_pcb* pcb, int seg_index) +{ + int num = 0; + struct tcp_seg* seg = pcb->ooseq; + + /* then check the actual segment */ + while(seg != NULL) { + if(num == seg_index) { + return TCP_TCPLEN(seg); + } + num++; + seg = seg->next; + } + fail(); + return -1; +} + +/** Get the tcplen (datalen + SYN/FIN) of all segments on the ooseq list + * + * @param pcb the pcb to check for ooseq segments + * @return tcplen of all segment + */ +static int +tcp_oos_tcplen(struct tcp_pcb* pcb) +{ + int len = 0; + struct tcp_seg* seg = pcb->ooseq; + + /* then check the actual segment */ + while(seg != NULL) { + len += TCP_TCPLEN(seg); + seg = seg->next; + } + return len; +} + +/* Setup/teardown functions */ + +static void +tcp_oos_setup(void) +{ + tcp_remove_all(); +} + +static void +tcp_oos_teardown(void) +{ + tcp_remove_all(); + netif_list = NULL; + netif_default = NULL; +} + + + +/* Test functions */ + +/** create multiple segments and pass them to tcp_input in a wrong + * order to see if ooseq-caching works correctly + * FIN is received in out-of-sequence segments only */ +START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ) +{ + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_8_9, *p_4_8, *p_4_10, *p_2_14, *p_fin, *pinseq; + char data[] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16}; + ip_addr_t remote_ip, local_ip, netmask; + u16_t data_len; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + LWIP_UNUSED_ARG(_i); + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + data_len = sizeof(data); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = data_len; + counters.expected_data = data; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + + /* create segments */ + /* pinseq is sent as last segment! */ + pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); + /* p1: 8 bytes before FIN */ + /* seqno: 8..16 */ + p_8_9 = tcp_create_rx_segment(pcb, &data[8], 8, 8, 0, TCP_ACK|TCP_FIN); + /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ + /* seqno: 4..11 */ + p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); + /* p3: same as p2 but 2 bytes longer */ + /* seqno: 4..13 */ + p_4_10 = tcp_create_rx_segment(pcb, &data[4], 10, 4, 0, TCP_ACK); + /* p4: 14 bytes before FIN, includes data from p1 and p2, plus partly from pinseq */ + /* seqno: 2..15 */ + p_2_14 = tcp_create_rx_segment(pcb, &data[2], 14, 2, 0, TCP_ACK); + /* FIN, seqno 16 */ + p_fin = tcp_create_rx_segment(pcb, NULL, 0,16, 0, TCP_ACK|TCP_FIN); + EXPECT(pinseq != NULL); + EXPECT(p_8_9 != NULL); + EXPECT(p_4_8 != NULL); + EXPECT(p_4_10 != NULL); + EXPECT(p_2_14 != NULL); + EXPECT(p_fin != NULL); + if ((pinseq != NULL) && (p_8_9 != NULL) && (p_4_8 != NULL) && (p_4_10 != NULL) && (p_2_14 != NULL) && (p_fin != NULL)) { + /* pass the segment to tcp_input */ + test_tcp_input(p_8_9, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 8); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */ + + /* pass the segment to tcp_input */ + test_tcp_input(p_4_8, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ + + /* pass the segment to tcp_input */ + test_tcp_input(p_4_10, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* ooseq queue: unchanged */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ + + /* pass the segment to tcp_input */ + test_tcp_input(p_2_14, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ + + /* pass the segment to tcp_input */ + test_tcp_input(p_fin, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* ooseq queue: unchanged */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ + + /* pass the segment to tcp_input */ + test_tcp_input(pinseq, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 1); + EXPECT(counters.recv_calls == 1); + EXPECT(counters.recved_bytes == data_len); + EXPECT(counters.err_calls == 0); + EXPECT(pcb->ooseq == NULL); + } + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + + +/** create multiple segments and pass them to tcp_input in a wrong + * order to see if ooseq-caching works correctly + * FIN is received IN-SEQUENCE at the end */ +START_TEST(test_tcp_recv_ooseq_FIN_INSEQ) +{ + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN; + char data[] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16}; + ip_addr_t remote_ip, local_ip, netmask; + u16_t data_len; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + LWIP_UNUSED_ARG(_i); + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + data_len = sizeof(data); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = data_len; + counters.expected_data = data; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + + /* create segments */ + /* p1: 7 bytes - 2 before FIN */ + /* seqno: 1..2 */ + p_1_2 = tcp_create_rx_segment(pcb, &data[1], 2, 1, 0, TCP_ACK); + /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ + /* seqno: 4..11 */ + p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); + /* p3: same as p2 but 2 bytes longer and one byte more at the front */ + /* seqno: 3..13 */ + p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK); + /* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */ + /* seqno: 2..13 */ + p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK); + /* pinseq is the first segment that is held back to create ooseq! */ + /* seqno: 0..3 */ + pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); + /* p5: last byte before FIN */ + /* seqno: 15 */ + p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); + /* p6: same as p5, should be ignored */ + p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); + /* pinseqFIN: last 2 bytes plus FIN */ + /* only segment containing seqno 14 and FIN */ + pinseqFIN = tcp_create_rx_segment(pcb, &data[14], 2, 14, 0, TCP_ACK|TCP_FIN); + EXPECT(pinseq != NULL); + EXPECT(p_1_2 != NULL); + EXPECT(p_4_8 != NULL); + EXPECT(p_3_11 != NULL); + EXPECT(p_2_12 != NULL); + EXPECT(p_15_1 != NULL); + EXPECT(p_15_1a != NULL); + EXPECT(pinseqFIN != NULL); + if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL) + && (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) { + /* pass the segment to tcp_input */ + test_tcp_input(p_1_2, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); + + /* pass the segment to tcp_input */ + test_tcp_input(p_4_8, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8); + + /* pass the segment to tcp_input */ + test_tcp_input(p_3_11, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); + /* p_3_11 has removed p_4_8 from ooseq */ + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11); + + /* pass the segment to tcp_input */ + test_tcp_input(p_2_12, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 12); + + /* pass the segment to tcp_input */ + test_tcp_input(pinseq, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 1); + EXPECT(counters.recved_bytes == 14); + EXPECT(counters.err_calls == 0); + EXPECT(pcb->ooseq == NULL); + + /* pass the segment to tcp_input */ + test_tcp_input(p_15_1, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 1); + EXPECT(counters.recved_bytes == 14); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); + + /* pass the segment to tcp_input */ + test_tcp_input(p_15_1a, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 1); + EXPECT(counters.recved_bytes == 14); + EXPECT(counters.err_calls == 0); + /* check ooseq queue: unchanged */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); + EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); + EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); + + /* pass the segment to tcp_input */ + test_tcp_input(pinseqFIN, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 1); + EXPECT(counters.recv_calls == 2); + EXPECT(counters.recved_bytes == data_len); + EXPECT(counters.err_calls == 0); + EXPECT(pcb->ooseq == NULL); + } + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} +END_TEST + +static char data_full_wnd[TCP_WND + TCP_MSS]; + +/** create multiple segments and pass them to tcp_input with the first segment missing + * to simulate overruning the rxwin with ooseq queueing enabled */ +START_TEST(test_tcp_recv_ooseq_overrun_rxwin) +{ +#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *pinseq, *p_ovr; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < (int)sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* create segments */ + /* pinseq is sent as last segment! */ + pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); + + for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) { + int count, expected_datalen; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], + TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); + EXPECT_RET(p != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_count(pcb); + EXPECT_OOSEQ(count == k+1); + datalen = tcp_oos_tcplen(pcb); + if (i + TCP_MSS < TCP_WND) { + expected_datalen = (k+1)*TCP_MSS; + } else { + expected_datalen = TCP_WND - TCP_MSS; + } + if (datalen != expected_datalen) { + EXPECT_OOSEQ(datalen == expected_datalen); + } + } + + /* pass in one more segment, cleary overrunning the rxwin */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == k); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == datalen2); + + /* now pass inseq */ + test_tcp_input(pinseq, &netif); + EXPECT(pcb->ooseq == NULL); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +/** similar to above test, except seqno starts near the max rxwin */ +START_TEST(test_tcp_recv_ooseq_overrun_rxwin_edge) +{ +#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *pinseq, *p_ovr; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < (int)sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0xffffffff - (TCP_WND / 2); + + /* create segments */ + /* pinseq is sent as last segment! */ + pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); + + for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) { + int count, expected_datalen; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], + TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); + EXPECT_RET(p != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_count(pcb); + EXPECT_OOSEQ(count == k+1); + datalen = tcp_oos_tcplen(pcb); + if (i + TCP_MSS < TCP_WND) { + expected_datalen = (k+1)*TCP_MSS; + } else { + expected_datalen = TCP_WND - TCP_MSS; + } + if (datalen != expected_datalen) { + EXPECT_OOSEQ(datalen == expected_datalen); + } + } + + /* pass in one more segment, cleary overrunning the rxwin */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == k); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == datalen2); + + /* now pass inseq */ + test_tcp_input(pinseq, &netif); + EXPECT(pcb->ooseq == NULL); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +START_TEST(test_tcp_recv_ooseq_max_bytes) +{ +#if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_ovr; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ + + /* create segments and 'recv' them */ + for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) { + int count; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k], + TCP_MSS, k, 0, TCP_ACK); + EXPECT_RET(p != NULL); + EXPECT_RET(p->next == NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_pbuf_count(pcb); + EXPECT_OOSEQ(count == i); + datalen = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == (i * TCP_MSS)); + } + + /* pass in one more segment, overrunning the limit */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue (ensure the new segment was not accepted) */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS)); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +#endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +START_TEST(test_tcp_recv_ooseq_max_pbufs) +{ +#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + int i; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_ovr; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ + + /* create segments and 'recv' them */ + for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) { + int count; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i], + 1, i, 0, TCP_ACK); + EXPECT_RET(p != NULL); + EXPECT_RET(p->next == NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_pbuf_count(pcb); + EXPECT_OOSEQ(count == i); + datalen = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == i); + } + + /* pass in one more segment, overrunning the limit */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue (ensure the new segment was not accepted) */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen2 == (i-1)); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +static void +check_rx_counters(struct tcp_pcb *pcb, struct test_tcp_counters *counters, u32_t exp_close_calls, u32_t exp_rx_calls, + u32_t exp_rx_bytes, u32_t exp_err_calls, int exp_oos_count, int exp_oos_len) +{ + int oos_len; + EXPECT(counters->close_calls == exp_close_calls); + EXPECT(counters->recv_calls == exp_rx_calls); + EXPECT(counters->recved_bytes == exp_rx_bytes); + EXPECT(counters->err_calls == exp_err_calls); + /* check that pbuf is queued in ooseq */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == exp_oos_count); + oos_len = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(exp_oos_len == oos_len); +} + +/* this test uses 4 packets: + * - data (len=TCP_MSS) + * - FIN + * - data after FIN (len=1) (invalid) + * - 2nd FIN (invalid) + * + * the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq + */ +static void test_tcp_recv_ooseq_double_FINs(int delay_packet) +{ + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0; + int first_dropped = 0xff; + + for(i = 0; i < (int)sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP_ADDR4(&local_ip, 192, 168, 1, 1); + IP_ADDR4(&remote_ip, 192, 168, 1, 2); + IP_ADDR4(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* create segments */ + p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); + p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN); + k = 1; + p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK); + p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN); + + if(delay_packet & 1) { + /* drop normal data */ + first_dropped = 1; + } else { + /* send normal data */ + test_tcp_input(p, &netif); + exp_rx_calls++; + exp_rx_bytes += TCP_MSS; + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 2) { + /* drop FIN */ + if(first_dropped > 2) { + first_dropped = 2; + } + } else { + /* send FIN */ + test_tcp_input(p_normal_fin, &netif); + if (first_dropped < 2) { + /* already dropped packets, this one is ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen++; + } else { + /* inseq */ + exp_close_calls++; + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 4) { + /* drop data-after-FIN */ + if(first_dropped > 3) { + first_dropped = 3; + } + } else { + /* send data-after-FIN */ + test_tcp_input(p_data_after_fin, &netif); + if (first_dropped < 3) { + /* already dropped packets, this one is ooseq */ + if (delay_packet & 2) { + /* correct FIN was ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen += k; + } + } else { + /* inseq: no change */ + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 8) { + /* drop 2nd-FIN */ + if(first_dropped > 4) { + first_dropped = 4; + } + } else { + /* send 2nd-FIN */ + test_tcp_input(p_2nd_fin_ooseq, &netif); + if (first_dropped < 3) { + /* already dropped packets, this one is ooseq */ + if (delay_packet & 2) { + /* correct FIN was ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen++; + } + } else { + /* inseq: no change */ + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 1) { + /* dropped normal data before */ + test_tcp_input(p, &netif); + exp_rx_calls++; + exp_rx_bytes += TCP_MSS; + if((delay_packet & 2) == 0) { + /* normal FIN was NOT delayed */ + exp_close_calls++; + exp_oos_pbufs = exp_oos_tcplen = 0; + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 2) { + /* dropped normal FIN before */ + test_tcp_input(p_normal_fin, &netif); + exp_close_calls++; + exp_oos_pbufs = exp_oos_tcplen = 0; + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 4) { + /* dropped data-after-FIN before */ + test_tcp_input(p_data_after_fin, &netif); + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 8) { + /* dropped 2nd-FIN before */ + test_tcp_input(p_2nd_fin_ooseq, &netif); + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + /* check that ooseq data has been dumped */ + EXPECT(pcb->ooseq == NULL); + + /* make sure the pcb is freed */ + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); + tcp_abort(pcb); + EXPECT(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); +} + +/** create multiple segments and pass them to tcp_input with the first segment missing + * to simulate overruning the rxwin with ooseq queueing enabled */ +#define FIN_TEST(name, num) \ + START_TEST(name) \ + { \ + LWIP_UNUSED_ARG(_i); \ + test_tcp_recv_ooseq_double_FINs(num); \ + } \ + END_TEST +FIN_TEST(test_tcp_recv_ooseq_double_FIN_0, 0) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_1, 1) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_2, 2) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_3, 3) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_4, 4) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_5, 5) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_6, 6) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_7, 7) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_8, 8) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_9, 9) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_10, 10) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_11, 11) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_12, 12) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_13, 13) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_14, 14) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_15, 15) + + +/** Create the suite including all tests for this module */ +Suite * +tcp_oos_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_tcp_recv_ooseq_FIN_OOSEQ), + TESTFUNC(test_tcp_recv_ooseq_FIN_INSEQ), + TESTFUNC(test_tcp_recv_ooseq_overrun_rxwin), + TESTFUNC(test_tcp_recv_ooseq_overrun_rxwin_edge), + TESTFUNC(test_tcp_recv_ooseq_max_bytes), + TESTFUNC(test_tcp_recv_ooseq_max_pbufs), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_0), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_1), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_2), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_3), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_4), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_5), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_6), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_7), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_8), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_9), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_10), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_11), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_12), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_13), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_14), + TESTFUNC(test_tcp_recv_ooseq_double_FIN_15) + }; + return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(testfunc), tcp_oos_setup, tcp_oos_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.h b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.h new file mode 100644 index 0000000000..5b82013b73 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/tcp/test_tcp_oos.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_TCP_OOS_H +#define LWIP_HDR_TEST_TCP_OOS_H + +#include "../lwip_check.h" + +Suite *tcp_oos_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.c b/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.c new file mode 100644 index 0000000000..147822f492 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.c @@ -0,0 +1,68 @@ +#include "test_udp.h" + +#include "lwip/udp.h" +#include "lwip/stats.h" + +#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS +#error "This tests needs UDP- and MEMP-statistics enabled" +#endif + +/* Helper functions */ +static void +udp_remove_all(void) +{ + struct udp_pcb *pcb = udp_pcbs; + struct udp_pcb *pcb2; + + while(pcb != NULL) { + pcb2 = pcb; + pcb = pcb->next; + udp_remove(pcb2); + } + fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); +} + +/* Setups/teardown functions */ + +static void +udp_setup(void) +{ + udp_remove_all(); +} + +static void +udp_teardown(void) +{ + udp_remove_all(); +} + + +/* Test functions */ + +START_TEST(test_udp_new_remove) +{ + struct udp_pcb* pcb; + LWIP_UNUSED_ARG(_i); + + fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); + + pcb = udp_new(); + fail_unless(pcb != NULL); + if (pcb != NULL) { + fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 1); + udp_remove(pcb); + fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0); + } +} +END_TEST + + +/** Create the suite including all tests for this module */ +Suite * +udp_suite(void) +{ + testfunc tests[] = { + TESTFUNC(test_udp_new_remove), + }; + return create_suite("UDP", tests, sizeof(tests)/sizeof(testfunc), udp_setup, udp_teardown); +} diff --git a/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.h b/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.h new file mode 100644 index 0000000000..5426bf42e7 --- /dev/null +++ b/Sming/third-party/lwip2/lwip2-src/test/unit/udp/test_udp.h @@ -0,0 +1,8 @@ +#ifndef LWIP_HDR_TEST_UDP_H +#define LWIP_HDR_TEST_UDP_H + +#include "../lwip_check.h" + +Suite* udp_suite(void); + +#endif diff --git a/Sming/third-party/lwip2/makefiles/Makefile.build-lwip2 b/Sming/third-party/lwip2/makefiles/Makefile.build-lwip2 new file mode 100644 index 0000000000..928bb638a0 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.build-lwip2 @@ -0,0 +1,56 @@ + +ROOT = . +include makefiles/Makefile.defs + +#################################### +#### list of functions going to IRAM +# esp +IRAM = glue2esp_err esp2glue_err pbuf_wrapper_get pbuf_wrapper_release glue2esp_linkoutput ethernet_input pbuf_alloc pbuf_free pbuf_ref +# git +IRAM += glue2git_err git2glue_err new_linkoutput esp2glue_pbuf_freed esp2glue_alloc_for_recv esp2glue_ethernet_input +# lwip2 +IRAM += sys_timeout_LWIP2 +# sntp +IRAM += sntp_time_inc sntp_get_current_timestamp +#################################### + +all: $(LWIP_LIB_RELEASE) + +$(LWIP_LIB_RELEASE): $(LWIP_LIB) + @# according to eagle.app.v6.common.ld: + @# putting symbols into .gnu.linkonce.literal.* instead of (default:).text.* + @# will eventually move them in iram: section .text.* instead of .irom0.text.* + @# check this with xtensa-lx106-elf-objdump -t | grep + @( [ ! -r $(LWIP_LIB_RELEASE) ] || [ $(LWIP_LIB) -nt $(LWIP_LIB_RELEASE) ] ) && cp $(LWIP_LIB) $(LWIP_LIB_RELEASE) && for i in $(IRAM); do \ + echo "---- moving $$i in IRAM"; \ + $(OC) --rename-section .text.$$i=.gnu.linkonce.literal.$$i $(LWIP_LIB_RELEASE); \ + true; \ + done || true + +.PHONY: $(LWIP_LIB) +$(LWIP_LIB): + make -f makefiles/Makefile.glue-esp + make -f makefiles/Makefile.glue + make -C lwip2-src/src -f ../../makefiles/Makefile.lwip2 BUILD=../../$(BUILD) LWIP_LIB=../../$(LWIP_LIB) + +section-show: + @for i in $(IRAM); do \ + echo $$i \\t\\t `$(OD) -t $(LWIP_LIB_RELEASE) | grep " F .* $${i}$$"`; \ + done; true + +install: $(LWIP_LIB_RELEASE) + rm -rf $(LWIP_INCLUDES_RELEASE) + mkdir -p $(LWIP_INCLUDES_RELEASE) + cp -a lwip2-src/src/include/* $(LWIP_INCLUDES_RELEASE) + cp -a glue-lwip/lwip-git-hash.h glue-lwip/arch $(LWIP_INCLUDES_RELEASE) + echo "// this file will be overwritten upon lwip2 rebuild" > $(LWIP_INCLUDES_RELEASE)/lwipopts.h + echo "#ifndef __CUSTOM_EXTRA_DEFINES__" >> $(LWIP_INCLUDES_RELEASE)/lwipopts.h + echo "#define __CUSTOM_EXTRA_DEFINES__" >> $(LWIP_INCLUDES_RELEASE)/lwipopts.h + echo "$(CUSTOM_EXTRA_DEFINES)" >> $(LWIP_INCLUDES_RELEASE)/lwipopts.h + echo "#endif" >> $(LWIP_INCLUDES_RELEASE)/lwipopts.h + cat glue-lwip/lwipopts.h >> $(LWIP_INCLUDES_RELEASE)/lwipopts.h + echo "warning: this directory is re/over/written from lwip2 builder upon lwip2 rebuild" > $(LWIP_INCLUDES_RELEASE)/README.md + touch $(LWIP_INCLUDES_RELEASE)/espconn.h + +clean: + rm -rf build $(LWIP_LIB) diff --git a/Sming/third-party/lwip2/makefiles/Makefile.defs b/Sming/third-party/lwip2/makefiles/Makefile.defs new file mode 100644 index 0000000000..7ab4f87182 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.defs @@ -0,0 +1,10 @@ + +CC = $(TOOLS)gcc +AR = $(TOOLS)ar +OC = $(TOOLS)objcopy +OD = $(TOOLS)objdump + +BUILD = build +BUILD_FLAGS = -Wall -Wextra -std=c99 -c -Os -g -Wpointer-arith -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections +BUILD_DEFINES = -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -DLWIP_OPEN_SRC -DLWIP_BUILD -DUSE_OPTIMIZE_PRINTF + diff --git a/Sming/third-party/lwip2/makefiles/Makefile.glue b/Sming/third-party/lwip2/makefiles/Makefile.glue new file mode 100644 index 0000000000..f325cb3e4b --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.glue @@ -0,0 +1,14 @@ + +OBJ = \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard glue/*.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard glue-lwip/*.c)) \ + +BUILD_INCLUDES = -I$(BUILD) -Iglue -Iglue-lwip -Ilwip2-src/src/include -I$(SDK)/include + +include makefiles/Makefile.defs +include makefiles/Makefile.rules + +-include $(BUILD)/glue/*.d +-include $(BUILD)/glue-lwip/*.d + +all: $(LWIP_LIB) diff --git a/Sming/third-party/lwip2/makefiles/Makefile.glue-esp b/Sming/third-party/lwip2/makefiles/Makefile.glue-esp new file mode 100644 index 0000000000..89a460bded --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.glue-esp @@ -0,0 +1,12 @@ + +OBJ = \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard glue-esp/*.c)) + +BUILD_INCLUDES = -I$(BUILD) -I$(SDK)/include -Iglue-esp/include-esp -Iglue + +include makefiles/Makefile.defs +include makefiles/Makefile.rules + +-include $(BUILD)/glue-esp/*.d + +all: $(LWIP_LIB) diff --git a/Sming/third-party/lwip2/makefiles/Makefile.lwip2 b/Sming/third-party/lwip2/makefiles/Makefile.lwip2 new file mode 100644 index 0000000000..560e346039 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.lwip2 @@ -0,0 +1,30 @@ + +# this one is executed from directory lwip2-src/src/ + +OBJ = \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard netif/ethernet.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard core/*.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard core/ipv4/*.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard core/ipv6/*.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard api/*.c)) \ + $(patsubst %.c,$(BUILD)/%.o,$(wildcard apps/sntp/*.c)) \ + +BUILD_INCLUDES = -I$(BUILD) -I$(SDK)/include -Iinclude -I../../glue -I../../glue-lwip + +all: hash $(LWIP_LIB) + +hash: ../../glue-lwip/lwip-git-hash.h + +../../glue-lwip/lwip-git-hash.h: + cd ../..; makefiles/make-lwip-hash + +include ../../makefiles/Makefile.defs +include ../../makefiles/Makefile.rules + +-include $(BUILD)/netif/*.d +-include $(BUILD)/core/*.d +-include $(BUILD)/core/ipv4/*.d +-include $(BUILD)/core/ipv6/*.d +-include $(BUILD)/api/*.d +-include $(BUILD)/apps/sntp/*.d + diff --git a/Sming/third-party/lwip2/makefiles/Makefile.rules b/Sming/third-party/lwip2/makefiles/Makefile.rules new file mode 100644 index 0000000000..bbbed06469 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/Makefile.rules @@ -0,0 +1,11 @@ + +$(BUILD)/%.h: + @mkdir -p $(dir $@) + @touch $@ + +$(BUILD)/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(BUILD_FLAGS) $(BUILD_DEFINES) $(BUILD_INCLUDES) $< -o $@ + +$(LWIP_LIB): $(BUILD)/user_config.h $(OBJ) + $(AR) cru $@ $(OBJ) diff --git a/Sming/third-party/lwip2/makefiles/make-lwip-hash b/Sming/third-party/lwip2/makefiles/make-lwip-hash new file mode 100755 index 0000000000..33e6d4e126 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/make-lwip-hash @@ -0,0 +1,15 @@ +#!/bin/sh + +cd lwip2-src + +hash=$(git log -1 --format="%h") +tag=$(git describe --tag 2>/dev/null) + +cat << EOF > ../glue-lwip/lwip-git-hash.h +// generated by makefiles/make-lwip2-hash +#ifndef LWIP_HASH_H +#define LWIP_HASH_H +#define LWIP_HASH 0x$hash +#define LWIP_HASH_STR "$hash(tag:$tag)" +#endif // LWIP_HASH_H +EOF diff --git a/Sming/third-party/lwip2/makefiles/patch-non-local-includes b/Sming/third-party/lwip2/makefiles/patch-non-local-includes new file mode 100755 index 0000000000..91368a7d65 --- /dev/null +++ b/Sming/third-party/lwip2/makefiles/patch-non-local-includes @@ -0,0 +1,9 @@ +#!/bin/sh + +{ +for i in "$@"; do + echo "--- ${0##*/}: patching ${i##*/} (include \"lwip/xxx\" -> )" + sed 's,^\(#include\)[ \t]*"\(lwip[^"]*\)".*,\1 <\2>,g' < $i > $i.new + mv $i.new $i +done +} 1>&2 diff --git a/Sming/third-party/pwm/pwm.c b/Sming/third-party/pwm/pwm.c index 51bdf356c9..0386a06ff1 100644 --- a/Sming/third-party/pwm/pwm.c +++ b/Sming/third-party/pwm/pwm.c @@ -16,9 +16,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/* Set the following three defines to your needs */ +#include -#include +/* Set the following three defines to your needs */ #ifndef SDK_PWM_PERIOD_COMPAT_MODE #define SDK_PWM_PERIOD_COMPAT_MODE 0 @@ -44,11 +44,6 @@ #define PWM_MAX_PERIOD PWM_MAX_TICKS #endif -/* ISR related definitions that are missing in some SDKs */ -extern void ets_isr_attach(int intr, void *handler, void *arg); -extern void ets_isr_mask(unsigned intr); -extern void ets_isr_unmask(unsigned intr); - #include #include #include @@ -116,7 +111,7 @@ struct timer_regs { }; static struct timer_regs* timer = (void*)(0x60000600); -static void pwm_intr_handler(void) +static void pwm_intr_handler(void* param) { if ((pwm_state.current_set[pwm_state.current_phase].off_mask == 0) && (pwm_state.current_set[pwm_state.current_phase].on_mask == 0)) {

    M7Ub83|fJ~*1 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libwpa2.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libwpa2.a new file mode 100755 index 0000000000000000000000000000000000000000..6f023dc7f10c03777c1b61dcd66100780df84d94 GIT binary patch literal 475218 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

  2. 9uIA4=VT-( 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 ALjV8( literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libmain.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libmain.a new file mode 100755 index 0000000000000000000000000000000000000000..ee745485109e3d4943037b2b0f556b9afdca6ff3 GIT binary patch literal 228174 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libmbedtls.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libmbedtls.a new file mode 100644 index 0000000000000000000000000000000000000000..62a0422a76143501eec321b84f18ba8e8528a736 GIT binary patch literal 666800 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 u3!iX(`Agr0M@s1Hw$&<&A(sH3d*)5S|Y z?e+aKQ0l3ptm;2p>S@nDQ2lbJ)Kf=U)qf22a54cYR|J&RTG=SuO4N-fLJ)P6`gk0x zvf^4~TZy{Co;p!CsTV9%)1GC9uq@v#p_0&;T?EukWWCak!SgP)pJ;oCBe#a8@^yxE}q&=HY^@SKq&{L-$ zOFW}T9fGNmd!l9C#CV3@ZylibTL)?HQwQk1>o61N<9^0sq@33%-;I=O2qi;w&2LFk zPaS17zp)<17Sw9vjb*75V^8YSajedzuUnqfQ%Cu_eH4OB1Rvg^_uD?uvkpFeB<=Ne z5Pbx_cl(GrvxfFwVK#i#ft-SLla$MmzAfdikun(hz=6;gk@gIfgQb2bWa{5T%K91Q zWFpvvo;u3GQqMM|y#uMJv(!(Pdg>@E`y#2IhZNmlF!JVua2F!|P)9jf>T5w(d(sz5 z8|o;l{;fkBdEVvHhC0gXyiZB}R;0Xls`IXudg>^v^ETGmyeMs`qpWO7rJikTMO1az zE%nqQj)mKvZ=&B=yu$R{l>)J^L{dQMJR5QcoRa)eaC{do!z2W@jOYHVo8c zaqYNwFjx`Q{zT!Qg%E6rYVRIdQ+w{>DT7mneuzeP7Q!$@wGVC_W%Q#8>e*lPwNcZG zI!IZxgOtU2rOdU3Dl5(<^`mt96rG$+*@S-(rXwnOo=#q@lUM8H^_0!{2Z7^5$)!4Z zpH4oalTT5W?Od*tujyp5KUdmt9jENAI=QV*j?>9vf3EC1@w>fJ7QfpoW%0YcQg*Ve z?B8OYyhtan)X99`sK$W!-QFswID+`yUMY*;?UnK&o&5>Qa?J3Zf|A8MYpD-FpC~=w z?ZwYI*twXN2G7DYl;v?{%FjnvjxETYz8 zf&8Cm&Ucc@8f^Zb-@W&9=aX;dnPbfxO_&2Hs&{^?t7CsP}UPHyb)F23GIq ziq3lmf6TyKFVx3X@8^nsWq8&63yi&0|J@#x`2{1K*IT>se(MIdQ5-j4l~f3;4oR-I zwzhF~D*W&N`F1yRN5B)0#ecT%-HfDD*vIf_T+0Ou6ZT%}%8Ik|W=(Tm<2vBB^Rg11 zt^e#8JK2BHoq@l#y;L%D+JwjB)*jDD81HtqmL#Q>OnA1(#Dw4@Z;T)3YTmSYO6-eC z4ZMc9f-%<07*~cBIMlX0x9E6`dt%Y7X&ZA^hTYa%ZOw?E?5Yg}1K1ohrMV`_pC1Uk z+?GAE&N|4*0xLM#%3huyc&Y8!1%d355$k}H#vRz(b}W0k^^z0xlomDS%$)X}l1VL7 z^P98mTk>vs|A_@@tLkH1cJKFp?LHo31%A_3ms_+ZurbH_y&Shb;5n8bsH;n9ZcGY1 z-j-cZXFcUaS+#-hOn(2@=N!w<5B#jHH7}_+9AiB$hb}F`8@Xc+1}D46yq1=pTjDB6 z%0A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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libmesh.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libmesh.a new file mode 100755 index 0000000000000000000000000000000000000000..54379325f9d67da5796013c5c15683604b763804 GIT binary patch literal 198260 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libnet80211.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libnet80211.a new file mode 100755 index 0000000000000000000000000000000000000000..29393d5c226eff704ae93ffa8e1e1d923e9908ab GIT binary patch literal 330530 zcmeFa3w%`7xi-G{&OOKS5>rRq6FO4U<)z6NS3Dq6Jm6kBbP+N#y|AXTeY+5hKRd##z3AwYUN z=lk{F7gpA@-u13`-LHGi-rh@tp{BNvrcU<^r?Oe4nbYZ$u<3}f$?4C6naFpTg2*Pms~ z)t@p(ZT1{A%rlwCj~eD#jFs^l;}kP)V?*#P~IJ zv;;#Dzm+Y$_3goRbQ>z+_0gQkJg-CkyF&F8rqZTHBbuPmNNWn4BLyjy_H?&2)wlF? z>&fis=xS0WqlsxEdX0=Mp_NYk$P&XdC(;q@?F}}yoxLQ4@aT#`iLR_~Z_+Z*)!h`- z^Srw4Q+^hcCK3wvwxGGS*0*=I_iFssP)kd5*J`kP+M8Qg8`1KO`V9-Rwx=b8ii*|L z-YPR3RnXKH?2Jtaef>zF9#1=Z1Z6v0I!?o`Z@gY)XnlKYd;RJzq_n3+&qh<|`tIJY z`cqRN`Rju19l^#9y+mXX=wW-+672?Q=^S3BQoOl^?53vG-A3-wbUbrJx#$*qp}+kYvu+!mbS0P;89sqi{6g_LhI7@rt6HQtGlmST3J~$ zx1+14rLx8l<<`^H+6#p}BJOC0+q%H%R%It$sEy_h#3&+=y!OuSwY>(@(-iCwDXDMn z>THQo-lZ2vTd&fq#n)Tk$r_Ali4YZRjwzjMbtT=wP)|#JTkr4+fxKI|@D8r-(P|J? zy0#ngZ1bn`8-qRVO(XaQF`C525#h;RuSMc|wRg65jmR810D6raJ}^ktx3vVDV*(Es zSl!aoRv+x?>C!tpBOXC)WvFXdp`9w$)4sYJRoWeF*XNs4R&h{__83b#I$Anc>fPOK zM2#)MreXPV+3UOYs9avCN6){@b4PhCRaz>BjYp#9)~rQWjBVzcPjgF57ts8mSc^vU zzz{RC2igScQuFIt+l&5M-`%*jRpW}uP9$4nu3ovix89Z4xV;hr+$rceil)qwDBd6RV>etW$?V zXy%x#2VEcP39f4~x?Q`zwPS5hn_jSDP?f%VxKP(f6DA|*Y3mC0_H=aha`e}Nv}5A$ zc58W9>esJ!2Xpk1;R7)}PBTWY?tmYv}AK-fzst-+tsW2xv3k`E7aQFT#vOQa?G`LS9gm(9>n-Iah}!m z#(0NXP_C!-9%+dfqu_MQ!&AjpUWFCHRlT9LP3}}J7FH`!)@>~qjN}raqrLOG`j$@7 zIOS3TYmcg~5Ca=aTd+v!4N8x?V8;S6@t?w;*Rsw~RmgP-+Fo#_!A>UHxItd$+SRA( zyYdRHEJR4Ta1+>FpNLtARkspzmYdXJsTcVXixD@6kkUd6i0GTJq7=A$wOV1KCOM=D zZd-eEb4zEvn5qPW!x&m4W-j3jwXE)1*P?SMAjTdokd%sLyPG4iuI<1&L?~qUYHsP7 zi+s5Zj00|Av8-C;swz^by<9trfFrR)jk;NIg^+^Qb`*qLHX@umZ^>y7CCk-c@7kW2 z& zjr?=5Pkyio^JJ)nUF|x-aH|c~BwV2utOv3Di+GF3lrM{KB&FPAM-*U%(OKWt#Q{f) zmkrF1okzVmYAPr8k7lCB0PoISpVo6g;kKYWMPii* z6VTHZyw2S{C~i|vu)eiZ=s*XPv#3ab+s8s~oMIi}LfNe_up`+qX$_%|3YN?bXAmlj zIDATI-gN!2{ZVfhrnb)OF$i>CAJx99tG&}OrpF%A4nMLz#WiDgx#TsZMtiEeMxE9* z{S=bc7u(StkR5k0UQ9?o}njxoITv1%jRnc;$B3>wbjLikipy;x}v z=d+fEbKC{pa9(%U`j$`(iwmRStjNkChK&`%a1Og8In(9YxvDb#w0%~oA8hw;S!wA- z7tQo|F1o0UOi)AWjq?{)nWl+Dcb81#lSb5K81JTlA7>adg?FKmZ+NBT>8%@1q#w7X zcQWh(|Ac~&r#5`!)dT5=?(x3oc$&fs5^XE}I3?ei^se`9r|NyD?)N9XZ#jwYI!bfp zNhfRH@f6ei&>1p}WHW1DM*4B-sq1%z-ggRSoKw&pD_-Y#+u)|tV4b~3(paTl9bXzcdYrH>s9rx^BE)Y5BPK7Z6<^%91lAKCI{xs zd8xa}`7`nYwGsWqB0pA~dHeg$%7zs44^DE%aNqHe-&2LN;tTHf2z*%S24?ONT9 zNj&7KYYFvWcJ-8%O)H(|pXM(`E1FeWHlxg6UOvlniN|wFpKtOsxq+KK>v7rynUX90 zo|2U_3|3AUt%wcDji-JAk1ndOuAh75;;IFgEtpq2r*uP;zr3kA*cwdL_+{Xim6rP( zFKWFgHLz^K!g=+}7B5(`Y<~TMdGIPNEuD37X>fLGWnjUaveac)&9AQvTy^EbWlQJR zFI=#6er@H#tLBtaVcq=Ns}@|jc#d!3@)^icnUBmx3l=Mn`bCwOUs*fHKciHL5A#{D z7(QhpK;`n&1<-wDfZF*B=T{<0iz^q+pW~~oDq$&3^ZQbjMjx=4)6EOhNm zV9J~a!?9=(2G8LHiNOVkI?2CKa9usbN`8jMCszDRH9jHrF<#o|z^Hfu1&=oKLmAo} z3Mo?tLt;2$jF%!k95fRoMiB|33^8q{xe_Kx;%e9=`VlKVR{$%ST3`}oh|^)Hryhnx zKCz0onM@G*#ERceCWw3z%aD1YO;Y^-m+OM<$t-l+6$fdizZizZ^b=b!ET3sGY)ix+ zgHdH0047nMcnl0>YGBwWh(8WPq6~2s4EY@}B=U)Aliv$NqMKO7wVq56`Np)K>sRBz z26k`Awc8ZxXvb5!V8=9ZWYpfdF4$pAQ@rRfEPUmYAgmeOM|)?Hi$451i^iz8IFC4O zB82ZK5~0hTIT4zqF|D^{L$5InyRzUkaRfMxOK-s)Ryaa{veV91JZF>C({>hFnGU^t zMhcn$9M9wsdG(jcJ&NS7QfYOxqwP^=aZ<(=9a=30jUULO8H#?`G>8Elq?V zr}0D?fJ2&2YPgsV=4j-u9;MvIQObo!DYti&axaWhE)kg>O@1ezMUFa1rBaSV1*se+ zPayY?7%~8-LQa)AeJ;gVv=p`vhQk&8Y?zB6$1qACWpq;UeniHr>X&l5eubCB$SsGQ znm(yl$t{GO!sKs7`gXx)`Z%=GkLmk#jJ`X-;}ow*=~x$|uRPn0m-;vbD}7&!(YF_V zYKo&yrEf4sUoZ510DtP^u&(rdFGimyCY;jue2iQ^+#{9Cb1~t&bE4(KrG|<(&KlmX z8W3)zayc2JZ#N$0duRWpF=2Pe}^4N_~o-jzlQky zn7$lf>g1M&m~BzyS7MQ0VCtSPWw?c0Dly}~R$_(?YPeOyq8y-yTUz!Y##Ia3EAdR& z`4Tt7rW|D$KlKtK8atzY>f3l~~lT#7u|YCUY1Oi0Lrpa3bm#eDXy7YJAmJ&sf)q)aa5ahoC$-b1Fx|zyV;yh@6hlr4e!ahoLH96 z2O3UB{uDn)!yXM6Yq(s)^E6ze;cGSArr}-<_i1>GhVRnwS2es_!{5>HL1Nj?xdvAF zD6wn%(tDkxFL_>^JK2fdZ#GPo_9sDd4iswD^4~KX6lc!gubkOM^nlcc%NVLc;$-; zPbKEwnQj#nWit~-? ziit}v`xd4rJKpM;T-%XfTV?o)C;N-@165Y3Z=Qx!K@oIg-J zIisQ?ynW+9ReXPOehAL$ioW$5LsbcZ;>m%kM1S$*((+1wRg$l`pxi9Xy2MvxR-x)m z^BE?n$Sn6RN;iKa!V37jO(vU?Orxi`~6pI>(UNZ9$AuHmbK4= zXM=s4o^X)s@h3$q>T?|DMmQ^Ae;4K#&RB!qhI1S)=bs%THCpcEld|?5e(k}OjgQ~{ z{LZJW7vqwx-zGfJ&>l=#vY>Luu{lX4>E`d5q7`H2q_4J$)>K!P*yeF^ert)Re^(hh zUvm6eX%D{S__9(rpMQxDwRKnW?(G@j?H<7G$-$pFYkuYcE>G@WmeH_`+-s66kC0WK zTrnd9_UvSjXK&eaPK7TMuH@uWBg11*@H6Qp_M9<+@Zr3Kwk0Xa&zp@0X1L{Lr`S1V z2c6|>k{9RxDn4YG3zPfSdqNdv;oZq=+AJ%>XsB7*&{|p1>It`IBHC-LwyT!>r!&+# zbf{`D+!r=HN7h&Y``MC$NBl?9YaY!we0XNxi06f3jWi_|-fhJ1ObL{X+5TB`2g~)~ z?MHUL`e5?LtbL_gj}fB-r#_knm_C>cn6r`hIG+6;el3_%_THMuE1zHTRD2-Ld@-)# zo%of_spY=ptV@hP@|mc8d}!9t#ii-qUpeOMOb14hLZi*MAeMM_UDe)8Y%WI$5-C;@z$xWE5A8*PJ;J{WByzOJ61KpNb#2a*txiQTnYPYsrfuT zlD%cmIEVZlzN#!k@}DE$8k0~^aYaGRT<;T(d041;c2kPsJ?QwyB$!W;vE+bLvm(4a zVat!v6vmh(=G1u=6}>|VhHbGoyc&FW4SNL2%RYx$NhmSx=KJSdv+>AA^Z!yo?sxxK zV$Ml7zat#J_iKFxx!-@U(T)q*#?`I=)Ndya*hzzSLf`hxzWdCrn>_=z+1K|LoLkoe z$KUEVwr8R}!*#uH)6dwc>gF$=cV(@oa_&+*9KFPYd&{1dP^c^9!4HGF%P#RuZcc?% zl+Gycr+ieFC`Nv5=XJQb-HC_C9$rLEjrAwf)7;*(I*6bBP+4@ZDIY3mKY)?Ayyp$o?FlM1^^U$~-W)ckXAj~B&BA7(NPX(So;Z^}@&N(0xVB+3(~ z!7#4#VN|?l(#eA$>SS1^gJD?)B(m3o zxR%3^l)PRqjE_1IT%?ckAAuoJp7;V7^0`TGlK4MilPE)M!BFPAFg!#c{w<6ut9OA( zlqY6>`(ZwWA(2mFy3In@o&!vowJ@rDJ_SsoJn^?-7}rd+xd{?42L80fj{~ba4F3g8 zQgKxPGcMY&L|kpKNt7YBV5ol;49l1JvoIve5MK;K{f$p0}6iF{(Vn|_$z z!>D}4mJjQQVcD0?mH0ehOX3TF*{&!v4VXmz#7gH3jZdt?&H`?LEW>_5lYvvTAI4cq z2Pl4lizgAwaEjjm;DMn`pN0WNS($~Wwn_E@#>@UoVwy?p7nG;{H|;N@xEG-<5>ENa z@CX+m_`Blaza5SU@kY1$5pjg6))%AseQ+dD^w9iI3Z`WRcl}3L^YHh@kw`S@)BVtR z1X=x}h_;*>Nv-}E;4Gpeq*dN8k0jx&1*v{v90@UsQjCPrE`*G9o8r`8le;$}Vy=md z&^V&nhBc2U`>gq5IQesPEz(hBZsdSkwV$DpMAN6qpSGEVx>$a^d{j1Vro0~#Q#7Y- zHzUP#+LqHE>RPSet3z zDquz<*D^{uPQ9bi_l;4?{d$yg;*1)yXU#7XH=6WaH%hrXM=2M3uj6#}@%AY7{W$K- z`CuMNMVQ-(AucF3UM0u-8k};K9G6?;-5}zxnvQ2neX5)(*PzL%cEvMsh3WmA$GvyL zXLVer(vM4-h8TT!fj1dOk<#&r7=1T*-Q@@M@m7J-cT0@EA^44?uRliL1JHLVWT}tK zIi>IJ7=5q8Pc6j(BYE5&qwiHsU#_O_$1(c2bW+Q9T_4ZwRo===EApzjF$sgLEO^sSWo z{NRx~V)8{fL}7e7CSE=lQOk0MQ)yop6Yp0i;h8cNFkWs)RJ^-l^i{({EopUq_r&O9 zV|fg5Q=eDUcQ{7h(FDWzB^60hb$B#J?lE)}wWOt}%E!-Q;(ct2dpCpe=1V#DkFf~A z@=^UQ1N+L6+FvTMI40bSd<;xKR9M+G#!mIe0~ACmfH^Lz063EcGe=HQ4(%CG!TULPaTV*vQZHafFD{srQ(;ag7r1 zG3gX1dQy}VCk}gbcYf3X6lbu-Mk!9TINd$GRQ~txeGNamjuVF)dV1OOqIC9qa~DR1 zf#Qs*F>bc-D8-?L>LtQ<#qol%E`{N}F}68H^k+L{8}!0t;ost6?i_KXLx1-9EF;(0 zB>kx~3*5c1IZw_L?g_^8uoY4N%P^FE6DA8IR+5%L`t!)59QNI?v(R2X7URD(#?3Ka z5yJ=Ju7JG^b{2ARQ;h#WjQcBaGrc^L$-)S`FUJ2U+|m3N7%Aw3bi4V*;1csPs#AA) z;#acVM|E}c)lK>ng;UM}^!?pg_ZZsVY!rJ7O4uu?@QZ7{XDTXjx*c6t4}N~$-r3t)-;K9_ z7%Jhz!k(IB_2cuA^{c|i@7Ud6NSyW%MeW%}Q3Xnr?Z;%tLt7#V44Zqi9LZyQB%TC& zzQjDX=9+PUt$^YI77`GF{Mnm%HPf}rp4AxO39%b^b9%V$l zz&!runt^;`k_sziILLvB6`yW(hlc$E%GFgEjt~=EIKjJjWpDFnt zfi3D6dj1o5zT`8mWfFfJwkV$>01*AClRV-y$pi?3&)bkaIS+=_+X1RS&V%F8$5;L9x=%s$HbvYLhdw{Q(I3HN_5%AXn zUj;)M;zAfxE+N>L$S03DP4Zck=2ZLvT?a!M@`%$UzenmAjhVtYQr%C>G%WUIRL|wN1P`4%%^I@qMTV!AeM_MG0RKIkfkuoSIMy46$Ug+ zCK6Nulaof|uFr{A0e8a?Gu)>o<|Bl!Nle{)H2%X9GyW$fX1bo0m|=e-aimV6pM17& z#>M<`-%HGV^EXJuvtV=H7U_Y_woBXwd$q)$h3$bcxqtzQI)aQx;xx%0gqvZ%1)FU} z$=@gWT_b%?e-3jpMW zA)h?rG|8VT`3%SQr^=9JM|tvyRrvr$`iq!%#*ib^1Dp-abmRa><{gPCr}~b|eYdz{M@>7gKKJdBC?i{yb(_fXlM)E!f%)1(3r^JAt8DEh34x+7J?n8+8Y2F8@> zUrwy22lYV`Whk*ogT(ppQ+W~bT0-1y0}_k4Bwk8+i5oQBq2Uc0zFEUtHM~Q^yEMF) zSeDz6h7W1@2(c{Bmos)!}Bye>buKw9n#0J5^vG) zUBpR9An2Si|D(vXl{bmnG)eo6^ZMP}Tm$-DTMq z#NB0y-_m4wkfP+p-DN2w?k-C#?k-C#?k-Er-{7gR)f!%^;RX$NXn2E$Z`SZu4e!vf zIGdF5?$!818a|}qBN~30n4KGRT*Dt|I2mnU$#C7Rut&qi#Bw|-*YG?I*J$`!Vmaot zX}DLzeHz}P;kz{aRbn|_?bh&jG#uHg;Uz;J&?xSa&$@_$qj;~-BN-?-lojVs&gy<+ zy3v6NVXrjg20wIGShyJdUghJNDdzLu*UFyxgJX}e!Z$r-op{zf@xvYVF<*hSvQ z+pbyigO4RYd+oeG?64ZIo%h03zPx$<@J;6LoFPnxDjqR- zF7X(ANhw));TJ8VaB``C!zHKtQ)GCidW0Nbk%%`YpH-gSax)^ev&v37c6?y&X9IKl zeRDs~4?(i97(|n%E+lJyJR~m)9h#Y^sxc;6k z!ubQY;JyBh=h-*m4NbVSKZHd<*)LPDTmTy1N1>&zr@UnSRj z%rRdfaQ}k+Yawi#zoL!H+xu5uWByV|9OK`EndVEhRkqmHz6n$Mj^h{_1^+0oiN5Qs zZ^})|nm^^DQu`|3vw!gI-)_D`4T*_HQr5I77iC1)Z<1Zb>&H^N`5Py1ZmQ3GgC2kM zZFuUsyw6HZKh9qsApWmnoM)QsU)w*~_#xs>Uzs&^%ERY* zeBnM{IQ{s_tn;QkJT~v1Dc^hpEZ?&^zWtlij|-UM+rKjXI4(_7QKQduZ*FeGx~-n| z;r^_713vF9+pNoOO@7k1e&BbE+V`yK+kdl&bC|4k+ZkoKeo<5?L8-Jou=`+^!;l)p zUw4fp;a|<4?Po8wE>E89eYmt3^-MN{*!SI~1fx+qK zj~NKpgcs%dvVA)<=8Uyd2OIp4ED8+H8oVyke45^`F7kCwE?i{!Cg(O}mHnqlJm_kxsrt|0)tiNU3Az9*R0rd!13Pfm|vh9Kk=}~B);iT{*&hI zLS&4c*uLVxQNjC&`FY7px_(jOD}T`&$)^3|y7b@Ub!j!9U`ZlK*>c%sD7U+YaQAo= zRD8K?Ha5G#T^*P!Nz`p(5TiW>rXS{Fm=c&lm}VG`cf>cqa4$-{4Thw2GcDY^N7A~$ z#q{TE(WpaU@IAoXf>It)3!)4$(@cJ;%Z^;@^pKCRHMD6UqsCZRAs{0mFD7h9N0=mMP_FPllm9&tFNDAy)OZluQu$#1;&7*1@QJtpFxb zhM46;nJyR-`NXU{@_S)OOJZEaDX^J_Ilz|0JY$<6@im$}v6A@&aJQ6s zQj;N8GEV`kG2wkphWJ7mHlM;EriYkiHwaUz@rhNL&(iqBIZ}Rs#wS+%6&imuuZ@fB zRm8ic-FIR~ZrDaW`K<)J3PgUSX9NMfvpVK$J!cf+YsOA}OWm;V_l)2l`H;^DevvN= zjo`S{?A$b)rWv0V&dU)2(@u$vB+!RVs6|HuaS{-MC)WE-)OCjnELtO zzt>xizRh8S^8#t6YeoKYTqRutGa5NQcNvY`-J_KIzoV4<=_uvi8Kqn{GBKKbOdqA( zm7|nfH%d8i4vf5Qn0@>dV9&2+>Hn?0|zZij+PZathOLIrJ@s zOuR6F=8!u3*-B&9F*J$75X?tA;FPp#XS-`iu-$Fq2~=A=rcZ%a)2Hv8PQJ@p}} zk^JtC(Ki$Ns;Eek(szH1z6YSM0W#Ewq(<~T9i#6C=u>M-h(*%(c#J-KlB`3}@z*l)EzXSRzu<&F0xR+A; zN~AvWNoA<$t6eDmGA^2nAjf@*qRo(dgdUO<6wgW&6Ltj#n;OlnYwKY93S$9d)%-wn(g#f7>4KB2jBA;hRr$s zCgGlFd=s`J%0HOvFXvv~2fh(* zmd!_n+biw`0g7_T!if8I8J^{oh0_?WBNQ<`oL3dm{XE>8VgDF*7TW78G5+twxcNR@ zMGQYC#vOYf_iMu{(mO)_PB<~XD7mjf1!`>-zBraLbb0nW}5vPIA{wvB;4%4DMArL7~$)}vU6Z#2Y#zh{n zx)a(V`64aAW-|3}wh8PLq6&(PlpWfcju4LmsiZ-|Ycb z_fIziQ-(ZZb^nwq)IHO!z?316Slu%%qzwOncEC`EPU1AlXO_$Y`~eNZP=-8Wbsw-4 z*yJD3eK3@vlQ>QCMO#X7+k=NPz@$rHi0fc4(J<#U@}Vm7?oi5zvX%0pEdjG`nMBI- zjJ!x<>abzVGW-E?&Z7)@#A%Yx@G5MD#7kjkz^JgIKO!u7#40T7*p&A%n}Ml^JYsd< zFqM4%0mZ`*(~0G$z?|opCf>~?Rl*Qcme*s5J+L|d6Vsnzh%bWek(hi@CX&x8qzubG zju?@g2V3X?CST|Q_5zDO4vhb{%Q zviXL@e2%e4<9|zHJ_ETFSm}RM^2sAs`YV8y%+G+C2J(oN%&#P$d6@@neguC&$6+W> z9&wuFzc2ZG)=>?t-r(HuE~5-%8*B_WUkd@J}YI&BUUn-B%k%$KzUgXw@W^G#45krC7;iinl<@d zl20D7lIK33<;G`3ZIqYguwU}YBUa_ZbWr|Bun$Yjw#v0O`NSR6!$B8xRPxCqPLup@ zxRuO*OBwQrl?>Yib+R8g5>tP#7B&@rlp&8;h25aZjFU3t5i6M+C?osA6e&XQ1qTSgw%@i5Un~3S(jp zB9+6a`?D3qmahT*Ds_%W_UeyHPkt!yaN;{>2(D*YG?I zi+kc&-;(${RaIYY8tx^Qb=RliEgHUySk~!RH7xFlOTKtMAn`%U$a;TH!|YRv&+}k~ z-_>wD>P_)8G%W6kOP%7LxWqFxnF7Wc#@o<8$pk4|U1CqCoiQu%`Nv%hbACi^qWd8R1wLY$!G z8oap5YpgV6FL8KZ_wmf?Z7F7TyyeSZ-~18Fcj0;=OF~;`EZY6C&7>ymY8u2!tl(=D=|7%|!xg18t6`O`^Dbom>b3NtTVMvUZ znBxlhT`(k(oFFNXQib?XKvE=jm8# ziK=E5yK@MUORAfQwKQ045~S0~HNbB)`ZkVIZs#cF_MJtJX(IgqhM3)j6q^qv_Z0lt z+|MTWEMyo)FBc1LMXLP7x*kj=$Gwm8qpZT2P^Rl+xhp?ij%OaaTm?MUu%XLMhmamV z4{N{<2#kZ_a*%$s>tgin08e#$z=)0|G5R(mF!xH-$EA+a*CX|nf=5b&o6i*#!70*z z1AyFW2(Nayxu;j8;6DKHBhwzB1_Jen^pm zcgE-&4}FxQz8n~(FB4d`73%mrJh(4Xq#$j*edJ-R?gNu)ROw^BxJ}XZ?Z95*M(`9V zeabzO9VfIzeNO!*qTHZJkyF13C>O60|KYLz&p#{IYnI_XNgn7xKjgCfws>>auCz0o}YOn=8}YYAioOsH5y->t%JW5yor)O3HDTpxnwBS zFkmFEvE*}Y0pbx9F_#+)C2oY>A#nw5i7CT4D9}rXb29i4a;Fzq= zI|N@gNseLaoQQo%o%`f#n0YZ}rxNp-#EeVnXIUuRpkd}k@i%DrW({xEFvm|Nze~e= zH9Vx@L&UN?k7)R14IkI=2O1Vwo*9yqHj zY98IVr#fNKH+ir+alkj(&f0ocYt85nZ@%Tu%)ulx9L^bh;={TLsiCCvH%&3}lKPfq z_8W_ z_a#F$58Y%Zl-Au;UUv28=7qmDWGCR0OMSbC9^P%H-Pf=x!_KIw+1AjotzntxjamKK zY0J$=GOwTYACm`t1&^HDHeuI=tCp_1@8ggD$GPFnL;Y8!VFa+T*H89}Z)=5;#&>tm zO#I1TV^>|@gcqaz<2Q!&|9{w8vu~J%ZvWtzipDJZ@&ed{FrR@TslG%UFUM&;EXQDm zt$-m>z5>RA8H5SId|YCVr?Vt}1~!TE#7h20z+5*m>OOh_Vqwwr#IrSTy!;mv)vx&cvgejgSg`_OTZ=84QV>eXyiK2 zA}6a{{9ch*PPdUY7g&On9NQ1;;%suf6BC<0)#j*B1zfwrGWF~5vo>B|IGZ2-{N3y(($Bq@Egk;Mo-f=W0FR}Kue zX+j_MqF9INy9*4}2jDdM$*HQSLxCDEFqO<#;b6?hD(WMqq&qAX&_a@ zD7;j|4I1vy@CFUvtl_O1W*(HzT^io2;UNukoKW)9XZzjdwETP4=S5}ya#!^1>+eGe zhzR*+Jr7%d3pe(QCmnnyb@|#gA39%K8^x ze|{o#?|!6m&-|o8Up_b!FaO$JcWobN%(t_+IA?XS&RM^-6$W&vPpr{5WaFhYo5!Vi zZ{sq(ZJk)9+YPG{>fT9fG_2WWwRmM?vN0Im65gIM7~cG~?U{R$&E30m_B{Dv-KSFr zlFv^pGV)UFv_T^gYxRC3$+LYoR_|C_Z_l)I`!;j!j`ezYvj=N;d>WOXku=O(Ct$^% zlA2=fntfMM-z7uFH8HF9U0k*Q#Mye9Rr>%6HS-bkR=H{)r>)w@g|`n4#ID*0lE-h| zI&;&H|0=8Y-s{@`v1(ubce!e3FCnqlC{n9%`k94pPvWU#Kg84q>Ru7;sbj-({Y6SF5%CvVC&Nc<3NwX%O5m_&JECI4Gs&f*OF4h)Gh z#2moMe-B2j>>XedWk&Nh0Ct1emA&AdX=SemI{nICSMxVp*}La=oW|9<#vR+4eV4el zBK^Ozwl7CoMD2)FMe$W|>-nJEol=ID%17+lJ_Aj(8va~Mo@s4=82(%vC{p^G!BCif z%b|~Q)W>wvk1acPZT~8Gs9<>(rtS=(EPC_`v+|4{KFTq_j9=w9 zc5OcfYmw2c?RjtgIP~PeoM~+zkHSUN5mM=kFh&4z;vsp|<9~jw&z2RXKWA;P`aQLX z`sTRf{_snby;@h&U)`5tyXGE|#4yCHC)OD;XMtNJ-U6F4YVFK=Q0LnWqt@Dh5&dFs zK~K;U7(RpGD9yb(F}?1Wm}y~OBA=r@+YWIZY@fuh!!FeD$0S|~`wEFUBith~1AcZ4*k!z=kWX0CgtpV4%Vf<=g5)I?hehc;|^pQ z?k)lQi(T0`u7B`7XX5{PWa3>DzTLWe`_T3Y*lXC?{W$f1#GJT3)Hu2C;f;G1SlBP% zm>)ZpFpl{bm;D5A|-xgRDChQ!f?cq+^w%tbI>iLZvu zFywy%hD3QqYAx*ngF0!Ggv=;TsL}Fbm$77>X%(vliCx5si%nYizt!?}wCB>(P!jCd zYOb5fqR~jz&UN6ONsfM`N*H49AV{(Ll-y3n40dD;TBu?2^Prq_ z2X|un+O-vKT_5KH&O?e+euH2rOuyyOM>*UAZx`Gi7)46QMldMHxs7xX zrcogG5B+GkcGcIU7lJv`npDhNZcy>}m^HlBQx}P6e<}@hcO&skH}j#^d~|;uMuh=1 zegl1+KNTszuY#fLy8-$rM}1?ZAN6IzsJaC-8sXSOAW7+?ji@3t6PZ5>7uQQFeHp;q zsp|Upds7~{DN_2BdnEgRehsRpkm*|oMT!|^edg9qLV=a@IBPYvKtu1qiwSrZAup=_8PsL|C6wcQ$+qL40HJeO$wZ>mc zEGxT#SjO9-;pm+l{Jb9Te?RMbsdV&r`uUp+HX?USDnvO%%R6h|@s!NRy+!6zahFfB z=bG<3L%c6Fl)+Q)4s~K%-_>DIde;Yc~*ILwRy>HLf7^I_rqKWL!uw?1u%m!3t%`E5ZAzvgq~3>TB6-Z|4yI$ z9QugQ)K3%Qe|vp$2{O&0M4$gz5Q^0JSOEsH8p=+$?x=zc3-N4nEb!QPRVBbHG6!Cv zVZld@aX#dE4@ZBF!5lxu7zdl)5G*}PF3l<16YLtH2wwpstF`1zkh~X*S8t^C`WyqXOzC!`TrH@`wILO zDSfoz6`^=k^kKNTmcX%-(3b%_cK&}3a$LJAQu>s8B>U7eso|mi^ykTXO|eah?iq>t z)VsoIqKqlUGRr~>85fau=VecfTe}OZ_vBF5+Ro;+-F~B`r?tLuZEL;zN*ebaE}Zjc zNImNJl8i?^lO|4+OA(*sbKqfls<5m_^?OD>Ng$s*;xslOka%tlJ_jn2n*Vi7QN{mL z*ACOmW|nz0I@?-croVjD-+_6I1BbKa)BUxh3aZ&bjw#J(9B-Q78% zAAHzdx9zfR=G0~Kn;FsJvaJi>Ucuo6a~-8%w+AoIUE^7`c6E2Dr?<;9xtYy5Lh$bm z1)Ex8`4NHB0sa`0lzM_kby3=CigjJ}Tf@I85*0W-YB;^u8GY=8tbO5Q!E7s-aUz)W zY%ptoFmvD2&NELtKHGTnDW@PS!9Vtn*6gba^J*6w$#_m|%uC39*<;T=aI;}&v}RoL z()XQXW1dR;-O;1H=CfQ=StVB-{oU5XzY8Dxxq0mAn_tO@w==AThW9(pYkSNmDN!=U ze1dji-m#KBxz?nBZEpyauekmt|D=KiZ#HHxzWlPZ)}hwS#;emTIDR+Lu&!F{AG`C| z)8kvS%k6XQxWL#!-`IPMoC;4vyq(i9>n6ju)0nZ-n77kTF!xgT#+{CR?%>#a?4)ow zK79R6q3TJWn8r_8sy#^jfwXd9&2&D zRdUUDh7eiUnd%8t&J66EY5ohtzVvyg@TFRFrf*!=Ggh>cKUfYJMKp< ztewTyCj-8cD_(ucyn{Z~Z~9C2{AS+eGkkN$fo*Oj^Y+g=z6Fcce8%y9#u@S$wFAcH zJUemoU7;y`*SB5Y+5Xu>%j`JYNHkH{{;=~%vHyx>>x!ho0b}rrl<=;~!7EbD8>uLF zU<{JG#~y2+fAmq$o`qu{Fzh&A*a_^L<*S@E)nl%sl;51yIwRTaCEk>X3NU*J1E}I0 z+Zy|YEe*kIowSxGoSTl9rI?N@a9Br0Jn9Y?8;a%pKtpxb+PSy7v z!lo0DJ$$t_$l$21#=it+}=u0k~@2OcTgweRc2#-l?=A068BvE%#;)BOv_pjLe0lO7}Ez+KKW7da*A z<`oPS7`v(<-!>Nz&#{VjU~y2sqa@vqx6d)>lUX}<6)Wk-C(Hnyxq%aQmYr=@&`~zo zDcljb=hX^d|0O>2QnC{FId(?X0>^OQvyqcrA-)4T{^ao02UuwF}2QG&u?TonJ6e@HwY3aaBQqRW->lUmzzpki7A* zV`pthwzDU$zdqUg3Ax@w&^X)ce#K_v6VB%3Wbc&n45$%ZJbA~?1CE`tJ+p~}+$t2W1t{D9Si=jGXK6-be8rsH%Xma6dU+?gxQhwB88J8RILS5!e|j%yJ7;x_jJD z0-@!0%-A&3c=Kt;8vEH+Pn>D802J&c68i^rAUM=N0{%eNW&QP9XoI zvrC|H_U8+;%Jw% zBj?s4d_0K4S?IUBiAu~l=tSnf6Z@IT?L|#<#-P{TN6x{rBbBc%c{j)#^B&$s8Vz;4 zjUD>qna_Loz2&5s2d}jaBnt5digWzM1vT?B0v$OilX7cQ${QOe!2aZY+* z=lyPrhje*ka@-DsylP^(!_97cwQJF?uKm4l zb*4Sn`*X)Fgp%~nmARiT+Z=}Fx&MgIu0sYCV{4XT57JB^I0UP6gMoD_*lg_i=%-MH9>KO(}elu%d zP5N>7>s9XGITl|(5Ft^+_%>VI1KGCUpPh#JLVOO+j!Vv4WF=>$WEI(u2lAdZ-=;pT z(XW=Seai;98@c!EIhr`Qj?Rkxp^V`k+E%}ADZqN6JhrCBI%fbCJQ-~6-t}QqH z&G~a|@Q#wV$udgpvLlZ9bCCzHd=rD4P~^h}?qB9;^FQgF(POV(h7 zV}eY`=Z>#-cSTO9pH+5I%1I@c7#q74tI!!K|%Yb6WrTlGfQ5*V^$( zEoCKk;9%H4^nv+(QAh@LY*~#FLyS}qB3_awZ$e4Y9DZrT|0e#V;kOXseQ11ZT{&V6`$|IV+7rV-5C^`*ha%0oBq@n%`!-ANPU z@eRblZ!j2VHhMD~JM#}+8S-Wo{KV(;W|Xh7oBiLL;V$L2oB*e63%-74-bv+kCr<1M zA3h$4Uw(V-;-R{i?M81_Gea3q6bEhv}jgmsy3_Si}-Fss#`~1X@8E&E$ z?Ed;t-F?5K)(zC!Ppvz$w0J)&;t9RsUE`QH5c`6ex&5!(@e48&pL6nz!MwB&E~xcp zJ^Y0+jkej)8lQV__P`;}fklXa_bp!-=ksO`Oe>gj?if41JhRsNO=)Rw&CHu-XSQYT zXzllAhHSIX*n08G%z=z6w|;5p*XJf5xYI!xkFj;I=1P?1)73~;JtNNjMMA-qm-|uP z+kT19BYuLs>LtDvsh*`nwcr1sc17BhuUb{NIBnjv*1Fc0LQp;~z3#FxC1cRD>|V2m z0jh3vEE`+KnfMM|$ruc%-YoNSdL&-&K&e=?;q!MZQtw)_+3Ufj&c{C(Sdmt@;e|(* zS73|?W%_?Pc&yWK1nX;|(I92#G^WN7x#=Vn|yXeBOn z27}pw6vGPU1RmR1cgGtOi^?(_d#355xaG|m^k&!jU$6R>Q)D8)d2t)2pb|>gXOv!) zu|7KueoYt(dg_X5g zNfVdV)+U)hBC9Rfh;L*5Isth95=GdZF(yWa=}BTjrKbI6?`3M+-{c#-K&yoDwv z-s(zs;w?1&Ups8)V7KyLOh;j5$J;l&yygj~IJvyivX{0^vW7my4f}cnfT=Gz1cZ=Z5Q_VEvvM&`QpN~i|djniVt_<28Vj% z5uSmboN2uiG0(twj!^^aDCTe4I+f~str!qAM`#O^qmOi9}7;hf}Y>TTiI#vX1{3dN)MIfmn6P>!L^C|e>nbq z!x|dDGC%dQd#wX#>^TSOj9))yZMw`TPPlBcm3W!)>*uV*tBr+;5J+5Rgi10)Klo$a z!#T&d4&~kT#X_sL056Wr}S*bou0voq+XQz_!roYUX(`bK*XUTTw>N`w3YfE5%@caW4&?*tcZzl}cas3FgJ#*`3&j5nVFpce*rQ1Dl z-u`*#i+3T&gIk>M3^oSG4@?bO!Eq0~XJ`4nlRv%i{%b?t^BSLcx1phT2qT+!T%&jV zgEu)yGN#-8!2-O8^0zkj%&YCGx7~IK8NC-}@}#q=#`yK#>bj-zq2L7rC7ICJdd+PA z6El22%s?yO%$E8_|KQU{>ux*8&bTyfPcW})nbG>YTs!{Yr`Nw>tvuf@iL3Qaz-B_s zX#2h1XT82--bp9C`Mz-2@_H`JOg|n7@4jr>CtkrcG6nP8xyRgiKKV=}o^HldXMKQV z4;e%EHau+Q8Q!H%W1d+U3guZ}J8`eSq`<#AzaZl)b>a8sj4i&aHtk8r%;_g-Mu z3OzrBp2Jh7d*OJGrgD3nZGw#$~&$0}nag3ml*I!!%!A z=-j&Ib2sgAY$FeCEziE!o*(dzGwQY-pEneE?A5DLUiUjlYvT`n`+t~c9M~okeH*HG z0-{g5f4VO?c~7w5SaAFa?*;hi^-$Ofo_FGhlTQRE+GA1mQ&+A0S1a*Lm|Kn9(#*8d z+-(_wp&#YGJhpb|aPF_tLqkvJPD$?%zu4C|RM$4vHqZ!tcETPzZUBw&(ahc3J$ujy z@haU%Gd+)b;C%4SlMinV7*RWXClk%=%0WgCT_3 zY#Qq``_^+*T=U$?^>-rb+{5v=|LEjEQ80G_XQNZw{-zflw)Yf6B(dL3Vs*ax0;d(X zKYVE8K;pOdCcGLoI36WDb=9gvC|q=j0}na}W*IwP4o%&IK31`QsP1dePAw>V_@pVO zD0ZrEovdqoru@?n_avZFbN3!zvgc%DNx|}j#?|?`%i@domwn@8N&9 z|1rBcgbG{NZiRjjzCP=7KJ!26ht+q_BHMhFc*}llH10WBdCy7n5xUL6la}Y2+`ja{ zzU4R#oa*scF1O>%J@m88W6ivm^X{n~Ycz&m#G(X?%!~I}RS7s(33v;9XmxL!|ID~NMz3dmeBBSe zyRrA=<_%Z3B^AGyG}}u2<4MuM0^YpAl7hk2`R4zjaMjxa4H?2^vgUqn;R&JDv#!~S8|@Y78-p|y=$%^11cJe z``Xj1es(h7z_T0N7cdK6PP4+{q&pJKKeDZ=4Zia+p23@tIz1u$^Iq{K^0?$|zb`*I zBlkzCOWt$>+37XS8CTzI;XMbT470oYx%Ii$0k84wq#3sH!knk#+>LyRjj9tzc^K(y zC(ZIrDotCK=JPd`9tv4aGp(i>*qK#-KF~CywrSRmfekx0C*6*h95gKL+f<2xKfIYQ zOlVKSo1#nNpy>#c@BZB~fL)hZPGAqb^M{U|{`{6b7p})f;qkPARqM5b3~YC?R)0#2 zWbbhskKTw`N0f~Dp;jQye>+Ywi{j*)AER|Ps?Y_-7!6BxH?Yu^fxR&=31R&p-12z{ z9>FArD*WQ?@1+J(wNFbRB1sXS}igvF;I6j+(_aXxa0XuPxzGq+9cgEbo2J zzOOsS_CIHhDSC64le;@-&3(?sUCuN2Itwy)?s9BRV z<-LwC%Lv?o#fEq1pfj+z==QKvk-ycSVtiyzYj)~>T=@OCu{s_jS>uR$}&D_AlW2L63W zTmdVyRv4Fg%thFRWiGODW)62!G2Grwjxm#A_XiCB3d4JoV?M+dQ<&-hih*y_yL~VZ4Nu5!7gM;-Bx}rb-?$Xk?@WVmk=DTlS@9bZEAyU3`z4Odk=fQQ( z{uRdlPZ+?Dr=mUYr0$aReIci;2gg=eFyBoM0(-k1pRdo?nE`A~|MHMQjaJu}4~#L~ zjk~wa@!#{R2(wLw2|;c>1BAN1jK5_;r*T?F?W8_n|D--UC$P9E=8SVcmbyim9#5GM zMHN6%CHuc|R}U+|>*#_{@S~1>PUT0P+A71p)Icef zfq@d(c!{&-BMuU_|1!h(gCp((m#Sx+?PdY?&WLZ8Gnl$%yIHp?$vYFP3&Z~2M4!jg zTeQZkqw3@}b;nYkndTH`E}8CBPIrREj-BmaT;yMTp;cw=L#x$=Cc>;h-GS-ZGs|6HNd zZ5*?ifHf1G#;+K+k9X|x{R@o7tBnJnai-*3RW~@I4IWASq|=B(%4%%Qt$!v1+Jc#m zJ-IB?Su+L?@=!6V+%0=zqk}`f#YL^T0eCO@@MK{6m$B6XF3c?Z;N+6`PX@Za%;q_t@gXMEikT*| z@XkqQ;jNP@3sqM-J5QXnE;kYviBZfrEpe`G+9GYW! zpLZT#a-f(OSh8Emhm1Rp-7#cbJMU%1mF9m`zu*_qip0x@H{|9& z63u*sgVE2LI{kSxFt+x>vqMkkI8U1``cVH4`~>rQ|0wgvQTOiA4ZEWEY&G?0*IBXs$fs z+z?GF+SC)mJY+#Bq(JY%As%DaYbyG&*odq<_x; zd%$xe2DFpp)R*$#3V*QRZ@-N`lexR(5Zg+!b|ikY(cL6}tS; z9edrrzxEFI{^F*HJNS%)ERL5>A7{$n5zX8Y-G@g-9$_|+mVYP4`|;So&)lr@Q>C;_Pc}3Z2`$>9O$lsP3e?ueBNN%f}8mFwAWw0WaEHf;%LQ zwrXyf9l0!gLo||b`SAMjncs=Jt>lVtM{B;#qF0>x-L{2nP8E&c#ZtMf>!a&EpUX}e zet7)0?R@Uy!nTCKES&6lE=vs5m%n%;?qA(P!z;R@wQTZjjVZNg@|pYd4~LH};5`Z6 znERi+wxdtQ1n~f2TXRc8eQioI&P1(q_bf~M@`k76^*T) z(#2J?=Fgiw=fXL~c{B66>Iw?$>T4QnMp$}2^!&WSg4$_~(?&!V&M7OdS~zdcf`uhj zbBZwuw{51Lmsc}=L^v{MX8wqUmy}e6BbUrCTUc3ARW_%xq#|5)$;>=DlqXGRhRT*q z&dtls4^f;uXP!=|nj5}oe#Oj!$$7?nz?3=jFeTs25Vl^-890MIMP{fdDJu!1Nb|yT zOJ;^DW=|@}%b%KC5E`Kq`U{nxk1|;k+`^dk%PXj9EbN~HW#|_nzmPx8Rf05*Q z6Ny0w^0v6y{=5#(^@*-|^`m(n>=<+M6bcBth3vVpT*b7OzD#phT&(PBMN(@&A57h8-oMH6T<&*E~6D=j8wBCeN|>%1ND z3`7Q9Z(b|WXOJR7!W@^!kf9e*L`aYVa2q>VL8e?c`sb)`IwJl54UvKV$zDY2?;&!X z$)~~ZdSUMCsaCE!Lx+X8CV{&`u~chlTX9+^@tlSoy^72|2M$r z3-7jU$hwZtSvpMloTAxA{p}gsg`pae+lVRmF)p_U@ft)fYc%Rs%Xt=ByRg6Syqy>)b|M)~$#P^hrJsk@N0FWS~ywK1QAGN9*}bFdv_#{tn`Q z3jYU|%YBdfuDCLA-(wk=mLRT2Y(~_!bTybSB5~du5VgJC4OW|9g4N~)i~k7bGqGA8 zpeaAoB1A5iX(r-Un_5NZDkBDXvFV?+k7J6Y>UJLw_KJQwShsa9n1TMuI&Z$Eli6mt?uB6W8L@20#hA|W zTx;oMweJC+EH-z8bzOc4=03)G+4e>W_ksDaKJ`<*_=mu9lC^E~$8sh>qs_%&ZErPT z2HKOE-Hyn9O#7m*QAD5(S=-Wg!P@^kXxWg5!FD_1BVetoKJY@($52F|PqNzZ2iSGq z(<~cu3T){!*V4%wMBioUWM*mqp8!4>PX4oHL(UZ4kBa5-k2dGAk`Y)ovbM*T_aE>vkV)>10;Xc0~OlbNV6EjQS}6Z5!uMM4$~>ee%cmbo(x~ zY{=@L?VokD9dQ*{_mNFt2Kpq|BHfPoj-``zn|=(QE;jt3dIru*9*>msUSjFwfaq10 zPS$;VIrx0Bx!1BG>v4*0zFcg)*of`IonWnpuX5ueusq~zkg_}15TY|<`>P~Y8Up<=aP^&RH|04Am&@a`*6rzF2DQ%u)1E2))1G|;18vB9eBVeB zfjXJ1$?|*)F(~{4qztqn>#^WLu-4DBU}&!tbNp*U!ri zsZBBVRVUlMadIJauH!eMv0q^Me+p)xJz2LYe*|tCG}_>?i~c?bPlEREr`)f#uc!rU z|8_Z8w^#fzWrp~C4>r25dAU#omVwN3?Cpr-!P?iwA1_qD05-a;Z-PTI?+?HX^hy2( zQu>TPE=(5vE38Ze+LN_xYb>4IjOq0Anx&I37JZV{{>fS=(<~jP1I~ZgU#&;Hn-dUN z2C^Qbp9X7t+XH5x4cUvx@;r~I=f>>AwGTW6TqibP18aHW&s)wBo1NCSeiY2WWs&od za#?H-+&#(1z*^3+EDQqe$y#Rne1_9|5uI!|)$6IBa{>bACF?oQZi)!h$$G89{pAaY zEW=4C!wBI_u=a0X05fo2^0`Q9{}pgRcojG-{2;i0KLxjlKFwM$vM#F#tmUZ$Yn$PD z7Xz0&l+V~%FM8FtcQk)>&|gz>N4u&z8dlU-)i%`BwXPWKCzV_)wW#Xss;m8Uv#RD5 z&G<>Bmgdfe_L`Pls~F~eGkkyKGYsT6Gx|M98S5KbnpZWnSGg|%t9zN)RI{SKrJ<^` zd3i&7Y}qogc}3ewt3;yKtn6&6YHe$<*SI4;zqYQWxnafe=Isr2tE!eSTmC6i>N;DF zTdtX*{J+sygawR#eruuCO*sxNSBj&Z=pty#<+HOu@qAe$8BHMak+c|FXz}9ozWNAOg=~fGhO>4H>P)wGBSgmOAX{H?w zK1o|rZ0aCwDK_!=))bpIu+fqW<50m!78#=sC^dfxX`p{#8b~mw0^ppu z<x0oV<0Bd&*J_<|Qqs@f4;w&R;dOxriEgNzK616MKDkLen8&PS<74 zk6Z5TSneL2>v6dp&eG+s7Jo=g=*9$HM+)liYOyPD%{&_iv17Sz6g!?)GW5VshliP0 zf8U0kGWE7E<4!#)y%@~Pa!zBtJRIlm7|uo6CN-!JUY;m(+C$YCPKHK*yj)a&2jl$R zH{2akhKUL4V}G2#jdd7qz;fv?6H)!~I*Y~8_1%Wb8#PGz{uSphy#cp`qaQlw z-%gxE>#!MJs=uXi{t}w8eX;Cf*qm+oTNCFm0}Wk=&uo94asJ9Mp0ZoYH_`HUQ=Gpn zTwn4MS%a33zoV_pY3ZG@`kRD2r?LIr7w4}M{&ctklly(#73Z%B{>H%p*O!+o>W{Z> z?Dn!0;}SZYVf%YL&R=)8`;9vK(B`(vEHweY9I3%0*M#QA#|{&7e-6Md zUne>Xxa<$KW8iOtD>L7+-W`4^22VxgG}hl~0NdXt_|r>hOz!t_GVC~yh93CaAnk>h z!|LzzasHmbHLG5ha$fZ@6`)K#eG~HNJBq;^4&*eJZ!y3w-=Uy8+>S{msE-POGAE3? z!Q&|sf4qF;Y8eZ=Sbh5Kum?LQUmnI+`Vn&z{>)HGiR&bIQi!5kXY=}W;mi0O#* zcRA7`MDDuGUxk#xwNLka+s&H)+)r{iOWA7mw!1fe_!+>U$^(&rJ=(4X-< zT?428IxhcuT>kyId^9efg!79$_+dLsLw}foyaxKui_7!&fd)>W7nlDM@~ofVqJgKO zKW&PezAi4$^Fs~v*Bh7rNnHNXxcvUO{9ohp(YQQsd28VEGUM_Sr>YvS_T;_`Y+oy(yAzPRc8f-5-w;DAt|M|H5ytsU0 zTz+j_z9%k!XI%alarx)s@_&lUzY~||b*BcF*QXbJVCIwJ^5f$26XNpc#pR3R@{8i~ z^>O(t;__dO%ij=}za9Brl=E@ZKYRgS<3L6N%l|}N{`YbDSL5>U#pP41Lp1$m#^pVc zx)mk0RV&*tn%%(6Vm#tIx2~q6^Ag+$xx@^x$E&k&PoNxAF+|^BX7^w$o&&H|jjio< zxb@I#hV(rHhh074@(SEIzzoJ~Wpmx-p33EImsEzs<+EB^I~u~}?(cGRwszvC06vJ= z*ic{9P+PTP<#JDD0}9kxBR2&W)wIkpH!|?CU5u7@wpX>Z!driC+{S9ao72&bF*mNzV~Yg=P|sd0HjM^n`mD^bcSe6-QC zy0~Fg)g^EiF}H^BoO7pTOwR?pU*O>~>zW!cS4YkAhWikYuAi*jAAt4cA_;+_6^pP zTUpq-(X@5d-Ax-?LR-fb?uKeuWp=Y#%T-%VJKCAtPmRsORj;b4>uknd)|hHmv8}ze zwxPYD!(KJFrL?1q>WCHNE3M7P&Aeh|ON+TLXFKiWe&AsTHSlgDymh+$)+)4Sx9@6f zsabY>Z-brRgWb1d-pb{3R?J_~FstcuPu$$i?bzhUbyKsOThJCg;Z@7nb8SGt5!8PdKzk$;eK+4o6fy_55O{58 zbj+Vcmg8|yb)3&|6vLqd1dj31{xHrDcn+sNc`P>!o#Q>^ZY+ye;D({|RL|HTWzcf& z2B*t;)31bS`+_iiyd%s<>Hi_j^PIqhUX$bQkMiOzMc7w$#61a{6$&govK zvYga-&FU9@De}(wwD5TDl6k3-{i6R^bdHxkCd}6?UKCD8Jyc^JM}|@UC^|K=U-W;9 z&h1%Gd+{F?of=t}+eDip{6k2>JS;yovcHI``>2r7;!G{}6b;j?1M+_KW^C(OKubw?-Sj=F$Z_t%vW4PK~VfaHnOzmi9^bhj6#( z)X0A5)!=SKXBPe;JRmmR!hX>o5uI)Laf>&=PV4y%(W#NOo;T8_2>%fNDmK)}TF;x1 zcZz9&ecb1+FEz4X^d97$5?WyVNNlK){i5fK&ewOgV45?V*61rlr$+XRz7=`rLRz2? z5gTe`zv#0>{~L7P)8w|`eIJfVC~w0wrxgDXT1BTu_KV&n`bMO^nC8sEKZGkq?-llo zemnBcMfiun@e3}C8rd)UHqp6Vc3_%wF|9FXFFG}{U-UaH`};7>DWkP}UyS~#@gA99 z^qt7_8x9P=lzFL<{i5d}ug8uoGRndbL{uJUaXOjD9qfxKmL9M;iHzwC35e>4d7ZZo z%-;f{?Q&t-wh1FKuSC&?zHb$s%Y0mzW!W#xGX6z41L-m0AkqNJLO)zT^J*118=NKj zmyz;OM%u7GDlGkK7N?eFZwg0{~GBYVXkixSlb(?ab9XL6rJmGp)g;YTf%u4;2%Pn=+wx5(U&5xHjBlE8d+^pXoLNN=O6*$ zJzx~q=zRWx?VI;>HPD{nGQ{*`cY2L5b=)>I`hQ?K&sn@zn7;W~GUw$o^MqNJbVR2D z{}7rGX+w?d7ySy+>37N?eFM1HHK6}Bmp+;7p zJHXVrPFaZR^8wMRk=19mW%HQWP$R3&??gX{^cCSZkuq{w?;y=V)MKAt>Wvy%k9~Qx zk-9oVY^ag7{8MOCiGK*^i48TfU-Uxcby=liLyfGP$T;uwV3IWwfj0anLEGvi03Be&mpe`r~9ekyaJI-+wH>i@uV<) z?-k}U-wIITUjdtK4Xyz%5gRh=$U*yL_!1(QMUCu-UWU}vm9*Oiv7tuR_8bH| zm*O8nCnEg>h5e#uA@6(<{}8T6qzyH)U-WFSo`2pbHq^*^{+UCYQv5?O$5Z&BW{#(# z=OOQKB@muP=8>DX}7XoTP_b<EQH{ z_=mtGU_;UB_!M3y-y>=!)?d9~RrHq^*!lTDjy{6n}Ck$$L={nhw~kb~&d z7&LtdZKyqf=og*qtYbu`{#kGY)|Vs9dQ|2#HiNFH=@6!{prwm!H&%K_Ly)A^nJpt zv-gBKhVu`LKeE`gw|WQ&!(m6C)X09(Sq|#skp?l%VJC-hlITHUzvz=i=XvW?;Rw=V zVfxF$JWeD2AzUIlHL_py8qxV`8lU}T8TgDI+ojHXx#-l$I`0*tb6KX{E`tHW*F>jA z_KVJQ4Ekr=G2?__&ij4Q`N}?@-Js16k#fw4+=uiL;XfkHgI}kKOG3XYIyJIi^u3n- z6iiclKI=iB)W~XoNOYFx9bvYge_A{YdCpsdG)d2MW_EF+RJvFCptB;gTrS6=I)yo|*)2?) z>n%3pQLyK;+dD+(xY7L<7qdL);~&D)qEjR5c`U~=xLm$k%4;4npO5~XFxRUT^El8L z{!4UfWWVTUtO@h}9ooCrydPN1*IMcS&q&KKzxK}o(W#NOe=es@8vY@iAvV;=e&`9{ zN<=LipKGCiYGf^&8ApQ7b(t?V3z1d`Q|B`-oR?f9{C%Vx6QoY=5T=b8M}oc%+Etdm zgym_*KZLJ~PL1pr{hOBkQcQDrB7ktW=+wx5=zZXaMSl#b85fdrJ})}kMm6kopW^c~ zEHgE-w$;}~r#+uRrVXE+spq_3!9N5q^3>Dj^wzx}}&)uvOeibQys)l7|+1lXOp>u@0MW;sg zi~bAIIqy>zcfwBR<+D5VNsX-Yz9Bk4kI_YYt~kQGqEjR5wm2qw5sq(bF-_0?ymGvw zM%Ht`5u($+oA$C_^VuMlhZkYJ7j(-UJOaX1Ek^Q3c)okkYxe?Qx6|{DrC!$V` z&ldSbFA;lw_G1&K={hbDof=u!ak1#E{~p>0@DJfK(W#O7JC{k|1VraD{FC5NKqy8` z|C~Y3FN8Vi55k<+jH|$g*Ecgnr>lrCbuM17-7XTH8dC)NOsU=+wx%t%G2v4gV1C zM5NE4uwV2n{*gwd;r&xTt#aR}! zkD@(4oibOL+wfB1Jn&b9xy`>S%(n0~;Thmv!bRZ!6fOqy`A7O^n@Yek$gH0=!e!9E zXX)F8**13ySAu^myae1QycGOb;c9T=@RtQFFNm|==z>3%ye$JbN?{+ zuc4CZDK=>>=*qzqQ8T5v+!1=Hwp8zOt%TsXA9=nGT$dUHL{kO z_qlc5e{M1RKGlC~@qUZj=pX$*!=FT_M)pJJe)l)g|B3W{Vb%xp^w0j}Lt&PAnDi&S z4oDWJ-U(m2E~7=KM%HyX*|HA_XCpP&4pPru^iz$02$RHy8rfe>74Nu-ehJbU!V#nw z2(vtEVdr!hbI(PhQzQFDztpm4|Eu-cA60+K)s!LYVd`!aSE8BOC&sDm)&X zDa=o8oh8iAapei~xWM-e>HjjMms-p`^{*oBW<8(p)-&G^q)v^j=Ra#jzZYq*#mv*5 z%i1aY64DnfW?pSxvv`BG+*Hg@8){@-?iA5^{5emU*G#N;+E*bh6=uC{q)+bD2<4(v zBWoL8YT4Ha^Vqe_(pL)exU>oL>pib-(W#O3p4UdpzK8ZwpW8&IM%MM(LK_)R-XS*B z$U4saL(y4=t+eMrGQvZmQzPqn^%J7^qFrsnG<~k-MbW8|^|_jZq8~>3ip6}_fOX6I z?4_R+{6lzK^j={31Zl+5nWs%P(l1*4Wy@v<%IB%~vgJwQLQU0xKO8d7ycH~n}yk~?h$?v>C?ire^!{j-?j8=^1BlLQ{6pX_N}U?nFFLE<>B2t*4)xN88rd)U*F@ilv`6>{Oc8b7`$eZl)_KR# zhAV-<^{0PoWWVT-h|c=RK-6d69u=J$**^>a5Q2z$t$hScpVY{Dtqt@zyck3<*O)Ar zupc_d+K(acpl@J!AJMtept*nNbh}KS%7@8fe~7#W{}A>g>bx(KyYUZUFQW1u@>i+4 z_lwof6Ueh&ZA5wc$Wn%f$=&#e@DQT%17z{DlPvS@Aj`b$v(&!V;%#J^cPm-eWeZu> zh1*y4O=S4*M%gx4dN*18tR>5GyU3h~(21zm&TZsw{6lC$)cvTMEM+LSxQtB42&IV5 zI)i3x$GO_&BI+`4Az8{Wh1`vQ2ziKFh8%J?{vl)|s-G%#Hye0a43#De5jA?Twnb_K`N(AbJvX-j|^beXkIvZ*z|ZI(@Gaon

    Wh;!4|4wVy-Z4gv~XJ&QRn#IJuN?w%$k;nBjc?*Rtj$qikxDF7>!dA*{m>|}0 zn7bNTSc^P-x*u01-6TKKrC+ji!~H0?(LQPqHRh0Q^4f*Hym{(=>*R+#u9wMsudu}t zOb(Si);o<1ZjpzVw@&h?1LO^eVaWZE3~^|m&@x@lux$Q!uw2>v@6*AtS^w$$Zyc<9x9T4Xo#ocYgu)!~ z(02r1xmG8+Ll2dMRa2ROSnr#9h9yDoVO)njOmKZqQL-q@ySBVly z@Ar`DZrb@=@G!o5twNVgir=6vQ>`%#d>0xPLV5O$X_iDH?Df8hKsOTC+k-Ag`~4OQR0a>dKNM~p^q(?f1EZVqgyN(M|%I8tVa41_Uk?2iI^jbWVh({#EmCWXhX$#hNP~Eg5`dj9PTxI4j zU|IxoMKG-fH<;D|y)l36eD=`J=8re4u5AAJ1&8l*STLK5aTnUWjB8=o&n0>4oBw_e zk8zlBsPW8nc(%h_*PhPDc?KR`cj*6QY(B`|9>cs>2GfpgZx6CYaR7@_0W&c?GlbhB}WtSVxOzvvZrgmGU!8Fz@tP+cC1R z7J2w|f2B$~TYjXwt9fOuu6vDmj7%OKpqIBqDnnnr#Cc5jqa-8OYOS<8^Q+~c2 ze^oi)qh2)l&+4V?yz+g$oL4Rkolnp6O1?+g-MmtJYNou9JvEaW4(autnpIqIT@UVc z-Y?pDH@Jq}^YjC?`R1~R*-X1l?ezSy9D6Qw;Fzk3->4mO&!BG49A>IwM4z4Rbs1Dp zb%nhy?C7Ar^`B!BnEQQjqz3~6HUGRjSXDGJ%|9OvRwWOZ(){xYJhS;{8?Hk6HNmR< zb!w55Z2oywaBSB94trd_A~C0MZ8_H5teaknT?jzRHDd zKzV_0IeT-Gad#U~+(cIM+P=1l1lFS4UDD42G;Zp;VFca*>1L9FUBf7(i08XzwpcX* zF2)KiMW+_e@AS?z6}dbl0` z*k|11@V6X(3>@SBm&4D4SzHi>vtJ^{ZSuK(hIh6O5#|C>zJI69P|)H|aCnNt%wdd& z(W2qw9S&0j{zSAfD+}$)_|H>cY5o@r+nU7tBBqM2ikLQgZN$j?RKzr6(?6#TL!I_J zFdqJtWs^U@#&Ck%Ufxx5qljr_khbOJeM9m%DFAtbS$SK8EskLF6*-t~8Ce+b zy$us~x$cD}fJhd$PHvy>Fx^m>%a3%qUW8#^Bx7*|lcy!G1`x@@Hp%Vfp@Ul|KjaOF zVaQ|NXK@6RLAo%XcOC|*FE8&Q$+LPM6vL2rqYQEETHU8eoJC{=#M~Bb;~Sxd*xj1N zUEv!v2b*ya-MC%_~{ZJ0J=^9K-S39Uv|8Cv-Q1Z^>-_|-P z(lo_bCj-W`LtNM3b`SS20H($AjBA3=WXzHc44jPHpI{px> zN~%@od9eFQZ|t9zr$5t|3eWEo))$1xVs7h0`mbzGatCr(LzOMjQ7Z@AS;D@9KIuY6 zpWJ+{XUx}_h!u|faAXyU8U7^iMJ`fwULDB3Kil2=_R@MoAGZwAx3dI}$}OfV56Yad zj8+D)!j;)!Z6Re?;2BD53tZT=0jHNw&L9RG;zd9{`K8dSWFevV@7uYCyRI9RfNpdNUYYOGt%+l+ zU1wwya_%2)25cxikzRL`@J==JI-G;kQ9`r==HS*E@Z(t?X4mO$$SuKLA8!o;)v}m; zh%{u#=GI`FTNCzT-?j7LvUyT{#5{wM|7xB$pGp2>#cy`_z2G>&x=h&0em(wi!1x)5 zZ+H9;gY9ApTU_pb!vq^<@!hbmXU1vfKgMCk!sZ|9pFa_8#PU2;*m$0G{tPi}UTZqp zL`RPof5s-zi=DHkv3vfnAq|6;4ktcgxVz3%8TBg&@>sELr;9O#A9&;!@G5^qmkvW>pb-) zpblf;#)JJXPO}O^!4n;sauCi#9T#TO^=2^VDC6uQ&755#@1Ikc!W)!FIWQ zIUZ3t?Ect2hT-lyPaQ3JmRCetksgb28u1i8;p$~q^VAb0@26>$@Ne?4bqO+>svCZS zJbRj_qVvMFFfw_id1}YH)?Un0CrxOW)LR|!KhY`c`f~5HI?P_+x8}DLl8qlM)YNV3 z|McFA+O;S6kI!w%CoP4f`h(A%TDJW!&+k2J`~N;q9s7AJZX=$Ttod-A^q-ri|J=U> zN4f|N)I4<`6;d0EfU{6e8`T80k+4D~sY%Lpviv-?7Vq?n zz`KjFY~M}tfZ*2`fq4@@(&npu*ccpKxdnaoB7QUhyaM3h$^CI0C8KyRa%$R}_vdQw z`t+~qeXH$ByEt>I%kJ{wmyjPdLbYUlC@2;ybe$oDKQ3>au=2Vi)foqcDk!Of6TK?% zh7HI(9<&#ERK~bSC{TBESY#R9!xees3%qUXmbZ@WSa!zPh6xj=OqkrzFn(!!TSo^U z_8oi7oblsYHmqK=Y<%zM&)oTO{@lZ>@H*SaTnMV^RY8UQEU@krX{;wvhh6YIy$laN zntE51^?^rbhq-sRQ_i<9Z;Icg&8D$0<&NYmk#6S7FZrwOwDOsE2qoQ5x3dg}1&YhzP5&JCtxfZzesd*DxZ0O1eDADQ$I5dL6Gs~%4g{%`2LzZ&;S zbA=(UWTyAt`926O0G)PP#O^X+T0u?3reI|}v<@&Wi)lL;KgLDi&{~9F?0lVh)oXEH zehKA@7vzIr)fMz%8Jq8ZN;nrQ@IHqhaab_pXIy4+5pCGd%NhKb|44@qaCof4J9|IP zxXI)k<1k|i^FPVqB@QohI9y-;M1y3k9)=2=9FFHU|1H8c@4v+1DG|8%I))an}k!Z~MK_dB2go8U-THuStY!WRYca z2IM8qZSq#i&oIG1k)xv+n3ZFru$Ond`h*(!8Ch7nJiNSzB&1G$ z$m4nuhW%a{izAqvDS2OW9tO84%*%UP@@Rv|^J@|xlAAa--=3^U-K`;9--Yj8x>#?P zpAj-Jx5!ZMM*k|lspgPv`TMfN1pi)qmjfah-<@*%a;#D(2p{EO4bAF>_sZ5r1(WmD z|7-_DGI`jlvW(`ES$S#>x66IsbJec=nw`nZ=KRYxtn1Cb@2Qgy?zMjYx_y)>6>3t* zZD;-bL-V!jH1B!3KHrC}McZ_j#<$dIJMr`V;URwdr}v~uL1jq>3@T7}n-uvAa)b4s z`?UV;85Ryx!CUkHU#ZeGbN>ofK7IR~ubi#SmEKbq<|%Kub8`VW!Mu<|j@@+y8%9_8bJ$$+LalJfDPEXBQu6mV7XqZ#g3+zNZ}A2dK; zuq~gkQZa`n0}C80QuS9!*(eaQu7o}&?z-|xPs^)#i}F-HInDP|@+hB@rgS_0Q^8e5 zvQd5rxLko`T9=f6DsT>HYEQ~<35)}pHYVk_0;`JCsmo7~ z7w%VVL+-zT2MlOxS&@`~<|9gDP;sk#%5Q^zSg{$NFH-Q~#fKDHe%Au^ST)7Nk@KbV zh3kqZk*6G;_l!d zJSDui_!jWv#9fx`h6Vf3@JFGB&Q@we@mFmQRnYF?;LAe!tUMvrkC5E#d|;@)OX1~5 z=f|pxEmXgokknCC{XA2P)3=>L%Du%ySPkR-@Tjeo|nYRecR1Cx?)^)d@K`B|kxN z=2deDZ~19~?YQcbkk%B6v#?r+Iwa-i=YOl-|HM6LzU3F?X|i*3d#pjimVBeEdAU7) zOW1qzGbHbc{2sN)cwe4})sy)>_9E=E{96_Fo4o36p1jpZZV=PJ0?jZ~GzD`N9h|YE z->INs#2Q#QN&mZ@rDD;196MfiT`q=)s5Gk*k7C~{kI*yHXu=(oPu;&Tw{rRb*&UqQ zu7d4(hH$^~-E;fv8dir+ZjXSI>U-fDmLr)$^=#^5&m32}O36^}fdypld6+7FK>5Vn zDg+$D6=(=Jsh&@qgMy=?dL1E?a+4*kUs8p2wj#tF?)8Ws1n1}yRKJIMU7nw%@T7VS zaaM#2RjB?wj+KF{s`@DMwkl5_T37vc;;arAcWyPu(3GE^pRf4GRi6*r8To^h(uvi) zL@i&Fe@fP>>VF~5+Td7M{Vw9P2FKae=fT#Ne~)srsd`@otjk{`$Hmn@z;R|s=ep|q z5YQgte7t%Jj*j5CwVJOAm9Gzu+pB+o=ncVfcQxC9%g+jq`>Tf$XJe4|P*TOUC&^GD zd!}wu4erX+eY3guNcMWV{M`J*a#ue}CBG}+r23B}uqppz1)QB!ZBr01$k->Tnx&G_ z&ZB$pr^}neZ8)4ey!`Au7i9P+$kygOX{D*|t41AS3`_Rm1`N$j7a#wD1@6LqxF@V> z&I#U=^PWMkh7uGy1ETgOs%4r_p-5#_!kk%cG;5Zyr_bkt-Ib72jM8nrHo!vH>^&IuH^bFc9S2my|aDbTNO9Ge%+P9(x1-5cacd(PC z0uI?d*KIK0LHZufDJjE7hmSh#ndK>lF1yYF{Chs$8aDv>(-3WOpCAXE3kx zaj?R8wUhSVaQUiXh}0w^!DV!S0`uV;iLW8$yzw39bi8;qx>va!rDvpv zzBcil`1sBEj`i_wr!4A3R=2Jc4vit*Ww=+|UFg5a6ix(+{y~MYkGeX( zA>XlV^|IBi`e5Bl{dOWPU(?za?LKPiSl_&UdD66I@}%abmJKVCrnVI;^q!`vY2(sW zC{Br4p)D)e@hIQ3n%8Vt{FMTb|g(3+x0*0w?1s+F^KEt;0EUEaQOdFxU|TYA=d_G>k@hI*QJ z?BPc@%|GJsMe`RNdBPD*3+2DMtwp(LntkNFBNVZ{y|qngEnmM(vT(*MtdmLMU2<5n-`BNn=PYm5mC${;zU_>r zHO(}aj^)dhQL;<><&vBeT6xo=d2OvLL%144dVi(iYunTWo0lopYMLNlBGc{89Tf}I zw5+48X_X|Zj+)jTtip5qrHO>g8nU3SK~q{qQMaWA6N?+}K1B;%BXYy7YJxX}OOdv@ z=8mQAF6~Hfo7Ux8sGM{7;nQmB{rm5llB0Fy*oosB8pcf+J9)y`l?P2}nJ{I={<}EmM zLf;uPk34iD%cLR=`2t}R-^lcjdA9Ssw`Y9de?$M+s!8^a?=9n)I`WidZw*q9p3ivJ zaMDp(xV|Nivao{e-GfRFp|bGSu;f+N>ADiGk)@-uu!FYbvEz5m_6Te0#zAV;(Lt*~ zA9)`OlpS)DK14O5@SUkWSyNlLQJ@?HO%X!~2E7n1&h`Ma?rwX1!7tTbUs|>%W3SkE zqbHNM*ff?qOf{Onx{(Z@@9+m5{+PpGb@(BNA9wiY4nOVi|2f=OU5Djipu>AR+~DwA z9A;U;;-2mBg$`ft@K%R87ue$RJtxE49OjHC^MBl7)_KkUcMd=2Fl&3pQ|<65hi5o^ zjKe28yu#sjhqpR>lf$e#Te@F&_*sW_+hshgYZ!l>!xJ2y?(kfP7dm{Q!)q1buBKGa@8>TQ)lYJ!+3)HkBjbDbwS_3Mzada*0IpnL3X1Iv{mxz zWFt>qSSFA6!N|uCLO;h7VbC-g^4$~PEb&+z!Q@1l34lme-md#Uwkdz;Rggb5=PZ9G z2zz-K%l)se0xj(L7^hJ-G*k_b^YV}<)&5Lgi?GEJOlB(Z8_vVvhAw=4)xgIPA(HW} zliSzxDlI9_l^^MHy$Hj;NXFs_CX*$v1`x@@Hp%Vf-6nZ;@WW_;Tf=F2fjgLLYZa;WKKbc^S8U?gevc3SM(wY1J3Gs<9>I}j$hPwhsIyD*1+`wOk6c>z zKI-XYRT8%TbKFZgUaCSwgrr0AXGPTe(Qjkr%P+?>U->o_s-#0QTrTO590E&KWw~4h zG_|4*$$^TJ>5%ZAHYf>19g^?D+(n0EA`wy@lHZGc=Q<>}h%wV4`Cnp19g;?{>5%NJ z5=I@8&m+!sNLI@~(;+F7qyK^WGaZuf(s4%}k_IA09THAEO>w^>qubu=klZD1(;>NA zc`_XmbSh1U5yDVs!@kz8aV2Z@Vqr0k|zA44oNfqrb9AK31>Paa|nq# zB%dNi)FI(3pqUQI|5C7>>X4wtlX5X<6Lm;_Oi7{+$~nGVUXsZ7%$`7vzW>X0zs z%XCQ2#bG)mAEPv;L-GYeOot@s)0hs)ED|*xlG91lbV%x`Zqp&5`IdA@-bER<5yzEj_HtWC64Kk)WBvsB=_Jj9g=g9W;!H4LV)Rzunv;xkn9GV>5x2& zXwxBi7-^==O3NhCgy%c6QBR7gIS45rU3^_*)(;q^< zqwqSN-7IaOQFZd$M}Geq{1)Wj8A8rYlKmPKGDRVExrM=Zf%u7~uw?WnRSOlhBt+z) zK~H5gntPSM{!5IPYOuhPjBZd!#U6y506So4Kp}WwVX=Jo@AY2RH}qVjXu=Zy-&@Zm zss-gW&8X?D_EOvV+-y^Kkq!~eqf9A=Ow~EHnEfn3ZJ?_{47~e~R!az^29RiHFcyBf zWHHtZnH@hY#VkmQGg#9DJPpfuO9x!-C0}NCx#U#+2SO;rWhI3*Ex^TCM3=Ar0}a=| z8m%baYC^CW9j?H9_{RAg`Zsa=@T*1trYU}G3yp&prGcZD(%KNQqc%=u62Hl%UCrS1 z^zU3e3A~?t(l2wBg_FOv7THNNCsVWNh3?EhKxu~8=qL)ju5@Sq0oqZa_5BSxI%}7& zUAk_ksye+>(Mi>U(68vVvQE&rc-^Y%Xqc61XG!bmwV<)Hv`tOu4Yi$~)pl6Og|Kr0 zrGKWj!yuVq0yZy~M#|VQfst>I#|^x3jz6_z^jgs2u_i+^Kxc>dj7F@pYdJq7+kSas;hK^8L4{zuQrSckm}rK3qmRTh*Z3zm zJjG%39E@kC!?PV`Mc8;2JA8)2Z4RI1@Y@~U?C?bnR|xl{H-&zb)gj{x^qnByc!JT( zsEIf%1xC!cXiUV6Usz9uKdkUY%$SA!-}u)H&y1Kc43yIt#>g;UmLFEf4YMk4m^wEs z*ej|LS5AgHfzW4g$!BYd=wQ$`8fBn`TGJ$L%0+y_h}TuOs!@J3WQ^d04v_Kk&X&A| z@C{Ho}gkf%rw((6H+B@B<4dR=sxJJl=9+WYR`_tm1 zof%o!c6s=6oL!UFFXh;kZq*%<=i8sjd#sDR3ndReTHsEdU%r^(P>{z+!5%pEdcllhL!f5{+tu*@i#@iKE{ z7RW4@Sub;;%oQ@X$$V9YgEgL&p>G~7bEwQb8Qy@m$#6){2V~F%xl;yR{KsT|D)W1p z{>pca4DW;+Wq6;wNCr)X^JF;N;YOJ+$UGqPJ(>TK$*b|~BXh9Ku`(Qnz)3b=mieyC zFJ+#S(I)R?iVUZntdKcZ=5m?O$=oONxQvl>&@R<+L}MP^|NZ%jN0TYn=eM7b3?C`i zmV0qk)F&%0$Zxqb>39B=k#AjbP`={!_n82z+8xe)jhO)z3`Y&P#6s z7vyI@0{F#(e8snd&(i$%2LtHHZ+Rfua-W!P$Z!8-((m3WBddv`B=1Z5T`xFgWWM6M zq+(mrPg-$_@-q9&#N7Xee8rc7h|lM@-w7B#WVQwi!#^jM?H^UNxx-s1$JK(>!)M00 z{{p8(&b~aEeM>U@{M38PO;P0RPb9;yjD9x+q1RW8PFCEPpM8m*(o;r`9{y+=TCp|8 z*nZ9bXYWnmtE$eu|9wsd0*Nw;ASj0b5|tShRMd!yps2{8ctt}<0;E8KNf5AFa6)XU zf~dt-OB|}$s&(pMYimSBY_Ub_RI067$JVxLt+lO||L?o@vyumk*ABPu|K9h$>vQ&5 z-}UTg4SVgihc)h`wjCQmz!GQ>SWLelYJi9ps|}eCZ)~wr1mo* ztA`~s&d0S_={sf2JEXl)*l)~6^S3M+V==8bCj{}*KxKPVQn)mk*kC$m$wxc!#1Vz> zZ=ZO5D&4dY^@&f6`~CLP=33&IDYdd0ccr@vYt7S)>o@&s`wWY2MHQZAyi@q<_J-zp z!o@l#XCPaALw4K@rG0+tecY)COPd$0_}TU(nbo{xjueL{qxL>=R&yhKka+jf<}*|E z7008lQ?O!evf|jJp?Q&OAgN0si^(0sP} zJ1F{N*Qd?j{;9uZE50dz4b7`ecStH;F=}A8@D63h=Tr3+WvTqqO<&zE$)^6H+!ppr z%Wq*{v-_a6Vo&}Hdz*|q4Q@T2gH4+lZrxUc&HV>A&n9f1dDuKlu{-duNdPeK3D^b6 z;Jicgk1v{Z^xBM``azhRwN?W@3&T*)uy$BUepyx*?CJUX%$2TTTRm*bqN=Kz#>V7? z`lej{;<}m!QLb@O)!ZC2cXRa(x$4@68ckZ&#M-!LVMBfJGoh|YGmaN6Y^tfwX}N-? zngzKk&9Y7=3_UTY9rbNtRo9$VTNOgnbXawxH6}+i%*ingJEw)0b4*Z9j$Tqzm787P zu%NQZd{0rYWKC19az68%m*%SK>*|ye&B7g9S)C@YZqb5SX_BkvYT0JZ15S>rX>6*k zt8A*Rugh6vxrUlE7wIUfIf4cC4K+DCf|~TWYwGG3&6%5PTv%CElT4~}1ZCi|$?1JO}vMz#)W)}qFx$v84g)1@1m8j~YgPkOK&^8DJmd94|j%H-5RxqKa8 zuY9O&%vI|IBuA!48Io@YURy_k=Y)Kl(71!w33Xa2ptd@vN!p7RXclyGLQT`+`i6Nq z&1kM^n5_dM;5tR9+?!oHN0ZE}lc~z`1(kJ6bF76OGO|(nb_#d4*HX+h?n<2im5GoI z$yD_Lr6-~-6T#LgP=a_rVQU_c;sXP{)#^mJMhNeY2(5l*osztS-5X`BsQz2}q zZ>rZfb?iczRyVIsWrI=>#L4kma-eo@{lZ*jldd{0z;I32aV6ulkdFN(VE~wQRBmUOYnwzz>^$1L%?LZed=pGQx0{4JiW4QDay9214Hl$ay zN=#k7)^AUDw`LRZv?an_LJc*uS!E!J>5BIf6?e%M{_Lj3mAWBRRiYMeG2!ByrLq_k z&~^>k9moI;BUHzxy{ZE%7h840fTIG>t6!J2KH|jMtFH>|jR<_^^+LxDYmz7#xemh=g z^NI={SBQBhczR^ zu@q0j(@?mmcv~x%6i-Jz$p4--BOjJ_9Pd9zX(~7{P50+B;!$Z#3z3gbW6DE*5L{Ax z1F;?qcPgF^9|CtPegvH{aF611ksk{8E@m~Ig2Uik(&-gBTF3kUBBMPv-v3d2*m(bO z_&DwZ`OuKXp6vMh#`}jXv+@36DE4W@nqPb`@z{8O67Y|Y_a8v++IWAyQ&TW6gsj2U z6pCGjOZ0K${exnCYDBcqt8}A>+-S1?) z|7B#7tr>X=NBDQG8AV8m0 zjyT@`uVm(=uxD7hD&R-P`{QSH_mKn;*NnUp$4AEdqjpsHr`Qw6``p@&06s3gCaTW+XGv3g?YeWEkE-GS_s~ z8%G~j#L84>T1WY>)^528kyg6g4^U0r({VEmPHy~OD0km$bQ-yAe?OhnJ+^)e7%ZA`SKL^!v;-eF|Cs!-kY)lI~smhlMJqYUIB@kvxSX!uMXC z6h&c<7~;EA<{Db)b0Mu`^H8FLYbfY+36Tl#Wum&T8# z@8c&1DBQgMT9fjy;yg7Ost$@UYZ91vfl8b<-lh9;Vq` z;oXlrHlfQ+%l!KB+BYfPPpkZTczWul>arf5nYweb*28mCH!bk%;f1N2miP7WS*e?r z_x12Oshd{!^)O4|D1KVt*Tdwj+_c26=YB*M>ZD_B2uPn`FgR~Z_hNlF;1n!sWjjt6 zp@OF)kWoBlV%-gAe{~jS!zVQV-!zW@Nz*t&ORJVWQ|bMur*Y`n6N*OO>sdZh$Bd1l z_QUkQq`lU1%iAS<0=_YDUf^>B_YU(pssryH zyXl&(PbTe)wd>Z@_2VRXx-)hCJat{4x_+6uu1#IiS|j73I~`wLabVV(R*KroBF_mA5%{-Jb4yB6WQ)_4i=v+L-S9e(HKW z6Eg1WscTER@1E54bn5S`sq1IyzOSUN-(}hlQhaMt*So3as?_zXRP(CTbzQdoF4Fu( zn)~W{(^mrXexJI&mJP8#mAdZ8h8*0Qx}MLr?<&n3QrEMozYVGDrPSY-Q`ddz>3!&& zkb`e$!#TPv-S=i1<`t>yy)=~1rmnxF`z}gdm*utZr}*AZLwO}VhA*YZ@W-S*(|;~W z&)B9kzVD=(w`9T*J(FsFke=xaQ_TnR+V3uZ_otdI>Av!i%$w4rY)d1*Ar12RRB=OI zCl zz47lX94{|*I$rKs7fV|}e#edxbLFN9+STcgu*7xL-hyzD1tHVZ8CuJ1wibTl3d*hF zXy1Rsd0M*vsT=5j+Zx9@>abWa>(DOvw=8w+mn8oC=2EE%y@54z)4sn}`iCZ0{V!kr z_}@M2F1{>;RhB~^p;r5jYccdXI^thv0u-VQO?hQS>t zZ!sW>H^68!0*%p61GSZE`?NOvAwNeOGPW;k!ytzTXhZ&>wy6J*c(BRemW@Flj^X#P zL?MSq$R-?CYQ-RjqyCvr4wq{``ge+{Bg5ZuIxr(GkWoOsWM~G zhgEM2{`njmhk!h-Qm5f`kzC$`Jgr)%@;#h9tzxHgs?-?5Nvqnayv)gA;w7C!TsXs= zoVM2(Z(0RU^$&CMa;HDe$;UhS2~JLRJjQ#nlc!bmH2gE1Jgusy^4U&4*M(E(YwkzNvrg!oa#IVeOLn{L%va;k7ad3)G2FgMI`TH1s%Wt z@&w9yzIZT1_v_(9h9^TBYUWoCsjiu|NS{b(P`CdMl3EsXx4o6KW~rlkhux}Z?%>wA zkh(bFNkW(l|mgmNX5~>`(J9hXy(<;eta z{N!zo)M_*T`kLq=k6Q!G+hGNAHLivp_14{T@6zTF<%LPFZKAxeqM&zk-)J*>t8R0M zK6y=a?q6*tPb-hoMUSEMFu#&9WzlpJaJP&G_egE%(!Y;BQz={D2qN>k_K`O^_bM2* zLa-UNP+@3LicBs>CVi2KKQd$8B9rFGG*Ly)IqvUR7f7oPErwBlnB)B&k9Iu9ak=B8 z9FKQA(eWh5JQ-uW^g2YI;drLwYR7XO&v(4gag*aEj(PINxRyJ<(D6#gs~oR(e1+q6 zj<0dt?D$5<8yw&2_zuVSIR3Wd`y978e#r4=$6Fk4b^N5`XB|K1_yxx=JAU2qn~vXd z{I28o9e?1M%Qv2je8)wOOB{D{+|4m>J29Nzj&qLtJ62CrtNt*!n-V262)0`cV-mXQ z_LMKX+_*^g1Y=priLf3qJdviFoS;rO?j(D*aSz$`#=T`Pfz9v5CLbjGa^wAFe+iZj zPq}83m&?Azc#Q13jE|E2UE}exTVVO+ZH{xwv5>}BjAzPb?0pRX_a&KuJkBazF>UQ&9oNf}GYSi)Z0_cCdYSw!>GU_|dKzZ@u9#I_@%z5`a9A7ZtS~v( z&0OOAz z<{D*wMfCeKlT%(^HeM-x`tb>eYxe_VuHCHC8vXJ%j!ud6i%ib3gibBVbCP#-a^A+# z?=Si8PR`pn@-oT$I5}_Q$VW>)z{$%@K2dVUDaAbGZ5;hcl8@Cu@|h-Yk-W;u=bHRk$>%vaZ{vjXy5x;c z&f7Th4UM1)|ltOd?#-(ULt#ulXDEjb-wIn z#+2U+jcF~QhZmjIvOjN3`mZ$R8A91Yhil>n<6C6kWQ;!L3>}^)Uw86v81roTwv%r% z-Xi-^W6C&g!r{7Rei!_V>?e)6Zg3-~_2L)CJeOWFCOwo_ba+Pn+L&wcJ!8u4pN!F` zB7=T`;>~J&$r1=KHc~X*{3;ql`+q~*-qYMe75Yx#$3m^NyBp4=Nca+_xZ*vWnW~> zeF8W7w9qgH7G5iRwK4Y?+{kJ5`I7NBKD*Gv8p1sc+qw}iqo3h_9=H7-IzqBO1Yy4-~e>BD~ZggmQVx3}`XYww_ z=h{FdzB7*nR+Gv?jlPsYT{ za2cLKgQNq;b%*Xn&O^pb*TVFDzLVT=H`#1)oq-;(!o~E~*44PLW8No_E9me(L^%74 z*mijQ$3BIKuIG<9j4m5J_BLq6Fqorn9!lJTGIIJ;gC?JRjp45j^{%{s_kh zIWBj6jN=m=Pjk$3Erwa+m}gd$FLr#sDb*^!|!7=x@sMF$ji(~F%QRijHZ#(|0;|?k>QNO$6 zevXfD9M&eXGV>o!KHG7F@6~13)@}!_GZQ=W6CJ$>98Hewe z8Hewe8Hewe8Hewe8Hewe8FOQb#~!|4X7cd;GUM?5GUFqhe)xWw$;0={jKlZKjKlZK zjKlZKjBjz_gzuM`Jbb^*IDEg%IDEg%IDEg%IIK-%9KK&>9KK&>9KK&>9KK&>9KK&> z9KK&>9KK&>9KK&>9KK&>9KK&>+|sTs55xD%Odh^pW*oj>X8dvAFAM7twb#v0=HjBZ zFfWHq{skw$-pOxv^1Gb;TTZ^w$scj@*I-@$m^~CvED!x*lb4C(Gj62QISkf@ITAMg z3a2yAF?#X2rXt_U#g3^zMjcx7BU5LLJjn4d$Dj(I-D z^jzq8rQ^#SuXTL04SZ7}NebWGhU>I`u5eH;&SItMs8ZHY0=a;I~&lTUCw$>~t`@_QY(IGu-` z{87hSoz7EE{!_;QHcV$@ypsmx+$Z)lrhSO_F68B6(f}VR9%?*6e1P#p z@gc@j#YY&QBBpMLU)qbP55hCWQ;cVesRJUf71PEG(_Ta!5azx@9T2`)++a*Q&{E^e z#mkMa6klxIEM`Izes2&{_k(W{^G*ogDyH5CbHDkj@i)YG8i%$ZYI7&(0oFB#LW^M>&UV(NbA(5~}GWBMZgYRtPoZF%T)64UkvGd--U z@c=O+G?3Gl)7O~xoHAqDa)ufoBtFoXwwyzaY0o*z_-HZhw}d%S%$z=$Hl9%_F1Ag2vxjWK;4>x^lGp$?4Bt>T-EzbUCyg$RV!7#Z2-Yni|{6q1h#`J+~HRj&%j4^F8KR5ol_!VR7F>e~v2J?Gk`bPe2 z9Iih-)QPv9wjyKdIvtH^lj&~Eb-Sl=FL8fk?hX4H(^kV5;Rth}wu6j^iOY>gijOfq zNPL3v81Xb?uCp1&w7XOp)AsTyW3D;g`H72ul_kcsyRZ%va;~`*#uteB2orMpTdpvs z-Q`QhTz}UauM^*5OyA2L#&?OC-Ay>Ow|vi-ww8yC9}@r2_!03F#$12YBk;Rb+Y82A zf6SCYP8-Z`jcJGZgYj$P4~%~=X1yEqX@lutOgl^`VwGd6w?LvXzjDDv(u6Df8@i~rHI=;ejv*TMGb1#l@asQ3X zeKzuQj$d~i+SB9?M%P2s=l&SEhvWW^xtB$qF^;)6Mfp_6+-stIzT+j1xi3VW)sC-m z%=I62xXvTnQGBA6lZH-tXzNCKe>MbW^r#7@m;T}M;L?3tjoPFGIqK}=K0)8E50CQw zp!A}N;q4=V508%mY*m8-;h`SGBRzx{gV;~^KyTQGp*~Qg?UVElmkxeLXu}ZRPhFVo zW1C{OtYG*;@TBOF9gl6sKw4DSXBe0Wc8`~ZZ}JhI%qUcOK)^^$d2jT=9t~P4oJ^G zjEQ=*3Hjrgp#nrckT0~G#p8HQ9Q_EB?h3CZ7H+riC9w~0uEIl)@OW0o@W>Z4_M}UYYI(V-NdMicN{&9-&h6H{TIQdU{q$S{t$~`_s;EWS-CaP5z+;CEZF2+7ExUuhQ5; zZ8)`C#^heRtNmaGBS?B^R!dCgZSMPQ=fCfp;u92CJ{P>!6{Gm_De?SW1>s7h-Y9ct!nYmD(e$^uC}BHUW9(?D#5Kl#*2*QtEvOGA_J4GZu?Li*BCn| zjj=Bvk86yv5X{G~F~*B!>o>(imf0F(%uy*gjTG#-#uy3s$JZEJfiGKQj8z&wvc}j5 ziT>_2#$HjH;u>SC2=^1#82b!5w#FFkPw|`LZxW7uQ~W|Q$<`R#fX+X###m2|XVWJA zmlsb_cJAz(;$dN-$H>iz#or~~ovblNTi}1m8e>%6+twIcN|MHLztZjgO^!3JF*b}n zsiUa-??Rc$4%S_!r2B2C#WlvtQHyJgeL!Z$HOAF^#?WpcgvuCGkj2%a$X9TrL-KqJut}#Y)LF*c06yLUQieJPrtjLzj`kOVzm_ya} zP4Ndw#Yes=uAAfKQu^<>##jS~**QaNYfq|+t=|+6S8QBkEUZMFx2`cp%UD5NV{8L^K6#BXS|D537^C~Vb&atBoT#|Q7>&QJ-xU7>e&QNq zFXAVzF~+#NoqtpO3H-!0#_q$!u`%utA$yZ@E|;y1;qGqtWUwg+l) zjWJrgTE8j&B%#G`iqlT_U$Dj)Rl|REjWMq9xW?EIIFx_O8e{p_QIeiMO85JmWv4B^V9DOg>S<6gfAFuJHrTXiv zAhv0LKNk4vrv<)-_p=4QN}23=h<5)r><*s}@6RjpB*~Ohe8E_0)IwFrJ z-QM(yr0b#`AjNcrKvLH&{2{Yd$o9UQLkgcEC&=_Ob-0Zl#MsMrGOz zVMH@kJG03jGKwJcmtD0?PWk~5-2cu+6_S5X;I(yC^A}au4ApAq|9lMpBfdf&=AZt{ z-yv5)4uvD{M+uAGWc8me8+Jp&0Wqi||DYzQK@G%&yZ{2O5(KH;207 z?^{l%E!2PDM*`l16LzpkuK zD(dtxhuMi%?WtA(QeIp&cUI!{+77JMKS#KOqoTI1x^-4LGs!C&=gePJlT_5#Rp|2= zO%-WoESS~MRKK`Nk!f9gTe@k-aH`H~(kBLzimLkhdA0ICt5VDLSMW`eBu(_3$^{E5 zDF$_-xPncE)*%S-|NWmRPd{XkEY_irSxTAwTEZ%-7B%RbB25)lO6D9sfl~3`Z;cxj zlPW%8u1}OGd3AQ47gtwGwpbr-SuiUeO?6{^#av~O@~~pz0VT5xf2^F=R}41(qlxR?&=bM~1DlriQf={VLT|z9qR}TWnkr|>ZfZ#F zxsk$(75~?LtbB)D`Y&Hwqdj@rYVs0w>^SqcYirOb+-CB^dGu~t+1t$DuBD;ZWoJHl zZH?WvjBT5t)a+qSN(F0W3~1XOQZxJ`ZYp!pgwoe``_|%|{`TLtg9|QQfTQiR=8|wZ z2a};gLWVcqIJckDnc=-#hCY$ZZUIASj^8!sT{(Ws9FB8}c*Bn0FNfpz%LgOZ<-pZI zpC3Ae4HsMZ!vE55oO2xHA!DV;d-?<7ILL5ZRz%2xI7f)2#J*c~fwhj04D*QS_>)l= zORGNVkA4qwT<-W7$0s*6}Nj-*O!0 z5t(1w;^Q%fc|;};^N5VYJR;*TkI48~=XZ(Y3mva^e2wD`j_+~Y;&_YWXC1%nILsrm z^n`gt#$g_jahOMB%y`y#yhk_=^N36*%p)=m^N5Taoc=YAX(Nwe-s70@Xi@&IWBSvg zJdAa)@WWUK<1p62IE-~L4r3jR!&nF7Fpj}EjAJkkV;79W*ac&Hcw!p1IDXdg%Z|f5 zBJ&&O5gCVhM8;trk@2y*>BR8EJR+0R#2V#c9+AnzJR;*TkH|R8BQg&2h>YnUis6KL zL?#dOh>XKLBI7WR$T-X+GNuJ1h7;xynLNxRGTztegn2|JKhepXKLBI7WR$T-X+G7j^IjKe%4<1mlNILsq54)chN!#pD6 zFptRif7>_C*XY3#&zJw+`3B@XbYyOGI$<7>$?rq1>m2hl$G>x2s8^X7eiz4M9G~Qv zuz1E{RODNk(-Y;qfkvj8EHdvPk^4Fx;FyN#sB?(pv5v<%KHl+3j;kEcaa`w^=Ut48 zSCq&!TSulbJn~w{Uv$jc4^byP_xY0vZ|jy>_5oCWiem&Ys4)q?10z zoYn!xydLal+(pdj0Q}P2Im(!KCBC18yubKJV;b)#81t@lqVX{C6l301VngcVu%cbS~D^e7GQPI%Z~8+jNFlkeUjc$(usbAVcn21 zfSH)S!{zqro9oiYI3@ORyeDh(;qe|eN7rsNaUa)-4{x)=dsdmm@uD8Xnj*%at#M}m$iFym=_VG4roK{XdiI?=pcrOx1Kf>g7?aTpY;=bi_`|w(F zX*nl6-oaydSBs+`VN$e8P`HIF+7boJK!G~Z#MFv5u;N5Pabc!nnIyO>>na6OZsTU z*(RlTqqgg{o$$u??N7;mM%z!cc|-a*KO779Xr0!ir#9+$gS1gDIu1WmOrQaM;x}uQ%qq>Cs zUAn@T7p=%9=e)B?v6f`V>90%CaE1bgFHYAf3~XY$?tr)rOS$? z*~?2ZC3&TfJ{6Aa>N|(!nzp<%;?b?c`d_f6;n*#YUboMkx`g)=th}zIeQ8m0^_tR+ zKhEWvN-h{Uvh(1gLo+2erm?Qf?6c;Q>(*U2aY|`>9YSHRtFOLpQ(m(2y3&nzTE-o` z5``JpZ)~3oye7Ni!0aP;Wj77g*U;rEtjjzy;`E7Q+3{HN$cTL=b`fr>6?Paj8R;?E zag(zXONHZ>>!a%I{bI606DB7%AZsW89VX5a7XCQdbWC>Q`A84XOuSt7iX$_HM`mY) zaMnn%YzE;JF2c`@EQ%**HXWRu5khUu%or=trlpy}1G6(4z`HU7@5_!`mC*(yOz^0cr*E}*}KxuRJz%kizYqe{Zc8wdCaHKQkti=D`$tK>T zN}J~r%HcZ1;?m|h?724?*E3t%{3-FKzM0bId4h4fW(vDW*o49)MbfXdxeoaN61Az9 z)E1&YKoAl;J}E4c{t|@8DDdv3&5Q7RtP~dG@$Af|?K)|t%}eDfyjbG1(Y-ZOs3nnB zK2TP_ytH{^X^+7r>6zVD`uSao58Jw>WmA4KYIJtfTba*JTzB5&{N%F}CLfjbS~+mt z>*M-nTK)C;IDaqg#9vqZov8RWXIlp4b{^l8JMmZ0>Tl!6`rEV9iFqr}+j>~bwzA_(3QyF%udHIkhAT>Xk1EY>Y))EQ zny%`SX}xDOZ0uTC$o+A|&GQc~O^>5>=egN+cV2T)X>-*Pnk0CAH(hNfY4rF@<5UI& z60Qg^cg=fy=arOQvZhkcwewc4X*qfAwtbXb8t=^A}!*&4+^{qY5Mt_y#& zJsC84?wzGaB&)7kvS!v1nQzYNs)P=@tMrIW$c&nby*Fi(RjY7bG3v(5IUlS$Z|eyy+iI1^KPVkr*}0a+t`-H;TwS`+ z?&EXc9^1F`>Dfc`2N!O7CK+8(y5Wkk&6$DyvSXW*^75v^9S?eY!iy6gzv#=`N5B18 z_NtMY!FjExY;ruGdJ62@uQluxPAA>x6W8R*PUG^)+hL{4#UIg|+_%%ytCCqm3pj?o zyS5xYyk%s|)4xo{zj)5?%O6~;LYI{Ee)RDljGdj|u6Wwm<|>^hZXH+T_mV4_G_6^` z@`szJKfdbWK~I!)*GcI$y!P?Jc8nr<f?7HOfajIoy);-?t zjqJGFlftitBD3(}#|0*q)RP-TV4oSKU?eV4CLB!*k~0b>~%v zbGmWMx6-0FZf)V5?JLilzASiEKspWU&YOOsC@A!rR#>6^;WCkIdY^HpZ7&`&@X+kI z*Q8f+!?u0KJ(r9gT5?ZGmr?yQCE1k^lx{5Ja__RkUE+ip1-ic|?s0n0I7auFXOeZ- zjcA{ovbOhU$Bf9+S4$6Ge0jS}!-KiitGg9ny?WFI!-h2}|H967=Y4kRh-1Qy=)vcU zRy?4`U2A%V&h4}5Dy0O$J|wVX;m9 zW#pJfU8W-*95!Nn@_e>%gWi>vtvs)+{?jA3jnDOKDQQ$G%!D!+O5N5UwG7VRG(-jc zq9xnM*OyckPc1)SZOLw%mz{Eb)pOae4H{M|KdFb)vzxlAq_;fSQhM{e5numOx!z0q z^HOpoH<;FNM>J;?^vTy}q$0(j<=;(u<_@}G*p`+tN548FGiKV#^R|_Z>zRa;QFviE zj&1uW`Qw%(W%VW1#UpY@t}W9Me7bbo+;Y+~tCB`;T|;xG&)9);O_^Ic*^rhUE za5K?M&A!9K6_7nNvufkqH6_`S-DeJ5o15KIyJpa2y{oLevsb@W)5qlR*Kh2Rnbup1 zoyy}g)7LC0Da`39Hnixf5tj3DF2(rE$`2o2KC)%l;RRd!bsjdNrDbIE<_prJTX~*R zv~9ZX9%CNV?OwUtdf}!DifTc2a7nzQ%+G26R~;ntw#lDmXpfH`o7F z3jsd=+V`?6`X=Mb^su<>swbFnp!_Vm?13c79X?#8Bsa96rL?&$o9@sBl2?4jw%Wqt zmmE$p0ZJ#zWLep_10g_87q z{wDSO4H@{ovX$oznzF5I#8|!Rt-DTdVyi~bENH`P)X1Ju=y(!1QLB z?b~Z(-#wn_+w-NqJ>KcNdzS|m?($YLpmD&EeXFsCVegj=P6iAaApx6UXzO1xVE&@y z)WHK53?5LO4B2;)c8^ST4o-bYJCHf|8#Z!&wf4-fCU$MxWz@fTPNFV)o^?yI!t>{GgF3nxU8r@>ff}5J?_$F7oQ;3fna;(E0^^dPuwIThhw! zJ3!K;D9oHGg%tt+{otaaThQqbmlV|z;Q+W((b@3caJQna=nRB=6fGw;WpMAJW8r<^ zT+;pwdFY)#exa-mRdbX4V@X)jVL_6A92)r@>XQ74P*I2KB>#A*q(ftpe*)C0i1vW| z6R*^Nx1!64ZxTn-Bgvz)B>yCir#%^8o#CDoHVk zVd8K}z4m32yfG+F|1@FMN%BF#zRi+!SfEc273>ElMdxd0!60~8(Ueue-KBDV zQdGbhQ+%j1wcax2Qr5B#$B^<1cc-W4R>Sm>f! zP$GMet4Q@td9$>K)N~0^+!TWRqh!4*rKC>?CNImoQdkf^PEaEA)?B_U>D3^W zeWmi3pfaT(kCvRI`*Ml9EA-tn)3VEmca;QmGMplt)FqjRL-Lpy*zsGqHwE`9xqGdV z5(V#g*@}q}dTtP>hwxX?d-B105FNL12u}yE>j^3Z{Y-GbggfNKv%x*6LyYQY!97jx zGz;F$YuF(R-V9lAJ^C{#7{ATq#$2RZb}u>yN!sf!Y2}iUw4QSfwCt-21w}WkJ27|o zh$Pc9e}LS*xb64WmW-5cmx_udns^ZQ3}H{VMG9uQ;5_Y3k7Z5RdxG|M$Q9eWsAI}r{nbyOqrgRX|TV_C;PU@-Th$&MsZOgD#%M4 zcDp?%H_y29xRAJ^XYvc?%KZy@=+bm{k|`)SUq|+ioIN?GM``Q%EB&1a6zVLU3=9;U z4)9Fo$dhgjBJSP~67tQ0%x(po1zHn(F44{q!WuyX9ybX>P|q49JztkL^VEBdR=QAn zK|ztf=Sa5DWbZl|o%-k%DaBFm1(Wr5vO&6D&>Pk!>-n5yB)n&l3Rfsl{RK$6U!^Ee zw;**xeMEPT;tP~K&PBLm_etI4RdBbL7LT-I4tZUa7AAXMD|hDj%#9KiuGC*Kr|;gV zkV*EMEqDG|w@9+rUc$n`pVfb#hjbY2uHcr(RF@pGTp+?%T!hlMa#mx~t{e&J&V^m2 zpOVj_UBcsllb=H~$K??M>6i3jN@4rG5OZ?V{e++NzgAxJ|AS*1FhlMRr33KSpf{W}-;G&74tD zDd?CK2U+3X3A@^94oOj%LsHDxE%l*9Z=-b?wr`zb683h`UcM}^0N7ic$xP^quadqB zYp5i<4AG1f=A$sBgLymUJ+2xXJ}Iw35B{_B9owdZ@KO3sJI?#q!Dnarbf2^DBA?FL zwS$FAwWV9JCJl8dBuTqDwH_*TZ8K4JcN0{4v}viRN+;=@87|*@xa7%qujreQdlzS> z?GEhOrli7U4rR^ZJ;$g!pwEtnG$!Oit{`N3->@&_WZT@A(pC>4_fil26noNtNOE}3 z^t7bvDnMRDbis7izoyAxJrMA8tWDZ>oEtM~;YfO{_j0BU? zvh_eiaOjN!xJX+jITh;+U0F)*x0eC++9b!~r69F^%BFKT`QaKjy5kU@IlghEa9_3F9UQFd!C+i^` z^cM&gYg71GFGM-;>r{^Q+bI8&;DaFNi4n|Z{lBJ7li;xWgln$?D_(ok)(1uXq01GV zO@^)ivut{`^7H|V^+&0&AFC~sOvjq8O)Z0&^#Iq9WxbOkRuT%jA_BO`r1A?{l>5TuT)mu?uBS14rMBpXDbJd|w@_sy zEmJy%4RYMBO+jG2s4c_}P_88JtaH1Ews6dc3n(YL#eFC%J?9FiQu$k@Eyf3Po)q6T zvepNj+9K=W6t~EFCdF4|al%3bI=ocUobCF96ZbmAE|_~(;xLj76 z=aXkB)HFLL$DoEOQAcRgeSEGg7RD2e0U1f0t750*~SBlgt zxqV7{sSfJ8aOPS|J9&9<2x&6e*N`GP_SF>0q?b}8U)BZhttqAZf@cNUgH2^VFDW{D zJ;0NL9r3VuCh?R(hHZD{`<9VatlFqc_`YRimfd&mTSj@Zi~hc4T=aIO-?xk`v&;BC zYK_4V!z_ydo8&3uu`IHCLSzgbRb=;s$PQG5!2yiXmPt;*IwHz}aoV!U!RxV)i#vey zsWFX{X{o-)r}`eB>U(^u?`ci-uatI5j#8Q)MiNdKYjPH9c^k>r!_@5MR*od=;cMM~ zxY_N8c?N36tq;;v5Uq#r4l2{4%BNd>of1Wyjp5qzlQnCWt%n#cE7#@A)kwj zPB5bH1<^@ZRMpe729Xh(%Z>GHz>~0E)RyW%WQugKUJrN@RvJs|ZH_}tMXjeJzPad$ z84v8cx=lP5ZWU9oexfZeSv<4#RzUN^rP`F&UzT-KiqZE4a;^=cDOl7;cS)L-9oUo% z8&Z}@x_4cVC+eI^F4q0pIw#9|6b|owp#Gy)4DVv?CbkaxYI$SQyI+S%@ zeKFmEmA-~e`Ks`4ZFxy!Wt9-O#rxZr4KCWg$9kkhrW4hz zaK~MU&)cadq?hj86JpYsO@^LW`jc-0O)C#z5rYLC1s`K?@AACW2S zDMydIc*F%2p31UJLV*@b_)PfEwrAml&$MSLg|Jvcl2z|xUeaExDhRV8ExsYjFU%`! z-&I#;;EoJy@Z|VK}v^)Gm+W%PCyN0myLM|4$|7`nR!%=Yx1{!mmagB`j zX-;z*g@ro8?m?eZ9dnH%UlPKPz6h;2pQgY1l&#cnT6{Ac zn$9LUk*@d=^ETDD)R7XEZIVYma85H;dK5=0PDloOxd_s~;t#?h)cGY2Q=w9nyzlxb(T~Il{tFhB{~!l}uiT z_T)uD;563?!`aBR?<0A7g{ASH8}c;0$%L~Mk3YTSxV`LYg(o4))7|G<3OOHt8&^Sy zt8@FVA+EH1rME8*j zhBlov2jhQw^^w1Yp_HWMHO+(c{*m5|(rY$72Wd*;V`+DnTBTgamDL$LK+6i$d-g_s+gQm zz9*SXW%Z{PH8v$$jU_C?Ql*7O7HLV5xPDJXcve>|Y-*^eV6B$3D;Cx1fjp1(PU_~= zBpx0)ua%Ur8Qb3=AT|ZXXk5B4V|^9c7FBX@H+K38tIEy`mV(xq^Tys8pl#mUC~s* z2!vWKW2SX33VnPE8dYbqC#<>4qKXqvm@f;H0SpsPZdA&Yld zho)K!zl2?jYpdn;pU#F)e&uuTd5v@H8=7)Eq=TcY)#4`=yw7nwwT;y(OVdNzm%gau<3R9DnDRM#|EPLt2A$q38t zG}LHq7_G#UCXsVeQ8A}R3*^{BIU%s{8d;N6E?BrAq>s~reozi58A-a=^$IUCl|A*vv+)7hJwET~)(t|YF$wA{6xLj^(!{r_oc zoI&C3UIR~L8-_Y)TpEXdaVoIbOuj4CHb)z}YNbf#YNH<%`BH5d-sV$%FOZ803$Rq;o9-q*%{ z-1OFTH#cM9_Z6c<|0o6>I37Fg*%;*TiL%ju$jM>#TL<|wVs@d=q8G%4{%;Y=Acv!V zhJ?u=hx^J#ztqX$sL#jRFzCZk|70<{kTY5HK-s0*7_=7Us|ECXBWKYI4Ek_9N8fXD zc$oH=YWt0o!!h1nRsUoc;dBzmaQL{94l~I27BfbKaOl6mpbzgM8##SB802u&r(Xwy z9FF?*@nDd{QJ?-E401T?)Axfx4o7|ZfiTG7s81gn204sPI_Yx3;D)1|{uc~xILhga z!Qh5-vI*xfaaK0+axrBa_wnMGhqJ^a4;?zZhseh7T5-%LQZD@27MU6$eW$c zE#esd_e}?VIt@6dq=9Z3404!>riAmMlf&`a85o-6Q+@gk^u80qp)&BW12UJ_cJ*?3>eZ3 z$NTLYP7cSo{_Ny%Oq(h$!C=8rpI&YZ797v%U?+z)*eV?3QBDrWV>wYA(@*E-0Mln6 z1qKV=M>gk(E(Q!19FO-=aXjw~+l}d@3ju=#$8)MGT`Se9tP#~_D$%H~{ODUQcWBR%OsPB%gqqBJr%lXU=uzA z3dm2~^TjcIx`c^_eP0~IX%Q=mAb-^9!<JP6tMZ zxJs1B7}u`G$UBK+KEzG|()lkhH(0NVN+oL*4j(c+84^|~tge~0XimlK1}cMILNy{8 zlJ2dXHLIcKtQ~e!<@4&5S{`yvP2&!-orvbw)+w4aR3#%BQdPfTfoizPkhFd`B#kzt zY)R7)EuUy1%CWGaej%B#gW=RhlmAbwN60C{Y|@qu1v)sxUtW0Ncy~Ant%AJpplWr> zcML6+<%Jup-_K2?&E$oP(!057w3)o{0QPQwv|N7N#M(?=D3spK#n)!?^wL7VQ#2Gq zZZFZ`=G7q@++(6cHtwUeZPqqJ#hCRDj~7S7{yEVh8+ZLj+-H5nefCG(7kE{wPCvi|bJ494~}<2FNsN%kVxevqW2l=a$Sl z+9EG^Oc{ytm5x`zytB%z)|Mf1nJctK`8s${q`K{Ei#pA4H~q=ns4ePjaC|FFeL&_8 zZPD*Nu=)MAyF=aI&Z<2 zhIgIL`>-A32XG(#VRY-s`RSHWM2iF->XgDNj9S+ z@JrTx#khy;uffv4S2pJz{;uqAIwo(CGr;o?#yrwT$&EY?o`xCr_JGOJdD8K(9skua zYi!^b{Sl6t6By;6bNm&@-*Nma$4qyNeoGx6Va!-mhEJmNvR;81W(cpA&G5-6XUrkY zs8fbdM)@1YoD7CfMmZxAVFn&{b zsxI>Wl7GRtO#DSy@ixmwFX~X$h4+`vcTHz6#YW2&kQk3*+cHg5bLCBL}g@#2-H!|UWa;|;REZ%p-+xod=T zhTc_&>bU_QC;MdMd9qgEv%2Ga`oSAv)y4pNz>L z^@W6Rp4Rd1Wz4Xz0kHJZDKp0Jfu@80Sd&kc{AiO;l|9kq=$~wI^k+JGjgy~c%y?kN z&k*l)`DGjp$M~Y`t;WyFe$|+~eG8WU4C(*T_$SAMegB+TfpcZ?aB#rl!R34f$9=a-KIA!kY*?wGbplasck z#*BZuz;rmLmz$gcPgJS!J4x~WuIZpF;+S`ZuEJkEO2t3H^}jOjxo=T^No2ftaSW2W5QYMzfh|YnvWyOj8hU z4I2b+$ejY zG0)_)jL(t1)R?Ay-1t3T+cIOC?5m6k2RAx&cdR$&ed>B+ znv=g~e5dT&jSteX++)l;*SCx*11-i{awvJwnC3&=#6?#Lt8u_jX#24-&7ZiDKdbF2 z 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Μ_~jYD?#8c2(Np5r)A;2Zzh1_#chO7YS77}5 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�|iCRw$(3PtZV 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⋘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�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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/README.md b/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/README.md new file mode 100644 index 0000000000..0fc6ab9096 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/bin/at_sdio/README.md @@ -0,0 +1,81 @@ +# BOOT MODE +## download +### Flash size 8Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0xfc000 (optional) + blank.bin 0x7e000 & 0xfe000 + +### Flash size 16Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0x1fc000 (optional) + blank.bin 0x7e000 & 0x1fe000 + +### Flash size 16Mbit-C1: 1024KB+1024KB + boot_v1.2+.bin 0x00000 + user1.2048.new.5.bin 0x01000 + esp_init_data_default.bin 0x1fc000 (optional) + blank.bin 0xfe000 & 0x1fe000 + +### Flash size 32Mbit: 512KB+512KB + boot_v1.2+.bin 0x00000 + user1.1024.new.2.bin 0x01000 + esp_init_data_default.bin 0x3fc000 (optional) + blank.bin 0x7e000 & 0x3fe000 + +### Flash size 32Mbit-C1: 1024KB+1024KB + boot_v1.2+.bin 0x00000 + user1.2048.new.5.bin 0x01000 + esp_init_data_default.bin 0x3fc000 (optional) + blank.bin 0xfe000 & 0x3fe000 + +# NON-BOOT MODE +## download + eagle.flash.bin 0x00000 + eagle.irom0text.bin 0x10000 + blank.bin + Flash size 8Mbit: 0x7e000 & 0xfe000 + Flash size 16Mbit: 0x7e000 & 0x1fe000 + Flash size 16Mbit-C1: 0xfe000 & 0x1fe000 + Flash size 32Mbit: 0x7e000 & 0x3fe000 + Flash size 32Mbit-C1: 0xfe000 & 0x3fe000 + esp_init_data_default.bin (optional) + Flash size 8Mbit: 0xfc000 + Flash size 16Mbit: 0x1fc000 + Flash size 16Mbit-C1: 0x1fc000 + Flash size 32Mbit: 0x3fc000 + Flash size 32Mbit-C1: 0x3fc000 + +## compile + modify eagle.app.v6.ld, as + irom0_0_seg : org = 0x40210000, len = 0x6C000 + + +> NOTICE: UPDATE is not supported in non-boot mode; 4Mbit Flash is not supported in non-boot mode; + +# Update steps +1.Make sure TE(terminal equipment) is in sta or sta+ap mode + + AT+CWMODE=3 + OK + +2.Make sure TE got ip address + + AT+CWJAP="ssid","12345678" + OK + + AT+CIFSR + 192.168.1.134 + +3.Let's update + + AT+CIUPDATE + +CIPUPDATE:1 found server + +CIPUPDATE:2 connect server + +CIPUPDATE:3 got edition + +CIPUPDATE:4 start start + + OK + +> NOTICE: If there are mistakes in the updating, then break update and print ERROR. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/blank.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/blank.bin new file mode 100644 index 0000000000..7de9e36a64 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/bin/blank.bin @@ -0,0 +1 @@ +ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.2.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..78e12542a5698ca4274623fd8e75b9891c245ad5 GIT binary patch literal 1936 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.7.bin b/Sming/third-party/ESP8266_NONOS_SDK/bin/boot_v1.7.bin new file mode 100644 index 0000000000000000000000000000000000000000..94a1257595379ceeeb12dcb9f328af9c6a8463f4 GIT binary patch literal 4080 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 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "driver/gpio16.h" + +void ICACHE_FLASH_ATTR +gpio16_output_conf(void) +{ + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, + (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 + + WRITE_PERI_REG(RTC_GPIO_CONF, + (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable + + WRITE_PERI_REG(RTC_GPIO_ENABLE, + (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1); //out enable +} + +void ICACHE_FLASH_ATTR +gpio16_output_set(uint8 value) +{ + WRITE_PERI_REG(RTC_GPIO_OUT, + (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1)); +} + +void ICACHE_FLASH_ATTR +gpio16_input_conf(void) +{ + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, + (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection + + WRITE_PERI_REG(RTC_GPIO_CONF, + (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable + + WRITE_PERI_REG(RTC_GPIO_ENABLE, + READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe); //out disable +} + +uint8 ICACHE_FLASH_ATTR +gpio16_input_get(void) +{ + return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/hw_timer.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/hw_timer.c new file mode 100644 index 0000000000..287caa98e5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/hw_timer.c @@ -0,0 +1,162 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" + +#define US_TO_RTC_TIMER_TICKS(t) \ + ((t) ? \ + (((t) > 0x35A) ? \ + (((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)) : \ + (((t) *(APB_CLK_FREQ>>4)) / 1000000)) : \ + 0) + +#define FRC1_ENABLE_TIMER BIT7 +#define FRC1_AUTO_LOAD BIT6 + +//TIMER PREDIVED MODE +typedef enum { + DIVDED_BY_1 = 0, //timer clock + DIVDED_BY_16 = 4, //divided by 16 + DIVDED_BY_256 = 8, //divided by 256 +} TIMER_PREDIVED_MODE; + +typedef enum { //timer interrupt mode + TM_LEVEL_INT = 1, // level interrupt + TM_EDGE_INT = 0, //edge interrupt +} TIMER_INT_MODE; + +typedef enum { + FRC1_SOURCE = 0, + NMI_SOURCE = 1, +} FRC1_TIMER_SOURCE_TYPE; + +/****************************************************************************** +* FunctionName : hw_timer_arm +* Description : set a trigger timer delay for this timer. +* Parameters : uint32 val : +in autoload mode + 50 ~ 0x7fffff; for FRC1 source. + 100 ~ 0x7fffff; for NMI source. +in non autoload mode: + 10 ~ 0x7fffff; +* Returns : NONE +*******************************************************************************/ +void hw_timer_arm(u32 val) +{ + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val)); +} + +static void (* user_hw_timer_cb)(void) = NULL; +/****************************************************************************** +* FunctionName : hw_timer_set_func +* Description : set the func, when trigger timer is up. +* Parameters : void (* user_hw_timer_cb_set)(void): + timer callback function, +* Returns : NONE +*******************************************************************************/ +void hw_timer_set_func(void (* user_hw_timer_cb_set)(void)) +{ + user_hw_timer_cb = user_hw_timer_cb_set; +} + +static void hw_timer_isr_cb(void *arg) +{ + if (user_hw_timer_cb != NULL) { + (*(user_hw_timer_cb))(); + } +} + +static void hw_timer_nmi_cb(void) +{ + if (user_hw_timer_cb != NULL) { + (*(user_hw_timer_cb))(); + } +} + +/****************************************************************************** +* FunctionName : hw_timer_init +* Description : initilize the hardware isr timer +* Parameters : +FRC1_TIMER_SOURCE_TYPE source_type: + FRC1_SOURCE, timer use frc1 isr as isr source. + NMI_SOURCE, timer use nmi isr as isr source. +u8 req: + 0, not autoload, + 1, autoload mode, +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req) +{ + if (req == 1) { + RTC_REG_WRITE(FRC1_CTRL_ADDRESS, + FRC1_AUTO_LOAD | DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT); + } else { + RTC_REG_WRITE(FRC1_CTRL_ADDRESS, + DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT); + } + + if (source_type == NMI_SOURCE) { + ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_nmi_cb); + } else { + ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL); + } + + TM1_EDGE_INT_ENABLE(); + ETS_FRC1_INTR_ENABLE(); +} + +//-------------------------------Test Code Below-------------------------------------- +#if 0 +void hw_test_timer_cb(void) +{ + static uint16 j = 0; + j++; + + if ((WDEV_NOW() - tick_now2) >= 1000000) { + static u32 idx = 1; + tick_now2 = WDEV_NOW(); + os_printf("b%u:%d\n", idx++, j); + j = 0; + } + + //hw_timer_arm(50); +} + +void ICACHE_FLASH_ATTR user_init(void) +{ + hw_timer_init(FRC1_SOURCE, 1); + hw_timer_set_func(hw_test_timer_cb); + hw_timer_arm(100); +} +#endif +/* +NOTE: +1 if use nmi source, for autoload timer , the timer setting val can't be less than 100. +2 if use nmi source, this timer has highest priority, can interrupt other isr. +3 if use frc1 source, this timer can't interrupt other isr. + +*/ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/i2c_master.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/i2c_master.c new file mode 100644 index 0000000000..5f6fc93060 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/i2c_master.c @@ -0,0 +1,330 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "gpio.h" + +#include "driver/i2c_master.h" + +LOCAL uint8 m_nLastSDA; +LOCAL uint8 m_nLastSCL; + +/****************************************************************************** + * FunctionName : i2c_master_setDC + * Description : Internal used function - + * set i2c SDA and SCL bit value for half clk cycle + * Parameters : uint8 SDA + * uint8 SCL + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +i2c_master_setDC(uint8 SDA, uint8 SCL) +{ + SDA &= 0x01; + SCL &= 0x01; + m_nLastSDA = SDA; + m_nLastSCL = SCL; + + if ((0 == SDA) && (0 == SCL)) { + I2C_MASTER_SDA_LOW_SCL_LOW(); + } else if ((0 == SDA) && (1 == SCL)) { + I2C_MASTER_SDA_LOW_SCL_HIGH(); + } else if ((1 == SDA) && (0 == SCL)) { + I2C_MASTER_SDA_HIGH_SCL_LOW(); + } else { + I2C_MASTER_SDA_HIGH_SCL_HIGH(); + } +} + +/****************************************************************************** + * FunctionName : i2c_master_getDC + * Description : Internal used function - + * get i2c SDA bit value + * Parameters : NONE + * Returns : uint8 - SDA bit value +*******************************************************************************/ +LOCAL uint8 ICACHE_FLASH_ATTR +i2c_master_getDC(void) +{ + uint8 sda_out; + sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); + return sda_out; +} + +/****************************************************************************** + * FunctionName : i2c_master_init + * Description : initilize I2C bus to enable i2c operations + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_init(void) +{ + uint8 i; + + i2c_master_setDC(1, 0); + i2c_master_wait(5); + + // when SCL = 0, toggle SDA to clear up + i2c_master_setDC(0, 0) ; + i2c_master_wait(5); + i2c_master_setDC(1, 0) ; + i2c_master_wait(5); + + // set data_cnt to max value + for (i = 0; i < 28; i++) { + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + } + + // reset all + i2c_master_stop(); + return; +} + +/****************************************************************************** + * FunctionName : i2c_master_gpio_init + * Description : config SDA and SCL gpio to open-drain output mode, + * mux and gpio num defined in i2c_master.h + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_gpio_init(void) +{ + ETS_GPIO_INTR_DISABLE() ; +// ETS_INTR_LOCK(); + + PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC); + PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC); + + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO)); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO)); + + I2C_MASTER_SDA_HIGH_SCL_HIGH(); + + ETS_GPIO_INTR_ENABLE() ; +// ETS_INTR_UNLOCK(); + + i2c_master_init(); +} + +/****************************************************************************** + * FunctionName : i2c_master_start + * Description : set i2c to send state + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_start(void) +{ + i2c_master_setDC(1, m_nLastSCL); + i2c_master_wait(5); + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + i2c_master_setDC(0, 1); + i2c_master_wait(5); // sda 0, scl 1 +} + +/****************************************************************************** + * FunctionName : i2c_master_stop + * Description : set i2c to stop sending state + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_stop(void) +{ + i2c_master_wait(5); + + i2c_master_setDC(0, m_nLastSCL); + i2c_master_wait(5); // sda 0 + i2c_master_setDC(0, 1); + i2c_master_wait(5); // sda 0, scl 1 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 +} + +/****************************************************************************** + * FunctionName : i2c_master_setAck + * Description : set ack to i2c bus as level value + * Parameters : uint8 level - 0 or 1 + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_setAck(uint8 level) +{ + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + i2c_master_setDC(level, 0); + i2c_master_wait(5); // sda level, scl 0 + i2c_master_setDC(level, 1); + i2c_master_wait(8); // sda level, scl 1 + i2c_master_setDC(level, 0); + i2c_master_wait(5); // sda level, scl 0 + i2c_master_setDC(1, 0); + i2c_master_wait(5); +} + +/****************************************************************************** + * FunctionName : i2c_master_getAck + * Description : confirm if peer send ack + * Parameters : NONE + * Returns : uint8 - ack value, 0 or 1 +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_getAck(void) +{ + uint8 retVal; + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); + i2c_master_setDC(1, 1); + i2c_master_wait(5); + + retVal = i2c_master_getDC(); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); + + return retVal; +} + +/****************************************************************************** +* FunctionName : i2c_master_checkAck +* Description : get dev response +* Parameters : NONE +* Returns : true : get ack ; false : get nack +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_checkAck(void) +{ + if(i2c_master_getAck()){ + return FALSE; + }else{ + return TRUE; + } +} + +/****************************************************************************** +* FunctionName : i2c_master_send_ack +* Description : response ack +* Parameters : NONE +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_ack(void) +{ + i2c_master_setAck(0x0); +} +/****************************************************************************** +* FunctionName : i2c_master_send_nack +* Description : response nack +* Parameters : NONE +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_nack(void) +{ + i2c_master_setAck(0x1); +} + +/****************************************************************************** + * FunctionName : i2c_master_readByte + * Description : read Byte from i2c bus + * Parameters : NONE + * Returns : uint8 - readed value +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_readByte(void) +{ + uint8 retVal = 0; + uint8 k, i; + + i2c_master_wait(5); + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); // sda 1, scl 0 + + for (i = 0; i < 8; i++) { + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + + k = i2c_master_getDC(); + i2c_master_wait(5); + + if (i == 7) { + i2c_master_wait(3); //// + } + + k <<= (7 - i); + retVal |= k; + } + + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + + return retVal; +} + +/****************************************************************************** + * FunctionName : i2c_master_writeByte + * Description : write wrdata value(one byte) into i2c + * Parameters : uint8 wrdata - write value + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_writeByte(uint8 wrdata) +{ + uint8 dat; + sint8 i; + + i2c_master_wait(5); + + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + + for (i = 7; i >= 0; i--) { + dat = wrdata >> i; + i2c_master_setDC(dat, 0); + i2c_master_wait(5); + i2c_master_setDC(dat, 1); + i2c_master_wait(5); + + if (i == 0) { + i2c_master_wait(3); //// + } + + i2c_master_setDC(dat, 0); + i2c_master_wait(5); + } +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/key.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/key.c new file mode 100644 index 0000000000..2a931607b3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/key.c @@ -0,0 +1,177 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "gpio.h" +#include "user_interface.h" + +#include "driver/key.h" + +LOCAL void key_intr_handler(void *arg); + +/****************************************************************************** + * FunctionName : key_init_single + * Description : init single key's gpio and register function + * Parameters : uint8 gpio_id - which gpio to use + * uint32 gpio_name - gpio mux name + * uint32 gpio_func - gpio function + * key_function long_press - long press function, needed to install + * key_function short_press - short press function, needed to install + * Returns : single_key_param - single key parameter, needed by key init +*******************************************************************************/ +struct single_key_param *ICACHE_FLASH_ATTR +key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press) +{ + struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param)); + + single_key->gpio_id = gpio_id; + single_key->gpio_name = gpio_name; + single_key->gpio_func = gpio_func; + single_key->long_press = long_press; + single_key->short_press = short_press; + + return single_key; +} + +/****************************************************************************** + * FunctionName : key_init + * Description : init keys + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +key_init(struct keys_param *keys) +{ + uint8 i; + + ETS_GPIO_INTR_ATTACH(key_intr_handler, keys); + + ETS_GPIO_INTR_DISABLE(); + + for (i = 0; i < keys->key_num; i++) { + keys->single_key[i]->key_level = 1; + + PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func); + + gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id)); + + gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE) + | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) + | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE)); + + //clear gpio14 status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id)); + + //enable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE); + } + + ETS_GPIO_INTR_ENABLE(); +} + +/****************************************************************************** + * FunctionName : key_5s_cb + * Description : long press 5s timer callback + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_5s_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_5s); + + // low, then restart + if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + if (single_key->long_press) { + single_key->long_press(); + } + } +} + +/****************************************************************************** + * FunctionName : key_50ms_cb + * Description : 50ms timer callback to check it's a real key push + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_50ms_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_50ms); + + // high, then key is up + if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + os_timer_disarm(&single_key->key_5s); + single_key->key_level = 1; + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE); + + if (single_key->short_press) { + single_key->short_press(); + } + } else { + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE); + } +} + +/****************************************************************************** + * FunctionName : key_intr_handler + * Description : key interrupt handler + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +LOCAL void +key_intr_handler(void *arg) +{ + uint8 i; + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + struct keys_param *keys = (struct keys_param *)arg; + + for (i = 0; i < keys->key_num; i++) { + if (gpio_status & BIT(keys->single_key[i]->gpio_id)) { + //disable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE); + + //clear interrupt status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id)); + + if (keys->single_key[i]->key_level == 1) { + // 5s, restart & enter softap mode + os_timer_disarm(&keys->single_key[i]->key_5s); + os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0); + keys->single_key[i]->key_level = 0; + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE); + } else { + // 50ms, check if this is a real key up + os_timer_disarm(&keys->single_key[i]->key_50ms); + os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0); + } + } + } +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/sdio_slv.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/sdio_slv.c new file mode 100644 index 0000000000..43dc87bbb2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/sdio_slv.c @@ -0,0 +1,457 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "driver/slc_register.h" +#include "driver/sdio_slv.h" +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +//#include "gpio.h" +#include "user_interface.h" +#include "mem.h" + +#define SDIO_TOKEN_SIZE 0//4 +#define RX_BUFFER_SIZE 512 +#define RX_BUFFER_NUM 4 + +#define TX_BUFFER_SIZE 512 +#define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA) +#define TRIG_TOHOST_INT() SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\ + //CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0) +struct sdio_queue +{ + uint32 blocksize:12; + uint32 datalen:12; + uint32 unused:5; + uint32 sub_sof:1; + uint32 eof:1; + uint32 owner:1; + + uint32 buf_ptr; + uint32 next_link_ptr; +}; + +struct sdio_slave_status_element +{ + uint32 wr_busy:1; + uint32 rd_empty :1; + uint32 comm_cnt :3; + uint32 intr_no :3; + uint32 rx_length:16; + uint32 res:8; +}; + +union sdio_slave_status +{ + struct sdio_slave_status_element elm_value; + uint32 word_value; +}; + +//uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024]; +uint8 tx_buffer[TX_BUFFER_SIZE]; + +uint32 data_len = 0; + +struct sdio_list { + uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE]; + uint8* tail; + struct sdio_list* next; +}; + +static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL; +struct sdio_list* pHead_ToSend; +struct sdio_list* pTail_ToSend; +struct sdio_list* pHead_Sended; +struct sdio_list* pTail_Sended; + + + +os_event_t * sdioQueue; +struct sdio_queue rx_que,tx_que; + +static bool has_read = 0; + +static void sdio_slave_isr(void *para); +static void tx_buff_handle_done(void); +static void rx_buff_read_done(void); +static void tx_buff_write_done(void); + +static void sdio_try_to_load(void); +static void sdio_read_done_process(void); + +void sdio_slave_init(void) +{ + uint32 regval = 0; + union sdio_slave_status sdio_sta; + ETS_SDIO_INTR_DISABLE(); + ////reset orginal link + SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST); + CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST); + + os_printf("RX&TX link reset!\n"); + + //set sdio mode + SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE); + //clear to host interrupt io signal for preventing from random initial signal. + WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff); + //enable 2 events to trigger the to host intr io + SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA); + ////initialize rx queue information + + has_read = TRUE; + pHead_ToSend = NULL; + + int loop = RX_BUFFER_NUM; + struct sdio_list* p = NULL; + while(loop--) { + if(pHead_Sended == NULL) { + pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list)); + p = pHead_Sended; + } else { + p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list)); + p = p->next; + } + //os_printf("p:0x%08x\r\n",p); + p->tail = p->buffer + SDIO_TOKEN_SIZE; + p->next = NULL; + } + pTail_Sended = p; + + rx_que.blocksize = RX_BUFFER_SIZE; + rx_que.datalen=0; + rx_que.eof=1; + rx_que.owner=1; + rx_que.sub_sof=0; + rx_que.unused=0; + rx_que.buf_ptr=(uint32)pHead_Sended->buffer; + rx_que.next_link_ptr=0; + + + ////initialize tx queue information + tx_que.blocksize=TX_BUFFER_SIZE; + tx_que.datalen=0; + tx_que.eof=0; + tx_que.owner=1; + tx_que.sub_sof=0; + tx_que.unused=0; + tx_que.buf_ptr=(uint32)tx_buffer; + tx_que.next_link_ptr=0; + + ///////link tx&rx queue information address to sdio hardware + CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK); + regval= ((uint32)&rx_que); + SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK); + CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK); + regval= ((uint32)&tx_que); + SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK); + +#if (SDIO_TOKEN_SIZE == 0) + SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE); +#endif + + /////config sdio_status reg + sdio_sta.elm_value.comm_cnt=7; + sdio_sta.elm_value.intr_no=INIT_STAGE; + sdio_sta.elm_value.wr_busy=0; + sdio_sta.elm_value.rd_empty=1; + sdio_sta.elm_value.rx_length=0; + sdio_sta.elm_value.res=0; + SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); + + + /////attach isr func to sdio interrupt + ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL); + /////enable sdio operation intr + WRITE_PERI_REG(SLC_INT_ENA, SLC_INTEREST_EVENT); + /////clear sdio initial random active intr signal + WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff); + /////enable sdio intr in cpu + ETS_SDIO_INTR_ENABLE(); +} + +static void sdio_slave_isr(void *para) +{ + uint32 slc_intr_status,postval; + static uint8 state =0; + uint16 rx_len,i; + uint32* pword; + union sdio_slave_status sdio_sta; + + slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); + + if (slc_intr_status == 0) + { + /* No interested interrupts pending */ + return; + } + //clear all intrs + WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status); + //os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status); + //process every intr + + //TO HOST DONE + if (slc_intr_status & SLC_RX_EOF_INT_ENA) + { + //following code must be called after a data pack has been read + rx_buff_read_done(); + //TRIG_TOHOST_INT(); + //system_os_post(2, 1, 0); + sdio_read_done_process(); + } + + //FROM HOST DONE + if (slc_intr_status & SLC_TX_EOF_INT_ENA) + { + //call the following function after host cpu data transmission finished + tx_buff_write_done(); + + //system_os_post(USER_TASK_PRIO_1,SDIO_DATA_ERROR,0); + //os_printf("%d,%s\r\n",tx_que.datalen,tx_que.buf_ptr); + //at_fake_uart_rx((uint8*)tx_que.buf_ptr,tx_que.datalen); + if(sdio_recv_data_callback_ptr) { + sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen); + } + tx_buff_handle_done(); + TRIG_TOHOST_INT(); + //system_os_post(2, 3, 0); + } + + //TO HOST underflow + if(slc_intr_status & SLC_RX_UDF_INT_ENA) + { + } + + //FROM HOST overflow + if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA) + { + } + + slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); + if(slc_intr_status) + { + WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status); + os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status); + } + +} + +static void rx_buff_read_done(void) +{ + union sdio_slave_status sdio_sta; + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.comm_cnt++; + sdio_sta.elm_value.rd_empty=1; + sdio_sta.elm_value.rx_length=0; + sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //os_printf("rx_buff_read_done\r\n"); +} + +static void tx_buff_write_done(void) +{ + union sdio_slave_status sdio_sta; + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.comm_cnt++; + sdio_sta.elm_value.wr_busy=1; + sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register +} + +static void tx_buff_handle_done(void) +{ + union sdio_slave_status sdio_sta; + + /////config tx queue information + tx_que.blocksize=TX_BUFFER_SIZE; + tx_que.datalen=0; + tx_que.eof=0; + tx_que.owner=1; + + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.wr_busy=0; + sdio_sta.elm_value.intr_no |= TX_AVAILIBLE; + + SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); //tx buffer is ready for being written + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //*******************************************************************// + +} +static int32 rx_buff_load_done(uint16 rx_len) +{ + union sdio_slave_status sdio_sta; + + if(rx_len == 0) { + return 0; + } + if(rx_len > rx_que.blocksize) + { + rx_len = rx_que.blocksize; + } + + //os_memcpy(rx_que.buf_ptr,data,rx_len); + /////config rx queue information + rx_que.blocksize=RX_BUFFER_SIZE; + rx_que.datalen=rx_len + SDIO_TOKEN_SIZE; + rx_que.eof=1; + rx_que.owner=1; + + //ETS_SDIO_INTR_DISABLE(); + //available_buffer_amount--; + + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.rd_empty=0; + sdio_sta.elm_value.intr_no |= RX_AVAILIBLE; + sdio_sta.elm_value.rx_length=rx_len; + + SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); //rx buffer is ready for being read + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //ETS_SDIO_INTR_ENABLE(); + //os_printf("rx_buff_load_done(%d,0x%08x):%s\r\n",rx_len,rx_que.buf_ptr,rx_que.buf_ptr); + //os_printf("rx_buff_load_done:%d\r\n",rx_len); + return rx_len; +} + +int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len) +{ + int32 data_len = 0; + + if (pHead_Sended == NULL) { + os_printf("no buf\r\n"); + return 0; + } + int32 left_len = 0; + + while(len) + { + left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(pHead_Sended->tail - pHead_Sended->buffer); + if(len < left_len) + { + os_memcpy(pHead_Sended->tail,data,len); + pHead_Sended->tail += len; + len = 0; + data_len += len; + //os_printf(">555:0x%08x,0x%08x\r\n",pHead_Sended->buffer,pHead_Sended->tail); + } + else + { + os_memcpy(pHead_Sended->tail,data,left_len); + pHead_Sended->tail += left_len; + len -= left_len; + data += left_len; + data_len += left_len; + if(pHead_ToSend == NULL) { + pTail_ToSend = pHead_Sended; + pHead_ToSend = pTail_ToSend; + } else { + pTail_ToSend->next = pHead_Sended; + pTail_ToSend = pTail_ToSend->next; + } + pHead_Sended = pHead_Sended->next; + + pTail_ToSend->next = NULL; + if(pHead_Sended == NULL) + { + os_printf("buf full\r\n"); + break; + } + //os_printf(">666\r\n"); + } + } + + //os_printf(">>pHead_ToSend:0x%08x\r\n",pHead_ToSend); + + if(pHead_ToSend == NULL) { + pTail_ToSend = pHead_Sended; + pHead_ToSend = pTail_ToSend; + + pHead_Sended = pHead_Sended->next; + pTail_ToSend->next = NULL; + //system_os_post(2, 2, 0); + sdio_try_to_load(); + } + return data_len; +} + +static void sdio_try_to_load(void) +{ + if((has_read == TRUE) && (pHead_ToSend != NULL)) + { + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + //pHead_ToSend = pHead_ToSend->next; + has_read = FALSE; + //os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS)); + TRIG_TOHOST_INT(); + } +} + +static void sdio_read_done_process(void) +{ + has_read = TRUE; + + pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE; + if(pHead_Sended) { + pTail_Sended->next = pHead_ToSend; + pTail_Sended = pTail_Sended->next; + }else { + pTail_Sended = pHead_ToSend; + pHead_Sended = pTail_Sended; + } + pHead_ToSend = pHead_ToSend->next; + pTail_Sended->next = NULL; + //os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail); + if(pHead_ToSend) { + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + has_read = FALSE; + //os_printf("intr trig\r\n"); + //TRIG_TOHOST_INT(); + } else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) { + pHead_ToSend = pHead_Sended; + pTail_ToSend = pHead_ToSend; + pHead_Sended = pHead_Sended->next; + pTail_ToSend->next = NULL; + + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + has_read = FALSE; + //os_printf("intr trig\r\n"); + //TRIG_TOHOST_INT(); + } + + TRIG_TOHOST_INT(); +} + +bool sdio_register_recv_cb(sdio_recv_data_callback_t cb) +{ + sdio_recv_data_callback_ptr = cb; + + return TRUE; +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi.c new file mode 100644 index 0000000000..1324eb19be --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi.c @@ -0,0 +1,487 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "driver/spi.h" +#include "driver/spi_overlap.h" + +#define CACHE_FLASH_CTRL_REG 0x3ff0000C +#define CACHE_FLUSH_START_BIT BIT0 +#define CACHE_EMPTY_FLAG_BIT BIT1 +/****************************************************************************** + * FunctionName : cache_flush + * Description : clear all the cpu cache data for stability test. +*******************************************************************************/ +void cache_flush(void) +{ + while(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT) { + CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT); + SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT); + } + while(!(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT)); + + CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT); +} +/****************************************************************************** + * FunctionName : spi_master_init + * Description : SPI master initial function for common byte units transmission + * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid +*******************************************************************************/ +void ICACHE_FLASH_ATTR + spi_master_init(uint8 spi_no) +{ + uint32 regvalue; + + if(spi_no>1) return; //handle invalid input number + + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); + + WRITE_PERI_REG(SPI_CLOCK(spi_no), + ((3&SPI_CLKCNT_N)<1) return; //handle invalid input number + + if(high_bit) bytetemp=(low_8bit>>1)|0x80; + else bytetemp=(low_8bit>>1)&0x7f; + + regvalue= ((8&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number + + while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO); + + //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, + // bit15-0 is cmd value. + WRITE_PERI_REG(SPI_USER2(spi_no), + ((7&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number + + while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY); + + //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, + // bit15-0 is cmd value. + //0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value + WRITE_PERI_REG(SPI_USER2(spi_no), + ((7&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number + + while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); + + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY); + //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, + // bit15-0 is cmd value. + //0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value + WRITE_PERI_REG(SPI_USER2(spi_no), + ((7&SPI_USR_COMMAND_BITLEN)<1) + return; //handle invalid input number + if(data_len<=1) data_bit_len=7; + else if(data_len>=32) data_bit_len=0xff; + else data_bit_len=(data_len<<3)-1; + + //clear bit9,bit8 of reg PERIPHS_IO_MUX + //bit9 should be cleared when HSPI clock doesn't equal CPU clock + //bit8 should be cleared when SPI clock doesn't equal CPU clock + ////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST + if(spi_no==SPI){ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode + }else if(spi_no==HSPI){ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode + } + + //regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no)); + //slave mode,slave use buffers which are register "SPI_FLASH_C0~C15", enable trans done isr + //set bit 30 bit 29 bit9,bit9 is trans done isr mask + SET_PERI_REG_MASK( SPI_SLAVE(spi_no), + SPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN| + SPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN| + SPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN| + SPI_TRANS_DONE_EN); + //disable general trans intr + //CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN); + + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode + SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15 + + +//////**************RUN WHEN SLAVE RECIEVE*******************/////// + //tow lines below is to configure spi timing. + SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<>8)&0xff; + spi_data[(idx<<2)+2] = (recv_data>>16)&0xff; + spi_data[(idx<<2)+3] = (recv_data>>24)&0xff; + idx++; + } + //add system_os_post here + GPIO_OUTPUT_SET(0, 1); + } + if(regvalue&SPI_SLV_RD_BUF_DONE){ + //it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended. + GPIO_OUTPUT_SET(2, 0); + //add system_os_post here + //system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue); + + } + + }else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr, + + } +} + + +#ifdef SPI_SLAVE_DEBUG + +void ICACHE_FLASH_ATTR + set_miso_data() +{ + if(GPIO_INPUT_GET(2)==0){ + WRITE_PERI_REG(SPI_W8(HSPI),0x05040302); + WRITE_PERI_REG(SPI_W9(HSPI),0x09080706); + WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a); + WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e); + + WRITE_PERI_REG(SPI_W12(HSPI),0x15141312); + WRITE_PERI_REG(SPI_W13(HSPI),0x19181716); + WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a); + WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e); + GPIO_OUTPUT_SET(2, 1); + } +} + + + +void ICACHE_FLASH_ATTR + disp_spi_data() +{ + uint8 i = 0; + for(i=0;i<32;i++){ + os_printf("data %d : 0x%02x\n\r",i,spi_data[i]); + } + //os_printf("d31:0x%02x\n\r",spi_data[31]); +} + + +void ICACHE_FLASH_ATTR + spi_task(os_event_t *e) +{ + uint8 data; + switch(e->sig){ + case MOSI: + disp_spi_data(); + break; + case STATUS_R_IN_WR : + os_printf("SR ERR in WRPR,Reg:%08x \n",e->par); + break; + case STATUS_W: + os_printf("SW ERR,Reg:%08x\n",e->par); + break; + case TR_DONE_ALONE: + os_printf("TD ALO ERR,Reg:%08x\n",e->par); + break; + case WR_RD: + os_printf("WR&RD ERR,Reg:%08x\n",e->par); + break; + case DATA_ERROR: + os_printf("Data ERR,Reg:%08x\n",e->par); + break; + case STATUS_R_IN_RD : + os_printf("SR ERR in RDPR,Reg:%08x\n",e->par); + break; + default: + break; + } +} + +void ICACHE_FLASH_ATTR + spi_task_init(void) +{ + spiQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*SPI_QUEUE_LEN); + system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN); +} + +os_timer_t spi_timer_test; + +void ICACHE_FLASH_ATTR + spi_test_init() +{ + os_printf("spi init\n\r"); + spi_slave_init(HSPI); + os_printf("gpio init\n\r"); + gpio_init(); + os_printf("spi task init \n\r"); + spi_task_init(); +#ifdef SPI_MISO + os_printf("spi miso init\n\r"); + set_miso_data(); +#endif + + //os_timer_disarm(&spi_timer_test); + //os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl + //os_timer_arm(&spi_timer_test,50,1); +} + +#endif + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_interface.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_interface.c new file mode 100644 index 0000000000..0760ecfdbd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_interface.c @@ -0,0 +1,502 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/** + * @file spi_interface.c + * @brief Defines and Macros for the SPI. + */ + +#include "driver/spi_interface.h" +#include "osapi.h" +#include "ets_sys.h" + +//***************************************************************************** +// +// Make sure all of the definitions in this header have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Based on pAttr initialize SPI module. + * + */ +void ICACHE_FLASH_ATTR SPIInit(SpiNum spiNum, SpiAttr* pAttr) +{ + if ((spiNum > SpiNum_HSPI) + || (NULL == pAttr)) { + return; + } + // SPI_CPOL & SPI_CPHA + switch (pAttr->subMode) { + case SpiSubMode_1: + CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE); + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE + break; + case SpiSubMode_2: + SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE); + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE + break; + case SpiSubMode_3: + SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_CK_OUT_EDGE); + break; + case SpiSubMode_0: + default: + CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_CK_OUT_EDGE); + // To do nothing + break; + } + + // SPI bit order + if (SpiBitOrder_MSBFirst == pAttr->bitOrder) { + CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER); + CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER); + } else if (SpiBitOrder_LSBFirst == pAttr->bitOrder) { + SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER); + SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER); + } else { + // To do nothing + } + + // Disable flash operation mode + // As earlier as better, if not SPI_CTRL2 can not to be set delay cycles. + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_FLASH_MODE); + + // SPI mode type + if (SpiMode_Master == pAttr->mode) { + // SPI mode type + CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE); + // SPI Send buffer + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7 + // SPI Speed + if (1 < (pAttr->speed)) { + uint8 i, k; + i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1; + k = pAttr->speed / i; + CLEAR_PERI_REG_MASK(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK); + WRITE_PERI_REG(SPI_CLOCK(spiNum), + (((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | + (((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | + ((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | + (((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div + } else { + WRITE_PERI_REG(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed + } + // By default format:CMD+ADDR+DATA + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI ); + + //delay num + SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S)); + } else if (SpiMode_Slave == pAttr->mode) { + // BIT19 must do + SET_PERI_REG_MASK(SPI_PIN(spiNum), BIT19); + + // SPI mode type + SET_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE); + // SPI Send buffer + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15 + + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + + // If do not set delay cycles, slave not working,master cann't get the data. + SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num + // SPI Speed + WRITE_PERI_REG(SPI_CLOCK(spiNum), 0); + + // By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes). + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN, + 7, SPI_USR_COMMAND_BITLEN_S); + SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_WR_ADDR_BITLEN, + 7, SPI_SLV_WR_ADDR_BITLEN_S); + SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_RD_ADDR_BITLEN, + 7, SPI_SLV_RD_ADDR_BITLEN_S); + SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_BUF_BITLEN, + (32 * 8 - 1), SPI_SLV_BUF_BITLEN_S); + // For 8266 work on slave mode. + SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_STATUS_BITLEN, + 7, SPI_SLV_STATUS_BITLEN_S); + } else { + // To do nothing + } + + //clear Daul or Quad lines transmission mode + CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_QIO_MODE | SPI_DIO_MODE | SPI_DOUT_MODE | SPI_QOUT_MODE); + // Clear the data buffer. + uint8 i; + uint32 regAddr = REG_SPI_BASE(spiNum) + 0x40; + for (i = 0; i < 16; ++i) { + WRITE_PERI_REG(regAddr, 0); + regAddr += 4; + } + +} + +/** + * @brief Set address value by master mode. + * + */ +void ICACHE_FLASH_ATTR SPIMasterCfgAddr(SpiNum spiNum, uint32_t addr) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + // Set address + WRITE_PERI_REG(SPI_ADDR(spiNum), addr); +} + +/** + * @brief Set command value by master mode. + * + */ +void ICACHE_FLASH_ATTR SPIMasterCfgCmd(SpiNum spiNum, uint32_t cmd) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + // SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, + // bit15-0 is cmd value. + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S); +} + +/** + * @brief Send data to slave. + * + */ +int ICACHE_FLASH_ATTR SPIMasterSendData(SpiNum spiNum, SpiData* pInData) +{ + char idx = 0; + if ((spiNum > SpiNum_HSPI) + || (NULL == pInData) + || (64 < pInData->dataLen)) { + return -1; + } + uint32_t *value = pInData->data; + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + // Set command by user. + if (pInData->cmdLen != 0) { + // Max command length 16 bits. + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN, + ((pInData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S); + // Enable command + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND); + // Load command + SPIMasterCfgCmd(spiNum, pInData->cmd); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND); + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN, + 0, SPI_USR_COMMAND_BITLEN_S); + } + // Set Address by user. + if (pInData->addrLen == 0) { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR); + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN, + 0, SPI_USR_ADDR_BITLEN_S); + } else { + if (NULL == pInData->addr) { + return -1; + } + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN, + ((pInData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S); + // Enable address + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR); + // Load address + SPIMasterCfgAddr(spiNum, *pInData->addr); + } + // Set data by user. + if (pInData->dataLen != 0) { + if (NULL == value) { + return -1; + } + // Enable MOSI + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO); + // Load send buffer + do { + WRITE_PERI_REG((SPI_W0(spiNum) + (idx << 2)), *value++); + } while (++idx < ((pInData->dataLen / 4) + ((pInData->dataLen % 4) ? 1 : 0))); + // Set data send buffer length.Max data length 64 bytes. + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN, ((pInData->dataLen << 3) - 1), SPI_USR_MOSI_BITLEN_S); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN, + 0, SPI_USR_MOSI_BITLEN_S); + } + // Start send data + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + // Wait for transmit done + while (!(READ_PERI_REG(SPI_SLAVE(spiNum))&SPI_TRANS_DONE)); + CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_TRANS_DONE); + return 0; +} + +/** + * @brief Receive data from slave. + * + */ +int ICACHE_FLASH_ATTR SPIMasterRecvData(SpiNum spiNum, SpiData* pOutData) +{ + char idx = 0; + if ((spiNum > SpiNum_HSPI) + || (NULL == pOutData)) { + return -1; + } + + uint32_t *value = pOutData->data; + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + // Set command by user. + if (pOutData->cmdLen != 0) { + // Max command length 16 bits. + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN, + ((pOutData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S); + // Enable command + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND); + // Load command + SPIMasterCfgCmd(spiNum, pOutData->cmd); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND); + SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN, + 0, SPI_USR_COMMAND_BITLEN_S); + } + // Set Address by user. + if (pOutData->addrLen == 0) { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR); + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN, + 0, SPI_USR_ADDR_BITLEN_S); + } else { + if (NULL == pOutData->addr) { + return -1; + } + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN, + ((pOutData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S); + // Enable address + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR); + // Load address + SPIMasterCfgAddr(spiNum, *pOutData->addr); + } + // Set data by user. + if (pOutData->dataLen != 0) { + if (NULL == value) { + return -1; + } + // Clear MOSI enable + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + // Enable MOSI + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO); + // Set data send buffer length.Max data length 64 bytes. + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN, ((pOutData->dataLen << 3) - 1), SPI_USR_MISO_BITLEN_S); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO); + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN, + 0, SPI_USR_MISO_BITLEN_S); + } + // Start send data + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + // Read data out + do { + *value++ = READ_PERI_REG(SPI_W0(spiNum) + (idx << 2)); + } while (++idx < ((pOutData->dataLen / 4) + ((pOutData->dataLen % 4) ? 1 : 0))); + + + return 0; +} + +/** + * @brief Load data to send buffer by slave mode. + * + */ +int ICACHE_FLASH_ATTR SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t inLen) +{ + if (NULL == pInData) { + return -1; + } + uint32_t *value = pInData; + char i; + for (i = 0; i < inLen; ++i) { + WRITE_PERI_REG((SPI_W8(spiNum) + (i << 2)), *value++); + } + // Enable slave transmission liston + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + return 0; +} + +/** + * @brief Configurate slave prepare for receive data. + * + */ +int ICACHE_FLASH_ATTR SPISlaveRecvData(SpiNum spiNum) +{ + if ((spiNum > SpiNum_HSPI)) { + return -1; + } + // Enable slave transmission liston + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + + return 0; +} + +/** + * @brief Send data to slave(ESP8266 register of RD_STATUS or WR_STATUS). + * + */ +void ICACHE_FLASH_ATTR SPIMasterSendStatus(SpiNum spiNum, uint8_t data) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + // Enable MOSI + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR); + + // 8bits cmd, 0x04 is eps8266 slave write cmd value + WRITE_PERI_REG(SPI_USER2(spiNum), + ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) + | MASTER_WRITE_STATUS_TO_SLAVE_CMD); + // Set data send buffer length. + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN, + ((sizeof(data) << 3) - 1), SPI_USR_MOSI_BITLEN_S); + + WRITE_PERI_REG(SPI_W0(spiNum), (uint32)(data)); + // Start SPI + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + +} + +/** + * @brief Receive status register from slave(ESP8266). + * + */ +int ICACHE_FLASH_ATTR SPIMasterRecvStatus(SpiNum spiNum) +{ + if (spiNum > SpiNum_HSPI) { + return -1; + } + + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + // Enable MISO + SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO); + CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR); + + // 8bits cmd, 0x06 is eps8266 slave read status cmd value + WRITE_PERI_REG(SPI_USER2(spiNum), + ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) + | MASTER_READ_STATUS_FROM_SLAVE_CMD); + // Set revcive buffer length. + SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN, + 7, SPI_USR_MISO_BITLEN_S); + + // start spi module. + SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR); + + while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR); + + uint8_t data = (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff); + + return (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff); +} + +/** + * @brief Select SPI CS pin. + * + */ +void ICACHE_FLASH_ATTR SPICsPinSelect(SpiNum spiNum, SpiPinCS pinCs) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + // clear select + SET_PERI_REG_BITS(SPI_PIN(spiNum), 3, 0, 0); + SET_PERI_REG_MASK(SPI_PIN(spiNum), pinCs); +} + + +void SPIIntCfg(SpiNum spiNum, SpiIntInfo *pIntInfo) +{ + if ((spiNum > SpiNum_HSPI) + || (NULL == pIntInfo)) { + return; + } + // Clear the interrupt source and disable all of the interrupt. + CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), 0x3FF); + SPIIntEnable(spiNum, pIntInfo->src); + os_printf("src=%x\r\n,isrFunc=%x", (pIntInfo->src << 5), pIntInfo->isrFunc); + // + ETS_SPI_INTR_ATTACH(pIntInfo->isrFunc, NULL); + // Enable isr + ETS_SPI_INTR_ENABLE(); +} + + +/** + * @brief Enable SPI interrupt source. + * + */ +void ICACHE_FLASH_ATTR SPIIntEnable(SpiNum spiNum, SpiIntSrc intSrc) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + SET_PERI_REG_MASK(SPI_SLAVE(spiNum), (intSrc << 5)); +} + +/** + * @brief Disable SPI interrupt source. + * + */ +void ICACHE_FLASH_ATTR SPIIntDisable(SpiNum spiNum, SpiIntSrc intSrc) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), intSrc); +} + +/** + * @brief Clear all of SPI interrupt source. + * + */ +void ICACHE_FLASH_ATTR SPIIntClear(SpiNum spiNum) +{ + if (spiNum > SpiNum_HSPI) { + return; + } + CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SpiIntSrc_TransDone + | SpiIntSrc_WrStaDone + | SpiIntSrc_RdStaDone + | SpiIntSrc_WrBufDone + | SpiIntSrc_RdBufDone); +} + + +#ifdef __cplusplus +} +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_overlap.c b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_overlap.c new file mode 100644 index 0000000000..1e8d32df98 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/driver/spi_overlap.c @@ -0,0 +1,422 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "driver/spi_overlap.h" +#include "driver/spi.h" +#include "gpio.h" + +#define SPI_FLASH_READ_MODE_MASK 0x196000 +#define WAIT_HSPI_IDLE() while(READ_PERI_REG(SPI_EXT2(HSPI))||(READ_PERI_REG(SPI_CMD(HSPI))&0xfffc0000)); +#define CONF_HSPI_CLK_DIV(div) WRITE_PERI_REG(SPI_CLOCK(HSPI), (((div<<1)+1)<<12)+(div<<6)+(div<<1)+1) +#define HSPI_FALLING_EDGE_SAMPLE() SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE) +#define HSPI_RISING_EDGE_SAMPLE() CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE) +#define ACTIVE_HSPI_CS0 CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS);\ + SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS |SPI_CS2_DIS) +#define ACTIVE_HSPI_CS1 CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS);\ + SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS2_DIS) +#define ACTIVE_HSPI_CS2 CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS2_DIS);\ + SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS1_DIS) +#define ENABLE_HSPI_DEV_CS() PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2) +#define DISABLE_HSPI_DEV_CS() GPIO_OUTPUT_SET(15, 1);\ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15) +struct hspi_device_register hspi_dev_reg; +/****************************************************************************** + * FunctionName : hspi_overlap_init + * Description : enable hspi and spi module overlap mode +*******************************************************************************/ +void ICACHE_FLASH_ATTR +hspi_overlap_init(void) +{ + //hspi overlap to spi, two spi masters on cspi + SET_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap); + + //set higher priority for spi than hspi + SET_PERI_REG_MASK(SPI_EXT3(SPI),0x1); + SET_PERI_REG_MASK(SPI_EXT3(HSPI),0x3); + SET_PERI_REG_MASK(SPI_USER(HSPI), BIT(5)); +} +/****************************************************************************** + * FunctionName : hspi_overlap_deinit + * Description : recover hspi and spi module from overlap mode +*******************************************************************************/ +void ICACHE_FLASH_ATTR +hspi_overlap_deinit(void) +{ + //hspi overlap to spi, two spi masters on cspi + CLEAR_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap); + + //set higher priority for spi than hspi + CLEAR_PERI_REG_MASK(SPI_EXT3(SPI),0x1); + CLEAR_PERI_REG_MASK(SPI_EXT3(HSPI),0x3); + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), BIT(5)); +} + +/****************************************************************************** + * FunctionName : spi_reg_backup + * Description : backup SPI normal operation register value and disable CPU cache to modify some flash registers. + * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid +*******************************************************************************/ +void ICACHE_FLASH_ATTR + spi_reg_backup(uint8 spi_no,uint32* backup_mem) +{ + if(spi_no>1) return; //handle invalid input number + + backup_mem[PERIPHS_IO_MUX_BACKUP] =READ_PERI_REG(PERIPHS_IO_MUX); + backup_mem[SPI_USER_BACKUP] =READ_PERI_REG(SPI_USER(spi_no)); + backup_mem[SPI_CTRL_BACKUP] =READ_PERI_REG(SPI_CTRL(spi_no)); + backup_mem[SPI_CLOCK_BACKUP] =READ_PERI_REG(SPI_CLOCK(spi_no)); + backup_mem[SPI_USER1_BACKUP] =READ_PERI_REG(SPI_USER1(spi_no)); + backup_mem[SPI_USER2_BACKUP] =READ_PERI_REG(SPI_USER2(spi_no)); + backup_mem[SPI_CMD_BACKUP] =READ_PERI_REG(SPI_CMD(spi_no)); + backup_mem[SPI_PIN_BACKUP] =READ_PERI_REG(SPI_PIN(spi_no)); + backup_mem[SPI_SLAVE_BACKUP] =READ_PERI_REG(SPI_SLAVE(spi_no)); +} +/****************************************************************************** + * FunctionName : spi_reg_recover + * Description : recover SPI normal operation register value and enable CPU cache. + * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid +*******************************************************************************/ +void ICACHE_FLASH_ATTR + spi_reg_recover(uint8 spi_no,uint32* backup_mem) +{ + if(spi_no>1) return; //handle invalid input number + +// WRITE_PERI_REG(PERIPHS_IO_MUX, backup_mem[PERIPHS_IO_MUX_BACKUP]); + WRITE_PERI_REG(SPI_USER(spi_no), backup_mem[SPI_USER_BACKUP]); + WRITE_PERI_REG(SPI_CTRL(spi_no), backup_mem[SPI_CTRL_BACKUP]); + WRITE_PERI_REG(SPI_CLOCK(spi_no), backup_mem[SPI_CLOCK_BACKUP]); + WRITE_PERI_REG(SPI_USER1(spi_no), backup_mem[SPI_USER1_BACKUP]); + WRITE_PERI_REG(SPI_USER2(spi_no), backup_mem[SPI_USER2_BACKUP]); + WRITE_PERI_REG(SPI_CMD(spi_no), backup_mem[SPI_CMD_BACKUP]); + WRITE_PERI_REG(SPI_PIN(spi_no), backup_mem[SPI_PIN_BACKUP]); +// WRITE_PERI_REG(SPI_SLAVE(spi_no), backup_mem[SPI_SLAVE_BACKUP]); +} + +void ICACHE_FLASH_ATTR + hspi_master_dev_init(uint8 dev_no,uint8 clk_polar,uint8 clk_div) +{ + uint32 regtemp; + if((dev_no>3)||(clk_polar>1)||(clk_div>0x1f)) + { + os_printf("hspi_master_dev_init parameter is out of range!\n\r"); + return; + } + + WAIT_HSPI_IDLE(); + if(!hspi_dev_reg.hspi_reg_backup_flag){ + if(READ_PERI_REG(PERIPHS_IO_MUX)&BIT8){ + hspi_dev_reg.spi_io_80m=1; + SET_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK); + }else{ + hspi_dev_reg.spi_io_80m=0; + CLEAR_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK); + } + + regtemp=READ_PERI_REG(SPI_CTRL(SPI))&SPI_FLASH_READ_MODE_MASK; + CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_FLASH_READ_MODE_MASK); + SET_PERI_REG_MASK(SPI_CTRL(HSPI), regtemp); + spi_reg_backup(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + + spi_master_init(HSPI); + spi_reg_backup(HSPI, hspi_dev_reg.hspi_dev_reg_backup); + + hspi_dev_reg.hspi_reg_backup_flag=1; + + // spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + hspi_dev_reg.selected_dev_num=HSPI_IDLE; + } + + hspi_dev_reg.hspi_dev_conf[dev_no].active=1; + hspi_dev_reg.hspi_dev_conf[dev_no].clk_div=clk_div; + hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar=clk_polar; + + switch(dev_no){ + case HSPI_CS_DEV : + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9); + break; + + case SPI_CS1_DEV : + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_SPI_CS1); + if(hspi_dev_reg.spi_io_80m){ + os_printf("SPI CS1 device must work at 80Mhz"); + } + break; + + case SPI_CS2_DEV : + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_SPI_CS2); + if(hspi_dev_reg.spi_io_80m){ + os_printf("SPI CS2 device must work at 80Mhz"); + } + break; + + default: break; + } +} + +void ICACHE_FLASH_ATTR + hspi_dev_sel(uint8 dev_no) +{ + uint32 regval; + + if(dev_no>3){ + os_printf("hspi_dev_sel parameter is out of range!\n\r"); + return; + } + + if(!hspi_dev_reg.hspi_dev_conf[dev_no].active){ + os_printf("device%d has not been initialized!\n\r",dev_no); + return; + } + + switch(hspi_dev_reg.selected_dev_num){ + case HSPI_CS_DEV: + if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){ + WAIT_HSPI_IDLE(); + DISABLE_HSPI_DEV_CS(); + hspi_overlap_init(); + + if(hspi_dev_reg.spi_io_80m) {SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);} + else {CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);} + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + if(dev_no==SPI_CS1_DEV) {ACTIVE_HSPI_CS1;} + else {ACTIVE_HSPI_CS2;} + } + else if(dev_no==SPI_CS0_FLASH){ + WAIT_HSPI_IDLE(); + DISABLE_HSPI_DEV_CS(); + hspi_overlap_init(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + + if(hspi_dev_reg.spi_io_80m) {SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);} + + HSPI_RISING_EDGE_SAMPLE(); + ACTIVE_HSPI_CS0 ; + } + break; + + case SPI_CS1_DEV: + if(dev_no==SPI_CS2_DEV){ + WAIT_HSPI_IDLE(); + if(!hspi_dev_reg.spi_io_80m) {CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);} + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + ACTIVE_HSPI_CS2; + } + else if(dev_no==SPI_CS0_FLASH){ + WAIT_HSPI_IDLE(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + HSPI_RISING_EDGE_SAMPLE(); + ACTIVE_HSPI_CS0; + } + else if(dev_no==HSPI_CS_DEV){ + WAIT_HSPI_IDLE(); + ENABLE_HSPI_DEV_CS(); + hspi_overlap_deinit(); + CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div); + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + ACTIVE_HSPI_CS0; + } + break; + + case SPI_CS2_DEV: + if(dev_no==SPI_CS1_DEV){ + WAIT_HSPI_IDLE(); + if(!hspi_dev_reg.spi_io_80m) {CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);} + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + ACTIVE_HSPI_CS1; + } + else if(dev_no==SPI_CS0_FLASH){ + WAIT_HSPI_IDLE(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + HSPI_RISING_EDGE_SAMPLE(); + ACTIVE_HSPI_CS0; + } + else if(dev_no==HSPI_CS_DEV){ + WAIT_HSPI_IDLE(); + ENABLE_HSPI_DEV_CS(); + hspi_overlap_deinit(); + CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div); + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + ACTIVE_HSPI_CS0; + } + break; + + case SPI_CS0_FLASH: + if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){ + WAIT_HSPI_IDLE(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup); + + if(hspi_dev_reg.spi_io_80m) {SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);} + else {CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);} + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + if(dev_no==SPI_CS1_DEV) {ACTIVE_HSPI_CS1;} + else {ACTIVE_HSPI_CS2;} + } + else if(dev_no==HSPI_CS_DEV){ + WAIT_HSPI_IDLE(); + ENABLE_HSPI_DEV_CS(); + hspi_overlap_deinit(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup); + CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div); + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + ACTIVE_HSPI_CS0; + } + break; + + default: + if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){ + WAIT_HSPI_IDLE(); + DISABLE_HSPI_DEV_CS(); + hspi_overlap_init(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup); + + if(hspi_dev_reg.spi_io_80m) {SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);} + else {CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);} + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + if(dev_no==SPI_CS1_DEV) {ACTIVE_HSPI_CS1;} + else {ACTIVE_HSPI_CS2;} + } + else if(dev_no==SPI_CS0_FLASH){ + WAIT_HSPI_IDLE(); + DISABLE_HSPI_DEV_CS(); + hspi_overlap_init(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup); + + if(hspi_dev_reg.spi_io_80m) {SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);} + + HSPI_RISING_EDGE_SAMPLE(); + ACTIVE_HSPI_CS0 ; + } + else if(dev_no==HSPI_CS_DEV){ + WAIT_HSPI_IDLE(); + ENABLE_HSPI_DEV_CS(); + hspi_overlap_deinit(); + spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup); + CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div); + + if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar) {HSPI_FALLING_EDGE_SAMPLE();} + else {HSPI_RISING_EDGE_SAMPLE();} + + ACTIVE_HSPI_CS0; + } + break; + } + hspi_dev_reg.selected_dev_num=dev_no; +} + +/****************************************************************************** + * FunctionName : spi_read_data + * Description : use hspi to read flash data for stability test + * Parameters : SpiFlashChip * spi-- flash parameter structure pointer + * uint32 flash_addr--flash start address + * uint32 * addr_dest--start address for preped destination memory space + * uint32 byte_length--length of the data which needs to be read from flash +*******************************************************************************/ +SpiFlashOpResult ICACHE_FLASH_ATTR +hspi_overlap_read_flash_data(SpiFlashChip * spi, uint32 flash_addr, uint32 * addr_dest, uint32 byte_length) +{ + uint32 temp_addr,reg_tmp; + sint32 temp_length; + uint8 i; + uint8 remain_word_num; + + hspi_dev_sel(SPI_CS0_FLASH); + + //address range check + if ((flash_addr+byte_length) > (spi->chip_size)) + { + return SPI_FLASH_RESULT_ERR; + } + + temp_addr = flash_addr; + temp_length = byte_length; + + while(temp_length > 0) + { + if(temp_length >= SPI_BUFF_BYTE_NUM) + { + // reg_tmp=((temp_addr&0xff)<<16)|(temp_addr&0xff00)|((temp_addr&0xff0000)>>16)|(SPI_BUFF_BYTE_NUM << SPI_FLASH_BYTES_LEN); + reg_tmp= temp_addr |(SPI_BUFF_BYTE_NUM<< SPI_FLASH_BYTES_LEN) ; + WRITE_PERI_REG(SPI_ADDR(HSPI), reg_tmp); + WRITE_PERI_REG(SPI_CMD(HSPI), SPI_FLASH_READ); + while(READ_PERI_REG(SPI_CMD(HSPI)) != 0); + + for(i=0; i<(SPI_BUFF_BYTE_NUM>>2);i++) + { + *addr_dest++ = READ_PERI_REG(SPI_W0(HSPI)+i*4); + } + temp_length = temp_length - SPI_BUFF_BYTE_NUM; + temp_addr = temp_addr + SPI_BUFF_BYTE_NUM; + } + else + { + WRITE_PERI_REG(SPI_ADDR(HSPI), temp_addr |(temp_length << SPI_FLASH_BYTES_LEN )); + WRITE_PERI_REG(SPI_CMD(HSPI), SPI_FLASH_READ); + while(READ_PERI_REG(SPI_CMD(HSPI)) != 0); + + remain_word_num = (0== (temp_length&0x3))? (temp_length>>2) : (temp_length>>2)+1; + for (i=0; i + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "driver/uart.h" +#include "osapi.h" +#include "driver/uart_register.h" +#include "mem.h" +#include "os_type.h" + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; + +LOCAL struct UartBuffer* pTxBuffer = NULL; +LOCAL struct UartBuffer* pRxBuffer = NULL; + +/*uart demo with a system task, to output what uart receives*/ +/*this is a example to process uart data from task,please change the priority to fit your application task if exists*/ +/*it might conflict with your task, if so,please arrange the priority of different task, or combine it to a different event in the same task. */ +#define uart_recvTaskPrio 0 +#define uart_recvTaskQueueLen 10 +os_event_t uart_recvTaskQueue[uart_recvTaskQueueLen]; + +#define DBG +#define DBG1 uart1_sendStr_no_wait +#define DBG2 os_printf + + +LOCAL void uart0_rx_intr_handler(void *para); + +/****************************************************************************** + * FunctionName : uart_config + * Description : Internal used function + * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled + * UART1 just used for debug output + * Parameters : uart_no, use UART0 or UART1 defined ahead + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +uart_config(uint8 uart_no) +{ + if (uart_no == UART1){ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + }else{ + /* rcv_buff size if 0x100 */ + ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + #if UART_HW_RTS + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); //HW FLOW CONTROL RTS PIN + #endif + #if UART_HW_CTS + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS); //HW FLOW CONTROL CTS PIN + #endif + } + uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE + + WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M) << UART_PARITY_EN_S) //SET BIT AND PARITY MODE + | ((UartDev.parity & UART_PARITY_M) <> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { + break; + } + } + WRITE_PERI_REG(UART_FIFO(uart) , TxChar); + return OK; +} + +/****************************************************************************** + * FunctionName : uart1_write_char + * Description : Internal used function + * Do some special deal while tx char is '\r' or '\n' + * Parameters : char c - character to tx + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +uart1_write_char(char c) +{ + if (c == '\n'){ + uart_tx_one_char(UART1, '\r'); + uart_tx_one_char(UART1, '\n'); + }else if (c == '\r'){ + + }else{ + uart_tx_one_char(UART1, c); + } +} + +//os_printf output to fifo or to the tx buffer +LOCAL void ICACHE_FLASH_ATTR +uart0_write_char_no_wait(char c) +{ +#if UART_BUFF_EN //send to uart0 fifo but do not wait + uint8 chr; + if (c == '\n'){ + chr = '\r'; + tx_buff_enq(&chr, 1); + chr = '\n'; + tx_buff_enq(&chr, 1); + }else if (c == '\r'){ + + }else{ + tx_buff_enq(&c,1); + } +#else //send to uart tx buffer + if (c == '\n'){ + uart_tx_one_char_no_wait(UART0, '\r'); + uart_tx_one_char_no_wait(UART0, '\n'); + }else if (c == '\r'){ + + } + else{ + uart_tx_one_char_no_wait(UART0, c); + } +#endif +} + +/****************************************************************************** + * FunctionName : uart0_tx_buffer + * Description : use uart0 to transfer buffer + * Parameters : uint8 *buf - point to send buffer + * uint16 len - buffer len + * Returns : +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart0_tx_buffer(uint8 *buf, uint16 len) +{ + uint16 i; + for (i = 0; i < len; i++) + { + uart_tx_one_char(UART0, buf[i]); + } +} + +/****************************************************************************** + * FunctionName : uart0_sendStr + * Description : use uart0 to transfer buffer + * Parameters : uint8 *buf - point to send buffer + * uint16 len - buffer len + * Returns : +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart0_sendStr(const char *str) +{ + while(*str){ + uart_tx_one_char(UART0, *str++); + } +} +void at_port_print(const char *str) __attribute__((alias("uart0_sendStr"))); +/****************************************************************************** + * FunctionName : uart0_rx_intr_handler + * Description : Internal used function + * UART0 interrupt handler, add self handle code inside + * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg + * Returns : NONE +*******************************************************************************/ +LOCAL void +uart0_rx_intr_handler(void *para) +{ + /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents + * uart1 and uart0 respectively + */ + uint8 RcvChar; + uint8 uart_no = UART0;//UartDev.buff_uart_no; + uint8 fifo_len = 0; + uint8 buf_idx = 0; + uint8 temp,cnt; + //RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para; + + /*ATTENTION:*/ + /*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/ + /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */ + /*IF NOT , POST AN EVENT AND PROCESS IN SYSTEM TASK */ + if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)){ + DBG1("FRM_ERR\r\n"); + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); + }else if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)){ + DBG("f"); + uart_rx_intr_disable(UART0); + WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR); + system_os_post(uart_recvTaskPrio, 0, 0); + }else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)){ + DBG("t"); + uart_rx_intr_disable(UART0); + WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR); + system_os_post(uart_recvTaskPrio, 0, 0); + }else if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)){ + DBG("e"); + /* to output uart data from uart buffer directly in empty interrupt handler*/ + /*instead of processing in system event, in order not to wait for current task/function to quit */ + /*ATTENTION:*/ + /*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/ + /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */ + CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); + #if UART_BUFF_EN + tx_start_uart_buffer(UART0); + #endif + //system_os_post(uart_recvTaskPrio, 1, 0); + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR); + + }else if(UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)){ + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR); + DBG1("RX OVF!!\r\n"); + } + +} + +/****************************************************************************** + * FunctionName : uart_init + * Description : user interface for init uart + * Parameters : UartBautRate uart0_br - uart0 bautrate + * UartBautRate uart1_br - uart1 bautrate + * Returns : NONE +*******************************************************************************/ +#if UART_SELFTEST&UART_BUFF_EN +os_timer_t buff_timer_t; +void ICACHE_FLASH_ATTR +uart_test_rx() +{ + uint8 uart_buf[128]={0}; + uint16 len = 0; + len = rx_buff_deq(uart_buf, 128 ); + tx_buff_enq(uart_buf,len); +} +#endif + +LOCAL void ICACHE_FLASH_ATTR /////// +uart_recvTask(os_event_t *events) +{ + if(events->sig == 0){ + #if UART_BUFF_EN + Uart_rx_buff_enq(); + #else + uint8 fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; + uint8 d_tmp = 0; + uint8 idx=0; + for(idx=0;idxsig == 1){ + #if UART_BUFF_EN + //already move uart buffer output to uart empty interrupt + //tx_start_uart_buffer(UART0); + #else + + #endif + } +} + +void ICACHE_FLASH_ATTR +uart_init(UartBautRate uart0_br, UartBautRate uart1_br) +{ + /*this is a example to process uart data from task,please change the priority to fit your application task if exists*/ + system_os_task(uart_recvTask, uart_recvTaskPrio, uart_recvTaskQueue, uart_recvTaskQueueLen); //demo with a task to process the uart data + + UartDev.baut_rate = uart0_br; + uart_config(UART0); + UartDev.baut_rate = uart1_br; + uart_config(UART1); + ETS_UART_INTR_ENABLE(); + + #if UART_BUFF_EN + pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE); + pRxBuffer = Uart_Buf_Init(UART_RX_BUFFER_SIZE); + #endif + + + /*option 1: use default print, output from uart0 , will wait some time if fifo is full */ + //do nothing... + + /*option 2: output from uart1,uart1 output will not wait , just for output debug info */ + /*os_printf output uart data via uart1(GPIO2)*/ + //os_install_putc1((void *)uart1_write_char); //use this one to output debug information via uart1 // + + /*option 3: output from uart0 will skip current byte if fifo is full now... */ + /*see uart0_write_char_no_wait:you can output via a buffer or output directly */ + /*os_printf output uart data via uart0 or uart buffer*/ + //os_install_putc1((void *)uart0_write_char_no_wait); //use this to print via uart0 + + #if UART_SELFTEST&UART_BUFF_EN + os_timer_disarm(&buff_timer_t); + os_timer_setfn(&buff_timer_t, uart_test_rx , NULL); //a demo to process the data in uart rx buffer + os_timer_arm(&buff_timer_t,10,1); + #endif +} + +void ICACHE_FLASH_ATTR +uart_reattach() +{ + uart_init(BIT_RATE_115200, BIT_RATE_115200); +} + +/****************************************************************************** + * FunctionName : uart_tx_one_char_no_wait + * Description : uart tx a single char without waiting for fifo + * Parameters : uint8 uart - uart port + * uint8 TxChar - char to tx + * Returns : STATUS +*******************************************************************************/ +STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar) +{ + uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT); + if (fifo_cnt < 126) { + WRITE_PERI_REG(UART_FIFO(uart) , TxChar); + } + return OK; +} + +STATUS uart0_tx_one_char_no_wait(uint8 TxChar) +{ + uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(UART0))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT); + if (fifo_cnt < 126) { + WRITE_PERI_REG(UART_FIFO(UART0) , TxChar); + } + return OK; +} + + +/****************************************************************************** + * FunctionName : uart1_sendStr_no_wait + * Description : uart tx a string without waiting for every char, used for print debug info which can be lost + * Parameters : const char *str - string to be sent + * Returns : NONE +*******************************************************************************/ +void uart1_sendStr_no_wait(const char *str) +{ + while(*str){ + uart_tx_one_char_no_wait(UART1, *str++); + } +} + + +#if UART_BUFF_EN +/****************************************************************************** + * FunctionName : Uart_Buf_Init + * Description : tx buffer enqueue: fill a first linked buffer + * Parameters : char *pdata - data point to be enqueue + * Returns : NONE +*******************************************************************************/ +struct UartBuffer* ICACHE_FLASH_ATTR +Uart_Buf_Init(uint32 buf_size) +{ + uint32 heap_size = system_get_free_heap_size(); + if(heap_size <=buf_size){ + DBG1("no buf for uart\n\r"); + return NULL; + }else{ + DBG("test heap size: %d\n\r",heap_size); + struct UartBuffer* pBuff = (struct UartBuffer* )os_malloc(sizeof(struct UartBuffer)); + pBuff->UartBuffSize = buf_size; + pBuff->pUartBuff = (uint8*)os_malloc(pBuff->UartBuffSize); + pBuff->pInPos = pBuff->pUartBuff; + pBuff->pOutPos = pBuff->pUartBuff; + pBuff->Space = pBuff->UartBuffSize; + pBuff->BuffState = OK; + pBuff->nextBuff = NULL; + pBuff->TcpControl = RUN; + return pBuff; + } +} + + +//copy uart buffer +LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len) +{ + if(data_len == 0) return ; + + uint16 tail_len = pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos ; + if(tail_len >= data_len){ //do not need to loop back the queue + os_memcpy(pCur->pInPos , pdata , data_len ); + pCur->pInPos += ( data_len ); + pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize ); + pCur->Space -=data_len; + }else{ + os_memcpy(pCur->pInPos, pdata, tail_len); + pCur->pInPos += ( tail_len ); + pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize ); + pCur->Space -=tail_len; + os_memcpy(pCur->pInPos, pdata+tail_len , data_len-tail_len); + pCur->pInPos += ( data_len-tail_len ); + pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize ); + pCur->Space -=( data_len-tail_len); + } + +} + +/****************************************************************************** + * FunctionName : uart_buf_free + * Description : deinit of the tx buffer + * Parameters : struct UartBuffer* pTxBuff - tx buffer struct pointer + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart_buf_free(struct UartBuffer* pBuff) +{ + os_free(pBuff->pUartBuff); + os_free(pBuff); +} + + +//rx buffer dequeue +uint16 ICACHE_FLASH_ATTR +rx_buff_deq(char* pdata, uint16 data_len ) +{ + uint16 buf_len = (pRxBuffer->UartBuffSize- pRxBuffer->Space); + uint16 tail_len = pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize - pRxBuffer->pOutPos ; + uint16 len_tmp = 0; + len_tmp = ((data_len > buf_len)?buf_len:data_len); + if(pRxBuffer->pOutPos <= pRxBuffer->pInPos){ + os_memcpy(pdata, pRxBuffer->pOutPos,len_tmp); + pRxBuffer->pOutPos+= len_tmp; + pRxBuffer->Space += len_tmp; + }else{ + if(len_tmp>tail_len){ + os_memcpy(pdata, pRxBuffer->pOutPos, tail_len); + pRxBuffer->pOutPos += tail_len; + pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize ); + pRxBuffer->Space += tail_len; + + os_memcpy(pdata+tail_len , pRxBuffer->pOutPos, len_tmp-tail_len); + pRxBuffer->pOutPos+= ( len_tmp-tail_len ); + pRxBuffer->pOutPos= (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize ); + pRxBuffer->Space +=( len_tmp-tail_len); + }else{ + //os_printf("case 3 in rx deq\n\r"); + os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp); + pRxBuffer->pOutPos += len_tmp; + pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize ); + pRxBuffer->Space += len_tmp; + } + } + if(pRxBuffer->Space >= UART_FIFO_LEN){ + uart_rx_intr_enable(UART0); + } + return len_tmp; +} + + +//move data from uart fifo to rx buffer +void Uart_rx_buff_enq() +{ + uint8 fifo_len,buf_idx; + uint8 fifo_data; + #if 1 + fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; + if(fifo_len >= pRxBuffer->Space){ + os_printf("buf full!!!\n\r"); + }else{ + buf_idx=0; + while(buf_idx < fifo_len){ + buf_idx++; + fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; + *(pRxBuffer->pInPos++) = fifo_data; + if(pRxBuffer->pInPos == (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize)){ + pRxBuffer->pInPos = pRxBuffer->pUartBuff; + } + } + pRxBuffer->Space -= fifo_len ; + if(pRxBuffer->Space >= UART_FIFO_LEN){ + //os_printf("after rx enq buf enough\n\r"); + uart_rx_intr_enable(UART0); + } + } + #endif +} + + +//fill the uart tx buffer +void ICACHE_FLASH_ATTR +tx_buff_enq(char* pdata, uint16 data_len ) +{ + CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); + + if(pTxBuffer == NULL){ + DBG1("\n\rnull, create buffer struct\n\r"); + pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE); + if(pTxBuffer!= NULL){ + Uart_Buf_Cpy(pTxBuffer , pdata, data_len ); + }else{ + DBG1("uart tx MALLOC no buf \n\r"); + } + }else{ + if(data_len <= pTxBuffer->Space){ + Uart_Buf_Cpy(pTxBuffer , pdata, data_len); + }else{ + DBG1("UART TX BUF FULL!!!!\n\r"); + } + } + #if 0 + if(pTxBuffer->Space <= URAT_TX_LOWER_SIZE){ + set_tcp_block(); + } + #endif + SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD)<pOutPos++)); + if(pTxBuff->pOutPos == (pTxBuff->pUartBuff + pTxBuff->UartBuffSize)){ + pTxBuff->pOutPos = pTxBuff->pUartBuff; + } + } + pTxBuff->pOutPos = (pTxBuff->pUartBuff + (pTxBuff->pOutPos - pTxBuff->pUartBuff) % pTxBuff->UartBuffSize ); + pTxBuff->Space += data_len; +} + + +/****************************************************************************** + * FunctionName : tx_start_uart_buffer + * Description : get data from the tx buffer and fill the uart tx fifo, co-work with the uart fifo empty interrupt + * Parameters : uint8 uart_no - uart port num + * Returns : NONE +*******************************************************************************/ +void tx_start_uart_buffer(uint8 uart_no) +{ + uint8 tx_fifo_len = (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT; + uint8 fifo_remain = UART_FIFO_LEN - tx_fifo_len ; + uint8 len_tmp; + uint16 tail_ptx_len,head_ptx_len,data_len; + //struct UartBuffer* pTxBuff = *get_buff_prt(); + + if(pTxBuffer){ + data_len = (pTxBuffer->UartBuffSize - pTxBuffer->Space); + if(data_len > fifo_remain){ + len_tmp = fifo_remain; + tx_fifo_insert( pTxBuffer,len_tmp,uart_no); + SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); + }else{ + len_tmp = data_len; + tx_fifo_insert( pTxBuffer,len_tmp,uart_no); + } + }else{ + DBG1("pTxBuff null \n\r"); + } +} + +#endif + + +void uart_rx_intr_disable(uint8 uart_no) +{ +#if 1 + CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); +#else + ETS_UART_INTR_DISABLE(); +#endif +} + +void uart_rx_intr_enable(uint8 uart_no) +{ +#if 1 + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); +#else + ETS_UART_INTR_ENABLE(); +#endif +} + + +//======================================================== +LOCAL void +uart0_write_char(char c) +{ + if (c == '\n') { + uart_tx_one_char(UART0, '\r'); + uart_tx_one_char(UART0, '\n'); + } else if (c == '\r') { + } else { + uart_tx_one_char(UART0, c); + } +} + +void ICACHE_FLASH_ATTR +UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len) +{ + SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_BIT_NUM,len,UART_BIT_NUM_S); +} + +void ICACHE_FLASH_ATTR +UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num) +{ + SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_STOP_BIT_NUM,bit_num,UART_STOP_BIT_NUM_S); +} + +void ICACHE_FLASH_ATTR +UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask) +{ + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK); + SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask); +} + +void ICACHE_FLASH_ATTR +UART_SetParity(uint8 uart_no, UartParityMode Parity_mode) +{ + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY |UART_PARITY_EN); + if(Parity_mode==NONE_BITS){ + }else{ + SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode|UART_PARITY_EN); + } +} + +void ICACHE_FLASH_ATTR +UART_SetBaudrate(uint8 uart_no,uint32 baud_rate) +{ + uart_div_modify(uart_no, UART_CLK_FREQ /baud_rate); +} + +void ICACHE_FLASH_ATTR +UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh) +{ + if(flow_ctrl&USART_HardwareFlowControl_RTS){ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); + SET_PERI_REG_BITS(UART_CONF1(uart_no),UART_RX_FLOW_THRHD,rx_thresh,UART_RX_FLOW_THRHD_S); + SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN); + }else{ + CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN); + } + if(flow_ctrl&USART_HardwareFlowControl_CTS){ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS); + SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN); + }else{ + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN); + } +} + +void ICACHE_FLASH_ATTR +UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us) //do not use if tx flow control enabled +{ + uint32 t_s = system_get_time(); + while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)){ + + if(( system_get_time() - t_s )> time_out_us){ + break; + } + WRITE_PERI_REG(0X60000914, 0X73);//WTD + + } +} + + +bool ICACHE_FLASH_ATTR +UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us) +{ + uint32 t_start = system_get_time(); + uint8 tx_fifo_len; + uint32 tx_buff_len; + while(1){ + tx_fifo_len =( (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT); + if(pTxBuffer){ + tx_buff_len = ((pTxBuffer->UartBuffSize)-(pTxBuffer->Space)); + }else{ + tx_buff_len = 0; + } + + if( tx_fifo_len==0 && tx_buff_len==0){ + return TRUE; + } + if( system_get_time() - t_start > time_out_us){ + return FALSE; + } + WRITE_PERI_REG(0X60000914, 0X73);//WTD + } +} + + +void ICACHE_FLASH_ATTR +UART_ResetFifo(uint8 uart_no) +{ + SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); +} + +void ICACHE_FLASH_ATTR +UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask) +{ + WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask); +} + +void ICACHE_FLASH_ATTR +UART_SetIntrEna(uint8 uart_no,uint32 ena_mask) +{ + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask); +} + + +void ICACHE_FLASH_ATTR +UART_SetPrintPort(uint8 uart_no) +{ + if(uart_no==1){ + os_install_putc1(uart1_write_char); + }else{ + /*option 1: do not wait if uart fifo is full,drop current character*/ + os_install_putc1(uart0_write_char_no_wait); + /*option 2: wait for a while if uart fifo is full*/ + os_install_putc1(uart0_write_char); + } +} + + +//======================================================== + + +/*test code*/ +void ICACHE_FLASH_ATTR +uart_init_2(UartBautRate uart0_br, UartBautRate uart1_br) +{ + // rom use 74880 baut_rate, here reinitialize + UartDev.baut_rate = uart0_br; + UartDev.exist_parity = STICK_PARITY_EN; + UartDev.parity = EVEN_BITS; + UartDev.stop_bits = ONE_STOP_BIT; + UartDev.data_bits = EIGHT_BITS; + + uart_config(UART0); + UartDev.baut_rate = uart1_br; + uart_config(UART1); + ETS_UART_INTR_ENABLE(); + + // install uart1 putc callback + os_install_putc1((void *)uart1_write_char);//print output at UART1 +} + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/gpio16.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/gpio16.h new file mode 100644 index 0000000000..c21efaa825 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/gpio16.h @@ -0,0 +1,33 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __GPIO16_H__ +#define __GPIO16_H__ + +void gpio16_output_conf(void); +void gpio16_output_set(uint8 value); +void gpio16_input_conf(void); +uint8 gpio16_input_get(void); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/i2c_master.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/i2c_master.h new file mode 100644 index 0000000000..acbd5f26d8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/i2c_master.h @@ -0,0 +1,81 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __I2C_MASTER_H__ +#define __I2C_MASTER_H__ + +#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U +#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U +#define I2C_MASTER_SDA_GPIO 2 +#define I2C_MASTER_SCL_GPIO 14 +#define I2C_MASTER_SDA_FUNC FUNC_GPIO2 +#define I2C_MASTER_SCL_FUNC FUNC_GPIO14 + +//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U +//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U +//#define I2C_MASTER_SDA_GPIO 2 +//#define I2C_MASTER_SCL_GPIO 0 +//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2 +//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0 + +#if 0 +#define I2C_MASTER_GPIO_SET(pin) \ + gpio_output_set(1< + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#include "gpio.h" + +typedef void (* key_function)(void); + +struct single_key_param { + uint8 key_level; + uint8 gpio_id; + uint8 gpio_func; + uint32 gpio_name; + os_timer_t key_5s; + os_timer_t key_50ms; + key_function short_press; + key_function long_press; +}; + +struct keys_param { + uint8 key_num; + struct single_key_param **single_key; +}; + +struct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press); +void key_init(struct keys_param *key); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/sdio_slv.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/sdio_slv.h new file mode 100644 index 0000000000..6f5adebbb7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/sdio_slv.h @@ -0,0 +1,40 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SDIO_SLAVE_H__ +#define __SDIO_SLAVE_H__ +#include "c_types.h" +#include "user_interface.h" + +#define RX_AVAILIBLE 2 +#define TX_AVAILIBLE 1 +#define INIT_STAGE 0 + +void sdio_slave_init(void); + +int32 sdio_load_data(const uint8* data,uint32 len); +typedef void (*sdio_recv_data_callback_t)(uint8* data,uint32 len); + +bool sdio_register_recv_cb(sdio_recv_data_callback_t cb); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/slc_register.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/slc_register.h new file mode 100644 index 0000000000..dabde8b001 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/slc_register.h @@ -0,0 +1,300 @@ +//Generated at 2012-10-23 19:55:03 +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +#ifndef SLC_REGISTER_H_ +#define SLC_REGISTER_H_ + +#define REG_SLC_BASE 0x60000B00 +//version value:32'h091700 + +#define SLC_CONF0 (REG_SLC_BASE + 0x0) +#ifndef ESP_MAC_5 +#define SLC_MODE 0x00000003 +#define SLC_MODE_S 12 +#endif +#define SLC_DATA_BURST_EN (BIT(9)) +#define SLC_DSCR_BURST_EN (BIT(8)) +#define SLC_RX_NO_RESTART_CLR (BIT(7)) +#define SLC_RX_AUTO_WRBACK (BIT(6)) +#define SLC_RX_LOOP_TEST (BIT(5)) +#define SLC_TX_LOOP_TEST (BIT(4)) +#define SLC_AHBM_RST (BIT(3)) +#define SLC_AHBM_FIFO_RST (BIT(2)) +#define SLC_RXLINK_RST (BIT(1)) +#define SLC_TXLINK_RST (BIT(0)) + +#define SLC_INT_RAW (REG_SLC_BASE + 0x4) +#define SLC_TX_DSCR_EMPTY_INT_RAW (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_RAW (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_RAW (BIT(19)) +#define SLC_TOHOST_INT_RAW (BIT(18)) +#define SLC_RX_EOF_INT_RAW (BIT(17)) +#define SLC_RX_DONE_INT_RAW (BIT(16)) +#define SLC_TX_EOF_INT_RAW (BIT(15)) +#define SLC_TX_DONE_INT_RAW (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_RAW (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_RAW (BIT(12)) +#define SLC_TX_OVF_INT_RAW (BIT(11)) +#define SLC_RX_UDF_INT_RAW (BIT(10)) +#define SLC_TX_START_INT_RAW (BIT(9)) +#define SLC_RX_START_INT_RAW (BIT(8)) +#define SLC_FRHOST_BIT7_INT_RAW (BIT(7)) +#define SLC_FRHOST_BIT6_INT_RAW (BIT(6)) +#define SLC_FRHOST_BIT5_INT_RAW (BIT(5)) +#define SLC_FRHOST_BIT4_INT_RAW (BIT(4)) +#define SLC_FRHOST_BIT3_INT_RAW (BIT(3)) +#define SLC_FRHOST_BIT2_INT_RAW (BIT(2)) +#define SLC_FRHOST_BIT1_INT_RAW (BIT(1)) +#define SLC_FRHOST_BIT0_INT_RAW (BIT(0)) + +#define SLC_INT_STATUS (REG_SLC_BASE + 0x8) +#define SLC_TX_DSCR_EMPTY_INT_ST (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_ST (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_ST (BIT(19)) +#define SLC_TOHOST_INT_ST (BIT(18)) +#define SLC_RX_EOF_INT_ST (BIT(17)) +#define SLC_RX_DONE_INT_ST (BIT(16)) +#define SLC_TX_EOF_INT_ST (BIT(15)) +#define SLC_TX_DONE_INT_ST (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_ST (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_ST (BIT(12)) +#define SLC_TX_OVF_INT_ST (BIT(11)) +#define SLC_RX_UDF_INT_ST (BIT(10)) +#define SLC_TX_START_INT_ST (BIT(9)) +#define SLC_RX_START_INT_ST (BIT(8)) +#define SLC_FRHOST_BIT7_INT_ST (BIT(7)) +#define SLC_FRHOST_BIT6_INT_ST (BIT(6)) +#define SLC_FRHOST_BIT5_INT_ST (BIT(5)) +#define SLC_FRHOST_BIT4_INT_ST (BIT(4)) +#define SLC_FRHOST_BIT3_INT_ST (BIT(3)) +#define SLC_FRHOST_BIT2_INT_ST (BIT(2)) +#define SLC_FRHOST_BIT1_INT_ST (BIT(1)) +#define SLC_FRHOST_BIT0_INT_ST (BIT(0)) + +#define SLC_INT_ENA (REG_SLC_BASE + 0xC) +#define SLC_TX_DSCR_EMPTY_INT_ENA (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_ENA (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_ENA (BIT(19)) +#define SLC_TOHOST_INT_ENA (BIT(18)) +#define SLC_RX_EOF_INT_ENA (BIT(17)) +#define SLC_RX_DONE_INT_ENA (BIT(16)) +#define SLC_TX_EOF_INT_ENA (BIT(15)) +#define SLC_TX_DONE_INT_ENA (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_ENA (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_ENA (BIT(12)) +#define SLC_TX_OVF_INT_ENA (BIT(11)) +#define SLC_RX_UDF_INT_ENA (BIT(10)) +#define SLC_TX_START_INT_ENA (BIT(9)) +#define SLC_RX_START_INT_ENA (BIT(8)) +#define SLC_FRHOST_BIT7_INT_ENA (BIT(7)) +#define SLC_FRHOST_BIT6_INT_ENA (BIT(6)) +#define SLC_FRHOST_BIT5_INT_ENA (BIT(5)) +#define SLC_FRHOST_BIT4_INT_ENA (BIT(4)) +#define SLC_FRHOST_BIT3_INT_ENA (BIT(3)) +#define SLC_FRHOST_BIT2_INT_ENA (BIT(2)) +#define SLC_FRHOST_BIT1_INT_ENA (BIT(1)) +#define SLC_FRHOST_BIT0_INT_ENA (BIT(0)) + +#define SLC_FRHOST_BIT_INT_ENA_ALL 0xff + +#define SLC_INT_CLR (REG_SLC_BASE + 0x10) +#define SLC_TX_DSCR_EMPTY_INT_CLR (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_CLR (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_CLR (BIT(19)) +#define SLC_TOHOST_INT_CLR (BIT(18)) +#define SLC_RX_EOF_INT_CLR (BIT(17)) +#define SLC_RX_DONE_INT_CLR (BIT(16)) +#define SLC_TX_EOF_INT_CLR (BIT(15)) +#define SLC_TX_DONE_INT_CLR (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_CLR (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_CLR (BIT(12)) +#define SLC_TX_OVF_INT_CLR (BIT(11)) +#define SLC_RX_UDF_INT_CLR (BIT(10)) +#define SLC_TX_START_INT_CLR (BIT(9)) +#define SLC_RX_START_INT_CLR (BIT(8)) +#define SLC_FRHOST_BIT7_INT_CLR (BIT(7)) +#define SLC_FRHOST_BIT6_INT_CLR (BIT(6)) +#define SLC_FRHOST_BIT5_INT_CLR (BIT(5)) +#define SLC_FRHOST_BIT4_INT_CLR (BIT(4)) +#define SLC_FRHOST_BIT3_INT_CLR (BIT(3)) +#define SLC_FRHOST_BIT2_INT_CLR (BIT(2)) +#define SLC_FRHOST_BIT1_INT_CLR (BIT(1)) +#define SLC_FRHOST_BIT0_INT_CLR (BIT(0)) + +#define SLC_RX_STATUS (REG_SLC_BASE + 0x14) +#define SLC_RX_EMPTY (BIT(1)) +#define SLC_RX_FULL (BIT(0)) + +#define SLC_RX_FIFO_PUSH (REG_SLC_BASE + 0x18) +#define SLC_RXFIFO_PUSH (BIT(16)) +#define SLC_RXFIFO_WDATA 0x000001FF +#define SLC_RXFIFO_WDATA_S 0 + +#define SLC_TX_STATUS (REG_SLC_BASE + 0x1C) +#define SLC_TX_EMPTY (BIT(1)) +#define SLC_TX_FULL (BIT(0)) + +#define SLC_TX_FIFO_POP (REG_SLC_BASE + 0x20) +#define SLC_TXFIFO_POP (BIT(16)) +#define SLC_TXFIFO_RDATA 0x000007FF +#define SLC_TXFIFO_RDATA_S 0 + +#define SLC_RX_LINK (REG_SLC_BASE + 0x24) +#define SLC_RXLINK_PARK (BIT(31)) +#define SLC_RXLINK_RESTART (BIT(30)) +#define SLC_RXLINK_START (BIT(29)) +#define SLC_RXLINK_STOP (BIT(28)) +#define SLC_RXLINK_DESCADDR_MASK 0x000FFFFF +#define SLC_RXLINK_ADDR_S 0 + +#define SLC_TX_LINK (REG_SLC_BASE + 0x28) +#define SLC_TXLINK_PARK (BIT(31)) +#define SLC_TXLINK_RESTART (BIT(30)) +#define SLC_TXLINK_START (BIT(29)) +#define SLC_TXLINK_STOP (BIT(28)) +#define SLC_TXLINK_DESCADDR_MASK 0x000FFFFF +#define SLC_TXLINK_ADDR_S 0 + +#define SLC_INTVEC_TOHOST (REG_SLC_BASE + 0x2C) +#define SLC_TOHOST_INTVEC 0x000000FF +#define SLC_TOHOST_INTVEC_S 0 + +#define SLC_TOKEN0 (REG_SLC_BASE + 0x30) +#define SLC_TOKEN0_MASK 0x00000FFF +#define SLC_TOKEN0_S 16 +#define SLC_TOKEN0_LOCAL_INC_MORE (BIT(14)) +#define SLC_TOKEN0_LOCAL_INC (BIT(13)) +#define SLC_TOKEN0_LOCAL_WR (BIT(12)) +#define SLC_TOKEN0_LOCAL_WDATA_MASK 0x00000FFF +#define SLC_TOKEN0_LOCAL_WDATA_S 0 + +#define SLC_TOKEN1 (REG_SLC_BASE + 0x34) +#define SLC_TOKEN1_MASK 0x00000FFF +#define SLC_TOKEN1_S 16 +#define SLC_TOKEN1_LOCAL_INC_MORE (BIT(14)) +#define SLC_TOKEN1_LOCAL_INC (BIT(13)) +#define SLC_TOKEN1_LOCAL_WR (BIT(12)) +#define SLC_TOKEN1_LOCAL_WDATA 0x00000FFF +#define SLC_TOKEN1_LOCAL_WDATA_S 0 + +#define SLC_CONF1 (REG_SLC_BASE + 0x38) +#define SLC_STATE0 (REG_SLC_BASE + 0x3C) +#define SLC_STATE1 (REG_SLC_BASE + 0x40) + +#define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44) +#ifndef ESP_MAC_5 +#define SLC_TX_PUSH_IDLE_NUM 0x0000FFFF +#define SLC_TX_PUSH_IDLE_NUM_S 16 +#define SLC_TX_DUMMY_MODE (BIT(12)) +#endif +#define SLC_FIFO_MAP_ENA 0x0000000F +#define SLC_FIFO_MAP_ENA_S 8 +#define SLC_TXEOF_ENA 0x0000003F +#define SLC_TXEOF_ENA_S 0 + +#define SLC_RX_EOF_DES_ADDR (REG_SLC_BASE + 0x48) +#define SLC_TX_EOF_DES_ADDR (REG_SLC_BASE + 0x4C) +#define SLC_FROM_HOST_LAST_DESC SLC_TX_EOF_DES_ADDR +#define SLC_TO_HOST_LAST_DESC SLC_RX_EOF_DES_ADDR + +#define SLC_RX_EOF_BFR_DES_ADDR (REG_SLC_BASE + 0x50) +#define SLC_AHB_TEST (REG_SLC_BASE + 0x54) +#define SLC_AHB_TESTADDR 0x00000003 +#define SLC_AHB_TESTADDR_S 4 +#define SLC_AHB_TESTMODE 0x00000007 +#define SLC_AHB_TESTMODE_S 0 + +#define SLC_SDIO_ST (REG_SLC_BASE + 0x58) +#define SLC_BUS_ST 0x00000007 +#define SLC_BUS_ST_S 12 +#define SLC_SDIO_WAKEUP (BIT(8)) +#define SLC_FUNC_ST 0x0000000F +#define SLC_FUNC_ST_S 4 +#define SLC_CMD_ST 0x00000007 +#define SLC_CMD_ST_S 0 + +#define SLC_RX_DSCR_CONF (REG_SLC_BASE + 0x5C) +#ifdef ESP_MAC_5 +#define SLC_INFOR_NO_REPLACE (BIT(9)) +#define SLC_TOKEN_NO_REPLACE (BIT(8)) +#define SLC_POP_IDLE_CNT 0x000000FF +#else +#define SLC_RX_FILL_EN (BIT(20)) +#define SLC_RX_EOF_MODE (BIT(19)) +#define SLC_RX_FILL_MODE (BIT(18)) +#define SLC_INFOR_NO_REPLACE (BIT(17)) +#define SLC_TOKEN_NO_REPLACE (BIT(16)) // +#define SLC_POP_IDLE_CNT 0x0000FFFF +#endif +#define SLC_POP_IDLE_CNT_S 0 + +#define SLC_TXLINK_DSCR (REG_SLC_BASE + 0x60) +#define SLC_TXLINK_DSCR_BF0 (REG_SLC_BASE + 0x64) +#define SLC_TXLINK_DSCR_BF1 (REG_SLC_BASE + 0x68) +#define SLC_RXLINK_DSCR (REG_SLC_BASE + 0x6C) +#define SLC_RXLINK_DSCR_BF0 (REG_SLC_BASE + 0x70) +#define SLC_RXLINK_DSCR_BF1 (REG_SLC_BASE + 0x74) +#define SLC_DATE (REG_SLC_BASE + 0x78) +#define SLC_ID (REG_SLC_BASE + 0x7C) + +#define SLC_HOST_CONF_W0 (REG_SLC_BASE + 0x80 + 0x14) +#define SLC_HOST_CONF_W1 (REG_SLC_BASE + 0x80 + 0x18) +#define SLC_HOST_CONF_W2 (REG_SLC_BASE + 0x80 + 0x20) +#define SLC_HOST_CONF_W3 (REG_SLC_BASE + 0x80 + 0x24) +#define SLC_HOST_CONF_W4 (REG_SLC_BASE + 0x80 + 0x28) + +#define SLC_HOST_INTR_ST (REG_SLC_BASE + 0x80 + 0x1c) +#define SLC_HOST_INTR_CLR (REG_SLC_BASE + 0x80 + 0x30) +#define SLC_HOST_INTR_SOF_BIT (BIT(12)) + +#define SLC_HOST_INTR_ENA (REG_SLC_BASE + 0x80 + 0x34) +#define SLC_RX_NEW_PACKET_INT_ENA (BIT23) +#define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT0) +#define SLC_HOST_CONF_W5 (REG_SLC_BASE + 0x80 + 0x3C) +#define SLC_HOST_INTR_RAW (REG_SLC_BASE + 0x80 + 0x8) +#define SLC_HOST_INTR_ENA_BIT (BIT(23)) +//[15:12]: 0x3ff9xxxx -- 0b01 from_host +// 0x3ffaxxxx -- 0b10 general +// 0x3ffbxxxx -- 0b11 to_host +#define SLC_DATA_ADDR_CLEAR_MASK (~(0xf<<12)) +#define SLC_FROM_HOST_ADDR_MASK (0x1<<12) +#define SLC_TO_HOST_ADDR_MASK (0x3<<12) + +#define SLC_SET_FROM_HOST_ADDR_MASK(v) do { \ + (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ + (v) |= SLC_FROM_HOST_ADDR_MASK; \ +} while(0); + +#define SLC_SET_TO_HOST_ADDR_MASK(v) do { \ + (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ + (v) |= SLC_TO_HOST_ADDR_MASK; \ +} while(0); + + +#define SLC_TX_DESC_DEBUG_REG 0x3ff0002c //[15:0] set to 0xcccc + + +#endif // SLC_REGISTER_H_INCLUDED diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi.h new file mode 100644 index 0000000000..6af5e05a7c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi.h @@ -0,0 +1,74 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef SPI_APP_H +#define SPI_APP_H + +#include "spi_register.h" +#include "ets_sys.h" +#include "osapi.h" +#include "uart.h" +#include "os_type.h" +#include "spi_flash.h" + +#define SPI_FLASH_BYTES_LEN 24 +#define IODATA_START_ADDR BIT0 +#define SPI_BUFF_BYTE_NUM 32 + +/*SPI number define*/ +#define SPI 0 +#define HSPI 1 + +void cache_flush(void); +//spi master init funtion +void spi_master_init(uint8 spi_no); + +//lcd drive function +void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit); +//use spi send 8bit data +void spi_mast_byte_write(uint8 spi_no,uint8 data); + +//transmit data to esp8266 slave buffer,which needs 16bit transmission , +//first byte is master command 0x04, second byte is master data +void spi_byte_write_espslave(uint8 spi_no,uint8 data); +//read data from esp8266 slave buffer,which needs 16bit transmission , +//first byte is master command 0x06, second byte is to read slave data +void spi_byte_read_espslave(uint8 spi_no,uint8 *data); + + //esp8266 slave mode initial +void spi_slave_init(uint8 spi_no,uint8 data_len); + //esp8266 slave isr handle funtion,tiggered when any transmission is finished. + //the function is registered in spi_slave_init. +void spi_slave_isr_handler(void *para); + + +//hspi test function, used to test esp8266 spi slave +void hspi_master_readwrite_repeat(void); + + +void spi_test_init(void); + + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_interface.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_interface.h new file mode 100644 index 0000000000..d3b5d05f6c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_interface.h @@ -0,0 +1,353 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/** + * @file spi_interface.h + * @brief Defines and Macros for the SPI. + */ +#ifndef __SPI_INTERFACE_H__ +#define __SPI_INTERFACE_H__ + +#include "driver/spi_register.h" +#include "c_types.h" + +//***************************************************************************** +// +// Make sure all of the definitions in this header have a C binding. +// +//***************************************************************************** + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * @brief Defines slave commands. Default value based on slave ESP8266. + */ +#define MASTER_WRITE_DATA_TO_SLAVE_CMD 2 +#define MASTER_READ_DATA_FROM_SLAVE_CMD 3 + +#define MASTER_WRITE_STATUS_TO_SLAVE_CMD 1 +#define MASTER_READ_STATUS_FROM_SLAVE_CMD 4 + +/** + * @brief Support HSPI and SPI module. + * + */ +typedef enum +{ + SpiNum_SPI = 0, + SpiNum_HSPI = 1, +} SpiNum; + +/** + * @brief The SPI module can work in either master or slave mode. + * + */ +typedef enum +{ + SpiMode_Master = 0, + SpiMode_Slave = 1, +} SpiMode; + +/** + * @brief SPI sub mode + * + * Support 4 sub modes based on SPI clock polarity and phase. + * SPI_CPOL SPI_CPHA SubMode + * 0 0 0 + * 0 1 1 + * 1 0 2 + * 1 1 3 + */ +typedef enum +{ + SpiSubMode_0 = 0, + SpiSubMode_1 = 1, + SpiSubMode_2 = 2, + SpiSubMode_3 = 3, +} SpiSubMode; + +/** + * @brief The SPI module working speed. + * + * @attention Max speed 80MHz + * + */ +typedef enum +{ + SpiSpeed_0_5MHz = 160, + SpiSpeed_1MHz = 80, + SpiSpeed_2MHz = 40, + SpiSpeed_5MHz = 16, + SpiSpeed_8MHz = 10, + SpiSpeed_10MHz = 8, + +} SpiSpeed; + +/** + * @brief The SPI mode working speed. + * + */ +typedef enum +{ + SpiBitOrder_MSBFirst = 0, + SpiBitOrder_LSBFirst = 1, +} SpiBitOrder; + +// @brief SPI interrupt soource defined. +typedef enum +{ + SpiIntSrc_TransDone = SPI_TRANS_DONE, + SpiIntSrc_WrStaDone = SPI_SLV_WR_STA_DONE, + SpiIntSrc_RdStaDone = SPI_SLV_RD_STA_DONE, + SpiIntSrc_WrBufDone = SPI_SLV_WR_BUF_DONE, + SpiIntSrc_RdBufDone = SPI_SLV_RD_BUF_DONE, +} SpiIntSrc; + +// @brief SPI CS pin. +typedef enum +{ + SpiPinCS_0 = 1, + SpiPinCS_1 = 2, + SpiPinCS_2 = 4, +} SpiPinCS; + +#pragma pack (1) + +/** + * @brief SPI attribute + */ +typedef struct +{ + SpiMode mode; ///< Master or slave mode + SpiSubMode subMode; ///< SPI SPI_CPOL SPI_CPHA mode + SpiSpeed speed; ///< SPI Clock + SpiBitOrder bitOrder; ///< SPI bit order +} SpiAttr; + +/** + * @brief SPI data package + */ +typedef struct +{ + uint16_t cmd; ///< Command value + uint8_t cmdLen; ///< Command byte length + uint32_t *addr; ///< Point to address value + uint8_t addrLen; ///< Address byte length + uint32_t *data; ///< Point to data buffer + uint8_t dataLen; ///< Data byte length. +} SpiData; + + +/** + * @brief SPI interrupt information + */ +typedef struct +{ + SpiIntSrc src; ///< Interrupt source + void *isrFunc; ///< SPI interrupt callback function. + +} SpiIntInfo; + +#pragma upack (1) + +/** + * @brief Initialize SPI module. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pAttr + * Pointer to a struct SpiAttr that indicates SPI working attribution. + * + * @return void. + */ +void SPIInit(SpiNum spiNum, SpiAttr* pAttr); + +/** + * @brief Set slave address value by master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] addr + * Slave address to be set. + * + * @return void. + */ +void SPIMasterCfgAddr(SpiNum spiNum, uint32_t addr); + +/** + * @brief Set command value by master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] cmd + * Command will be send to slave. + * + * @return void. + */ +void SPIMasterCfgCmd(SpiNum spiNum, uint32_t cmd); + +/** + * @brief Send data to slave from master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pInData + * Pointer to a strcuture that will be send. + * + * @return int, -1:indicates failure,others indicates success. + */ + int SPIMasterSendData(SpiNum spiNum, SpiData* pInData); + +/** + * @brief Receive data from slave by master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pOutData + * Point to data buffer. + * + * @return int, -1:indicates failure,others indicates success. + * + */ + int SPIMasterRecvData(SpiNum spiNum, SpiData* pOutData); + +/** + * @brief Load data to slave send buffer. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pInData + * Point to data buffer. + * @param [in] inLen + * The number of bytes to be set. + * + * @return int, -1:indicates failure,others indicates success. + */ +int SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t inLen); + +/** + * @brief Receive data by slave. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] isrFunc + * isrFunc is a pointer to the function to be called when the SPI interrupt occurs. + * + * @return int, -1:indicates failure,others indicates success. + */ +int SPISlaveRecvData(SpiNum spiNum); + +/** + * @brief Set slave status by master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] data + * Data will be write to slave SPI_WR_STATUS. + * + * @return void. + * + * @attention Just for ESP8266(slave) register of RD_STATUS or WR_STATUS. + */ +void SPIMasterSendStatus(SpiNum spiNum, uint8_t data); + +/** + * @brief Get salve status by master. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * + * @return int, -1: indicates failure; other value in slave status. + * + * @attention Just for ESP8266(slave) register of RD_STATUS or WR_STATUS. + */ +int SPIMasterRecvStatus(SpiNum spiNum); + +/** + * @brief Select SPI CS pin. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pinCs + * Indicates which SPI pin to choose. + * + * @return void. + */ +void SPICsPinSelect(SpiNum spiNum, SpiPinCS pinCs); + +/** + * @brief Set SPI module interrupt source and callback function. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] pIntInfo + * Pointer to a struct SpiIntInfo that indicates SPI interrupt information. + * + * @return void. + */ +void SPIIntCfg(SpiNum spiNum, SpiIntInfo *pIntInfo); + +/** + * @brief Enable SPI module interrupt source. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] intSrc + * Indicates which interrupt source to enable. + * + * @return void. + */ +void SPIIntEnable(SpiNum spiNum, SpiIntSrc intSrc); + +/** + * @brief Disable SPI module interrupt source. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * @param [in] intSrc + * Indicates which interrupt source to disable. + * + * @return void. + */ +void SPIIntDisable(SpiNum spiNum, SpiIntSrc intSrc); + +/** + * @brief Clear all of spi interrupt. + * + * @param [in] spiNum + * Indicates which submode to be used, SPI or HSPI. + * + * @return void. + */ +void SPIIntClear(SpiNum spiNum); + +#ifdef __cplusplus +} +#endif + +#endif // __SPI_INTERFACE_H__ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_overlap.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_overlap.h new file mode 100644 index 0000000000..697c359f5c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_overlap.h @@ -0,0 +1,85 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef SPI_OVERLAP_APP_H +#define SPI_OVERLAP_APP_H + +#include "ets_sys.h" +#include "spi_flash.h" +#define HSPI_OVERLAP +//#define NO_HSPI_DEVICE +#define HOST_INF_SEL 0x3ff00028 +#define FUNC_SPI_CS2 1 +#define FUNC_SPI_CS1 1 +#define reg_cspi_overlap (BIT7) + +#define SPI_FLASH_BYTES_LEN 24 +#define IODATA_START_ADDR BIT0 +#define SPI_BUFF_BYTE_NUM 32 + +#define PERIPHS_IO_MUX_BACKUP 0 +#define SPI_USER_BACKUP 1 +#define SPI_CTRL_BACKUP 2 +#define SPI_CLOCK_BACKUP 3 +#define SPI_USER1_BACKUP 4 +#define SPI_USER2_BACKUP 5 +#define SPI_CMD_BACKUP 6 +#define SPI_PIN_BACKUP 7 +#define SPI_SLAVE_BACKUP 8 + +#define HSPI_CS_DEV 0 +#define SPI_CS1_DEV 1 +#define SPI_CS2_DEV 2 +#define SPI_CS0_FLASH 3 +#define HSPI_IDLE 4 + +struct hspi_device_config{ + uint8 active:1; + uint8 clk_polar:1; + uint8 res:1; + uint8 clk_div:5; +}; + +struct hspi_device_register{ + uint32 hspi_flash_reg_backup[9]; + uint32 hspi_dev_reg_backup[9]; + struct hspi_device_config hspi_dev_conf[4]; + uint8 selected_dev_num:3; + uint8 spi_io_80m:1; + uint8 hspi_reg_backup_flag:1; + uint8 res:3; +}; + +void hspi_overlap_init(void); +void hspi_overlap_deinit(void); +void spi_reg_recover(uint8 spi_no,uint32* backup_mem); +void spi_reg_backup(uint8 spi_no,uint32* backup_mem); + +void hspi_master_dev_init(uint8 dev_no,uint8 clk_polar,uint8 clk_div); +void hspi_dev_sel(uint8 dev_no); + +void hspi_overlap_flash_init(void); +SpiFlashOpResult hspi_overlap_read_flash_data(SpiFlashChip * spi, uint32 flash_addr, uint32 * addr_dest, uint32 byte_length); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_register.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_register.h new file mode 100644 index 0000000000..98289df5ca --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/spi_register.h @@ -0,0 +1,222 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef SPI_REGISTER_H_INCLUDED +#define SPI_REGISTER_H_INCLUDED + +#define REG_SPI_BASE(i) (0x60000200-i*0x100) +#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) + +#define SPI_FLASH_READ BIT31 +#define SPI_FLASH_WREN BIT30 +#define SPI_FLASH_WRDI BIT29 +#define SPI_FLASH_RDID BIT28 +#define SPI_FLASH_RDSR BIT27 +#define SPI_FLASH_WRSR BIT26 +#define SPI_FLASH_PP BIT25 +#define SPI_FLASH_SE BIT24 +#define SPI_FLASH_BE BIT23 +#define SPI_FLASH_CE BIT22 +#define SPI_FLASH_RES BIT20 + +#define SPI_USR (BIT(18)) + +#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) + +#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) +#define SPI_WR_BIT_ORDER (BIT(26)) +#define SPI_RD_BIT_ORDER (BIT(25)) +#define SPI_QIO_MODE (BIT(24)) +#define SPI_DIO_MODE (BIT(23)) +#define SPI_QOUT_MODE (BIT(20)) +#define SPI_DOUT_MODE (BIT(14)) +#define SPI_FASTRD_MODE (BIT(13)) + +#define SPI_CTRL1(i) (REG_SPI_BASE(i) + 0xc) +#define SPI_CS_HOLD_DELAY 0xf +#define SPI_CS_HOLD_DELAY_S 28 +#define SPI_CS_HOLD_DELAY_RES 0xfff +#define SPI_CS_HOLD_DELAY_RES_S 16 + + +#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) + +#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) + +#define SPI_CS_DELAY_NUM 0x0000000F +#define SPI_CS_DELAY_NUM_S 28 +#define SPI_CS_DELAY_MODE 0x00000003 +#define SPI_CS_DELAY_MODE_S 26 +#define SPI_MOSI_DELAY_NUM 0x00000007 +#define SPI_MOSI_DELAY_NUM_S 23 +#define SPI_MOSI_DELAY_MODE 0x00000003 +#define SPI_MOSI_DELAY_MODE_S 21 +#define SPI_MISO_DELAY_NUM 0x00000007 +#define SPI_MISO_DELAY_NUM_S 18 +#define SPI_MISO_DELAY_MODE 0x00000003 +#define SPI_MISO_DELAY_MODE_S 16 +#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) +#define SPI_CLK_EQU_SYSCLK (BIT(31)) +#define SPI_CLKDIV_PRE 0x00001FFF +#define SPI_CLKDIV_PRE_S 18 +#define SPI_CLKCNT_N 0x0000003F +#define SPI_CLKCNT_N_S 12 +#define SPI_CLKCNT_H 0x0000003F +#define SPI_CLKCNT_H_S 6 +#define SPI_CLKCNT_L 0x0000003F +#define SPI_CLKCNT_L_S 0 + +#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) +#define SPI_USR_COMMAND (BIT(31)) +#define SPI_USR_ADDR (BIT(30)) +#define SPI_USR_DUMMY (BIT(29)) +#define SPI_USR_MISO (BIT(28)) +#define SPI_USR_MOSI (BIT(27)) + +#define SPI_USR_MOSI_HIGHPART (BIT(25)) +#define SPI_USR_MISO_HIGHPART (BIT(24)) + + +#define SPI_SIO (BIT(16)) +#define SPI_FWRITE_QIO (BIT(15)) +#define SPI_FWRITE_DIO (BIT(14)) +#define SPI_FWRITE_QUAD (BIT(13)) +#define SPI_FWRITE_DUAL (BIT(12)) +#define SPI_WR_BYTE_ORDER (BIT(11)) +#define SPI_RD_BYTE_ORDER (BIT(10)) +#define SPI_CK_OUT_EDGE (BIT(7)) +#define SPI_CK_I_EDGE (BIT(6)) +#define SPI_CS_SETUP (BIT(5)) +#define SPI_CS_HOLD (BIT(4)) +#define SPI_FLASH_MODE (BIT(2)) + +#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) +#define SPI_USR_ADDR_BITLEN 0x0000003F +#define SPI_USR_ADDR_BITLEN_S 26 +#define SPI_USR_MOSI_BITLEN 0x000001FF +#define SPI_USR_MOSI_BITLEN_S 17 +#define SPI_USR_MISO_BITLEN 0x000001FF +#define SPI_USR_MISO_BITLEN_S 8 + +#define SPI_USR_DUMMY_CYCLELEN 0x000000FF +#define SPI_USR_DUMMY_CYCLELEN_S 0 + +#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) +#define SPI_USR_COMMAND_BITLEN 0x0000000F +#define SPI_USR_COMMAND_BITLEN_S 28 +#define SPI_USR_COMMAND_VALUE 0x0000FFFF +#define SPI_USR_COMMAND_VALUE_S 0 + +#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) +#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) +#define SPI_IDLE_EDGE (BIT(29)) +#define SPI_CS2_DIS (BIT(2)) +#define SPI_CS1_DIS (BIT(1)) +#define SPI_CS0_DIS (BIT(0)) + +#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) +#define SPI_SYNC_RESET (BIT(31)) +#define SPI_SLAVE_MODE (BIT(30)) +#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) +#define SPI_SLV_WR_RD_STA_EN (BIT(28)) +#define SPI_SLV_CMD_DEFINE (BIT(27)) +#define SPI_TRANS_CNT 0x0000000F +#define SPI_TRANS_CNT_S 23 +#define SPI_TRANS_DONE_EN (BIT(9)) +#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) +#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) +#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) +#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) + + + +#define SLV_SPI_INT_EN 0x0000001f +#define SLV_SPI_INT_EN_S 5 + +#define SPI_TRANS_DONE (BIT(4)) +#define SPI_SLV_WR_STA_DONE (BIT(3)) +#define SPI_SLV_RD_STA_DONE (BIT(2)) +#define SPI_SLV_WR_BUF_DONE (BIT(1)) +#define SPI_SLV_RD_BUF_DONE (BIT(0)) + +#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) +#define SPI_SLV_STATUS_BITLEN 0x0000001F +#define SPI_SLV_STATUS_BITLEN_S 27 +#define SPI_SLV_BUF_BITLEN 0x000001FF +#define SPI_SLV_BUF_BITLEN_S 16 +#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F +#define SPI_SLV_RD_ADDR_BITLEN_S 10 +#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F +#define SPI_SLV_WR_ADDR_BITLEN_S 4 + +#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) +#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) +#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) +#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) + + + +#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 + +#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) +#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_WRSTA_CMD_VALUE_S 24 +#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_RDSTA_CMD_VALUE_S 16 +#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_WRBUF_CMD_VALUE_S 8 +#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_RDBUF_CMD_VALUE_S 0 + +#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) +#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) +#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) +#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) +#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) +#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) +#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) +#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) +#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) +#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) +#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) +#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) +#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) +#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) +#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) +#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) + +#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) + +#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) +#define SPI_INT_HOLD_ENA 0x00000003 +#define SPI_INT_HOLD_ENA_S 0 +#endif // SPI_REGISTER_H_INCLUDED diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart.h new file mode 100644 index 0000000000..07afb89321 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart.h @@ -0,0 +1,229 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef UART_APP_H +#define UART_APP_H + +#include "uart_register.h" +#include "eagle_soc.h" +#include "c_types.h" + +#define UART_TX_BUFFER_SIZE 256 //Ring buffer length of tx buffer +#define UART_RX_BUFFER_SIZE 256 //Ring buffer length of rx buffer + +#define UART_BUFF_EN 0 //use uart buffer , FOR UART0 +#define UART_SELFTEST 0 //set 1:enable the loop test demo for uart buffer, FOR UART0 + +#define UART_HW_RTS 0 //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0 +#define UART_HW_CTS 0 //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0 + + + + +#define UART0 0 +#define UART1 1 + + +typedef enum { + FIVE_BITS = 0x0, + SIX_BITS = 0x1, + SEVEN_BITS = 0x2, + EIGHT_BITS = 0x3 +} UartBitsNum4Char; + +typedef enum { + ONE_STOP_BIT = 0x1, + ONE_HALF_STOP_BIT = 0x2, + TWO_STOP_BIT = 0x3 +} UartStopBitsNum; + +typedef enum { + NONE_BITS = 0x2, + ODD_BITS = 1, + EVEN_BITS = 0 +} UartParityMode; + +typedef enum { + STICK_PARITY_DIS = 0, + STICK_PARITY_EN = 1 +} UartExistParity; + +typedef enum { + UART_None_Inverse = 0x0, + UART_Rxd_Inverse = UART_RXD_INV, + UART_CTS_Inverse = UART_CTS_INV, + UART_Txd_Inverse = UART_TXD_INV, + UART_RTS_Inverse = UART_RTS_INV, +} UART_LineLevelInverse; + + +typedef enum { + BIT_RATE_300 = 300, + BIT_RATE_600 = 600, + BIT_RATE_1200 = 1200, + BIT_RATE_2400 = 2400, + BIT_RATE_4800 = 4800, + BIT_RATE_9600 = 9600, + BIT_RATE_19200 = 19200, + BIT_RATE_38400 = 38400, + BIT_RATE_57600 = 57600, + BIT_RATE_74880 = 74880, + BIT_RATE_115200 = 115200, + BIT_RATE_230400 = 230400, + BIT_RATE_460800 = 460800, + BIT_RATE_921600 = 921600, + BIT_RATE_1843200 = 1843200, + BIT_RATE_3686400 = 3686400, +} UartBautRate; + +typedef enum { + NONE_CTRL, + HARDWARE_CTRL, + XON_XOFF_CTRL +} UartFlowCtrl; + +typedef enum { + USART_HardwareFlowControl_None = 0x0, + USART_HardwareFlowControl_RTS = 0x1, + USART_HardwareFlowControl_CTS = 0x2, + USART_HardwareFlowControl_CTS_RTS = 0x3 +} UART_HwFlowCtrl; + +typedef enum { + EMPTY, + UNDER_WRITE, + WRITE_OVER +} RcvMsgBuffState; + +typedef struct { + uint32 RcvBuffSize; + uint8 *pRcvMsgBuff; + uint8 *pWritePos; + uint8 *pReadPos; + uint8 TrigLvl; //JLU: may need to pad + RcvMsgBuffState BuffState; +} RcvMsgBuff; + +typedef struct { + uint32 TrxBuffSize; + uint8 *pTrxBuff; +} TrxMsgBuff; + +typedef enum { + BAUD_RATE_DET, + WAIT_SYNC_FRM, + SRCH_MSG_HEAD, + RCV_MSG_BODY, + RCV_ESC_CHAR, +} RcvMsgState; + +typedef struct { + UartBautRate baut_rate; + UartBitsNum4Char data_bits; + UartExistParity exist_parity; + UartParityMode parity; + UartStopBitsNum stop_bits; + UartFlowCtrl flow_ctrl; + RcvMsgBuff rcv_buff; + TrxMsgBuff trx_buff; + RcvMsgState rcv_state; + int received; + int buff_uart_no; //indicate which uart use tx/rx buffer +} UartDevice; + +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +void uart0_sendStr(const char *str); + + +/////////////////////////////////////// +#define UART_FIFO_LEN 128 //define the tx fifo length +#define UART_TX_EMPTY_THRESH_VAL 0x10 + + + struct UartBuffer{ + uint32 UartBuffSize; + uint8 *pUartBuff; + uint8 *pInPos; + uint8 *pOutPos; + STATUS BuffState; + uint16 Space; //remanent space of the buffer + uint8 TcpControl; + struct UartBuffer * nextBuff; +}; + +struct UartRxBuff{ + uint32 UartRxBuffSize; + uint8 *pUartRxBuff; + uint8 *pWritePos; + uint8 *pReadPos; + STATUS RxBuffState; + uint32 Space; //remanent space of the buffer +} ; + +typedef enum { + RUN = 0, + BLOCK = 1, +} TCPState; + +//void ICACHE_FLASH_ATTR uart_test_rx(); +STATUS uart_tx_one_char(uint8 uart, uint8 TxChar); +STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar); +void uart1_sendStr_no_wait(const char *str); +struct UartBuffer* Uart_Buf_Init(); + + +#if UART_BUFF_EN +LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len); +void uart_buf_free(struct UartBuffer* pBuff); +void tx_buff_enq(char* pdata, uint16 data_len ); +LOCAL void tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len, uint8 uart_no); +void tx_start_uart_buffer(uint8 uart_no); +uint16 rx_buff_deq(char* pdata, uint16 data_len ); +void Uart_rx_buff_enq(); +#endif +void uart_rx_intr_enable(uint8 uart_no); +void uart_rx_intr_disable(uint8 uart_no); +void uart0_tx_buffer(uint8 *buf, uint16 len); + +//============================================== +#define FUNC_UART0_CTS 4 +#define FUNC_U0CTS 4 +#define FUNC_U1TXD_BK 2 +#define UART_LINE_INV_MASK (0x3f<<19) +void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len); +void UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num); +void UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask); +void UART_SetParity(uint8 uart_no, UartParityMode Parity_mode); +void UART_SetBaudrate(uint8 uart_no,uint32 baud_rate); +void UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh); +void UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us); //do not use if tx flow control enabled +void UART_ResetFifo(uint8 uart_no); +void UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask); +void UART_SetIntrEna(uint8 uart_no,uint32 ena_mask); +void UART_SetPrintPort(uint8 uart_no); +bool UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us); +//============================================== + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart_register.h b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart_register.h new file mode 100644 index 0000000000..4800df7868 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/include/driver/uart_register.h @@ -0,0 +1,159 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef UART_REGISTER_H_ +#define UART_REGISTER_H_ + +#define REG_UART_BASE(i) (0x60000000 + (i)*0xf00) +//version value:32'h062000 + +#define UART_FIFO(i) (REG_UART_BASE(i) + 0x0) +#define UART_RXFIFO_RD_BYTE 0x000000FF +#define UART_RXFIFO_RD_BYTE_S 0 + +#define UART_INT_RAW(i) (REG_UART_BASE(i) + 0x4) +#define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) +#define UART_BRK_DET_INT_RAW (BIT(7)) +#define UART_CTS_CHG_INT_RAW (BIT(6)) +#define UART_DSR_CHG_INT_RAW (BIT(5)) +#define UART_RXFIFO_OVF_INT_RAW (BIT(4)) +#define UART_FRM_ERR_INT_RAW (BIT(3)) +#define UART_PARITY_ERR_INT_RAW (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) +#define UART_RXFIFO_FULL_INT_RAW (BIT(0)) + +#define UART_INT_ST(i) (REG_UART_BASE(i) + 0x8) +#define UART_RXFIFO_TOUT_INT_ST (BIT(8)) +#define UART_BRK_DET_INT_ST (BIT(7)) +#define UART_CTS_CHG_INT_ST (BIT(6)) +#define UART_DSR_CHG_INT_ST (BIT(5)) +#define UART_RXFIFO_OVF_INT_ST (BIT(4)) +#define UART_FRM_ERR_INT_ST (BIT(3)) +#define UART_PARITY_ERR_INT_ST (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) +#define UART_RXFIFO_FULL_INT_ST (BIT(0)) + +#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC) +#define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) +#define UART_BRK_DET_INT_ENA (BIT(7)) +#define UART_CTS_CHG_INT_ENA (BIT(6)) +#define UART_DSR_CHG_INT_ENA (BIT(5)) +#define UART_RXFIFO_OVF_INT_ENA (BIT(4)) +#define UART_FRM_ERR_INT_ENA (BIT(3)) +#define UART_PARITY_ERR_INT_ENA (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) +#define UART_RXFIFO_FULL_INT_ENA (BIT(0)) + +#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10) +#define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) +#define UART_BRK_DET_INT_CLR (BIT(7)) +#define UART_CTS_CHG_INT_CLR (BIT(6)) +#define UART_DSR_CHG_INT_CLR (BIT(5)) +#define UART_RXFIFO_OVF_INT_CLR (BIT(4)) +#define UART_FRM_ERR_INT_CLR (BIT(3)) +#define UART_PARITY_ERR_INT_CLR (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) +#define UART_RXFIFO_FULL_INT_CLR (BIT(0)) + +#define UART_CLKDIV(i) (REG_UART_BASE(i) + 0x14) +#define UART_CLKDIV_CNT 0x000FFFFF +#define UART_CLKDIV_S 0 + +#define UART_AUTOBAUD(i) (REG_UART_BASE(i) + 0x18) +#define UART_GLITCH_FILT 0x000000FF +#define UART_GLITCH_FILT_S 8 +#define UART_AUTOBAUD_EN (BIT(0)) + +#define UART_STATUS(i) (REG_UART_BASE(i) + 0x1C) +#define UART_TXD (BIT(31)) +#define UART_RTSN (BIT(30)) +#define UART_DTRN (BIT(29)) +#define UART_TXFIFO_CNT 0x000000FF +#define UART_TXFIFO_CNT_S 16 +#define UART_RXD (BIT(15)) +#define UART_CTSN (BIT(14)) +#define UART_DSRN (BIT(13)) +#define UART_RXFIFO_CNT 0x000000FF +#define UART_RXFIFO_CNT_S 0 + +#define UART_CONF0(i) (REG_UART_BASE(i) + 0x20) +#define UART_DTR_INV (BIT(24)) +#define UART_RTS_INV (BIT(23)) +#define UART_TXD_INV (BIT(22)) +#define UART_DSR_INV (BIT(21)) +#define UART_CTS_INV (BIT(20)) +#define UART_RXD_INV (BIT(19)) +#define UART_TXFIFO_RST (BIT(18)) +#define UART_RXFIFO_RST (BIT(17)) +#define UART_IRDA_EN (BIT(16)) +#define UART_TX_FLOW_EN (BIT(15)) +#define UART_LOOPBACK (BIT(14)) +#define UART_IRDA_RX_INV (BIT(13)) +#define UART_IRDA_TX_INV (BIT(12)) +#define UART_IRDA_WCTL (BIT(11)) +#define UART_IRDA_TX_EN (BIT(10)) +#define UART_IRDA_DPLX (BIT(9)) +#define UART_TXD_BRK (BIT(8)) +#define UART_SW_DTR (BIT(7)) +#define UART_SW_RTS (BIT(6)) +#define UART_STOP_BIT_NUM 0x00000003 +#define UART_STOP_BIT_NUM_S 4 +#define UART_BIT_NUM 0x00000003 +#define UART_BIT_NUM_S 2 +#define UART_PARITY_EN (BIT(1)) +#define UART_PARITY_EN_M 0x00000001 +#define UART_PARITY_EN_S 1 +#define UART_PARITY (BIT(0)) +#define UART_PARITY_M 0x00000001 +#define UART_PARITY_S 0 + +#define UART_CONF1(i) (REG_UART_BASE(i) + 0x24) +#define UART_RX_TOUT_EN (BIT(31)) +#define UART_RX_TOUT_THRHD 0x0000007F +#define UART_RX_TOUT_THRHD_S 24 +#define UART_RX_FLOW_EN (BIT(23)) +#define UART_RX_FLOW_THRHD 0x0000007F +#define UART_RX_FLOW_THRHD_S 16 +#define UART_TXFIFO_EMPTY_THRHD 0x0000007F +#define UART_TXFIFO_EMPTY_THRHD_S 8 +#define UART_RXFIFO_FULL_THRHD 0x0000007F +#define UART_RXFIFO_FULL_THRHD_S 0 + +#define UART_LOWPULSE(i) (REG_UART_BASE(i) + 0x28) +#define UART_LOWPULSE_MIN_CNT 0x000FFFFF +#define UART_LOWPULSE_MIN_CNT_S 0 + +#define UART_HIGHPULSE(i) (REG_UART_BASE(i) + 0x2C) +#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF +#define UART_HIGHPULSE_MIN_CNT_S 0 + +#define UART_PULSE_NUM(i) (REG_UART_BASE(i) + 0x30) +#define UART_PULSE_NUM_CNT 0x0003FF +#define UART_PULSE_NUM_CNT_S 0 + +#define UART_DATE(i) (REG_UART_BASE(i) + 0x78) +#define UART_ID(i) (REG_UART_BASE(i) + 0x7C) + +#endif // UART_REGISTER_H_INCLUDED + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/make_lib.sh b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/make_lib.sh new file mode 100644 index 0000000000..d8573b67e8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/driver_lib/make_lib.sh @@ -0,0 +1,14 @@ +#!/bin/bash -x + +echo "make_lib.sh version 20160307" +echo "" + +touch include/user_config.h + +cd $1 +make clean +make COMPILE=gcc +cp .output/eagle/debug/lib/lib$1.a ../../lib/lib$1.a +xtensa-lx106-elf-strip --strip-unneeded ../../lib/lib$1.a +cd .. +rm include/user_config.h diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/Makefile new file mode 100644 index 0000000000..b1758da6c4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/Makefile @@ -0,0 +1,127 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user \ + driver + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a \ + driver/libdriver.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lupgrade\ + -lssl \ + -lpwm \ + -lsmartconfig \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/Makefile new file mode 100644 index 0000000000..38fd29fcd6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libdriver.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/i2c_master.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/i2c_master.c new file mode 100644 index 0000000000..5f6fc93060 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/i2c_master.c @@ -0,0 +1,330 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "gpio.h" + +#include "driver/i2c_master.h" + +LOCAL uint8 m_nLastSDA; +LOCAL uint8 m_nLastSCL; + +/****************************************************************************** + * FunctionName : i2c_master_setDC + * Description : Internal used function - + * set i2c SDA and SCL bit value for half clk cycle + * Parameters : uint8 SDA + * uint8 SCL + * Returns : NONE +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +i2c_master_setDC(uint8 SDA, uint8 SCL) +{ + SDA &= 0x01; + SCL &= 0x01; + m_nLastSDA = SDA; + m_nLastSCL = SCL; + + if ((0 == SDA) && (0 == SCL)) { + I2C_MASTER_SDA_LOW_SCL_LOW(); + } else if ((0 == SDA) && (1 == SCL)) { + I2C_MASTER_SDA_LOW_SCL_HIGH(); + } else if ((1 == SDA) && (0 == SCL)) { + I2C_MASTER_SDA_HIGH_SCL_LOW(); + } else { + I2C_MASTER_SDA_HIGH_SCL_HIGH(); + } +} + +/****************************************************************************** + * FunctionName : i2c_master_getDC + * Description : Internal used function - + * get i2c SDA bit value + * Parameters : NONE + * Returns : uint8 - SDA bit value +*******************************************************************************/ +LOCAL uint8 ICACHE_FLASH_ATTR +i2c_master_getDC(void) +{ + uint8 sda_out; + sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); + return sda_out; +} + +/****************************************************************************** + * FunctionName : i2c_master_init + * Description : initilize I2C bus to enable i2c operations + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_init(void) +{ + uint8 i; + + i2c_master_setDC(1, 0); + i2c_master_wait(5); + + // when SCL = 0, toggle SDA to clear up + i2c_master_setDC(0, 0) ; + i2c_master_wait(5); + i2c_master_setDC(1, 0) ; + i2c_master_wait(5); + + // set data_cnt to max value + for (i = 0; i < 28; i++) { + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + } + + // reset all + i2c_master_stop(); + return; +} + +/****************************************************************************** + * FunctionName : i2c_master_gpio_init + * Description : config SDA and SCL gpio to open-drain output mode, + * mux and gpio num defined in i2c_master.h + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_gpio_init(void) +{ + ETS_GPIO_INTR_DISABLE() ; +// ETS_INTR_LOCK(); + + PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC); + PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC); + + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO)); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain; + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO)); + + I2C_MASTER_SDA_HIGH_SCL_HIGH(); + + ETS_GPIO_INTR_ENABLE() ; +// ETS_INTR_UNLOCK(); + + i2c_master_init(); +} + +/****************************************************************************** + * FunctionName : i2c_master_start + * Description : set i2c to send state + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_start(void) +{ + i2c_master_setDC(1, m_nLastSCL); + i2c_master_wait(5); + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + i2c_master_setDC(0, 1); + i2c_master_wait(5); // sda 0, scl 1 +} + +/****************************************************************************** + * FunctionName : i2c_master_stop + * Description : set i2c to stop sending state + * Parameters : NONE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_stop(void) +{ + i2c_master_wait(5); + + i2c_master_setDC(0, m_nLastSCL); + i2c_master_wait(5); // sda 0 + i2c_master_setDC(0, 1); + i2c_master_wait(5); // sda 0, scl 1 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 +} + +/****************************************************************************** + * FunctionName : i2c_master_setAck + * Description : set ack to i2c bus as level value + * Parameters : uint8 level - 0 or 1 + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_setAck(uint8 level) +{ + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + i2c_master_setDC(level, 0); + i2c_master_wait(5); // sda level, scl 0 + i2c_master_setDC(level, 1); + i2c_master_wait(8); // sda level, scl 1 + i2c_master_setDC(level, 0); + i2c_master_wait(5); // sda level, scl 0 + i2c_master_setDC(1, 0); + i2c_master_wait(5); +} + +/****************************************************************************** + * FunctionName : i2c_master_getAck + * Description : confirm if peer send ack + * Parameters : NONE + * Returns : uint8 - ack value, 0 or 1 +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_getAck(void) +{ + uint8 retVal; + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); + i2c_master_setDC(1, 1); + i2c_master_wait(5); + + retVal = i2c_master_getDC(); + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); + + return retVal; +} + +/****************************************************************************** +* FunctionName : i2c_master_checkAck +* Description : get dev response +* Parameters : NONE +* Returns : true : get ack ; false : get nack +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +i2c_master_checkAck(void) +{ + if(i2c_master_getAck()){ + return FALSE; + }else{ + return TRUE; + } +} + +/****************************************************************************** +* FunctionName : i2c_master_send_ack +* Description : response ack +* Parameters : NONE +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_ack(void) +{ + i2c_master_setAck(0x0); +} +/****************************************************************************** +* FunctionName : i2c_master_send_nack +* Description : response nack +* Parameters : NONE +* Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_send_nack(void) +{ + i2c_master_setAck(0x1); +} + +/****************************************************************************** + * FunctionName : i2c_master_readByte + * Description : read Byte from i2c bus + * Parameters : NONE + * Returns : uint8 - readed value +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +i2c_master_readByte(void) +{ + uint8 retVal = 0; + uint8 k, i; + + i2c_master_wait(5); + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); // sda 1, scl 0 + + for (i = 0; i < 8; i++) { + i2c_master_wait(5); + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + i2c_master_setDC(1, 1); + i2c_master_wait(5); // sda 1, scl 1 + + k = i2c_master_getDC(); + i2c_master_wait(5); + + if (i == 7) { + i2c_master_wait(3); //// + } + + k <<= (7 - i); + retVal |= k; + } + + i2c_master_setDC(1, 0); + i2c_master_wait(5); // sda 1, scl 0 + + return retVal; +} + +/****************************************************************************** + * FunctionName : i2c_master_writeByte + * Description : write wrdata value(one byte) into i2c + * Parameters : uint8 wrdata - write value + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +i2c_master_writeByte(uint8 wrdata) +{ + uint8 dat; + sint8 i; + + i2c_master_wait(5); + + i2c_master_setDC(m_nLastSDA, 0); + i2c_master_wait(5); + + for (i = 7; i >= 0; i--) { + dat = wrdata >> i; + i2c_master_setDC(dat, 0); + i2c_master_wait(5); + i2c_master_setDC(dat, 1); + i2c_master_wait(5); + + if (i == 0) { + i2c_master_wait(3); //// + } + + i2c_master_setDC(dat, 0); + i2c_master_wait(5); + } +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/key.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/key.c new file mode 100644 index 0000000000..2a931607b3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/driver/key.c @@ -0,0 +1,177 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "gpio.h" +#include "user_interface.h" + +#include "driver/key.h" + +LOCAL void key_intr_handler(void *arg); + +/****************************************************************************** + * FunctionName : key_init_single + * Description : init single key's gpio and register function + * Parameters : uint8 gpio_id - which gpio to use + * uint32 gpio_name - gpio mux name + * uint32 gpio_func - gpio function + * key_function long_press - long press function, needed to install + * key_function short_press - short press function, needed to install + * Returns : single_key_param - single key parameter, needed by key init +*******************************************************************************/ +struct single_key_param *ICACHE_FLASH_ATTR +key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press) +{ + struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param)); + + single_key->gpio_id = gpio_id; + single_key->gpio_name = gpio_name; + single_key->gpio_func = gpio_func; + single_key->long_press = long_press; + single_key->short_press = short_press; + + return single_key; +} + +/****************************************************************************** + * FunctionName : key_init + * Description : init keys + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +key_init(struct keys_param *keys) +{ + uint8 i; + + ETS_GPIO_INTR_ATTACH(key_intr_handler, keys); + + ETS_GPIO_INTR_DISABLE(); + + for (i = 0; i < keys->key_num; i++) { + keys->single_key[i]->key_level = 1; + + PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func); + + gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id)); + + gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE) + | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) + | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE)); + + //clear gpio14 status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id)); + + //enable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE); + } + + ETS_GPIO_INTR_ENABLE(); +} + +/****************************************************************************** + * FunctionName : key_5s_cb + * Description : long press 5s timer callback + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_5s_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_5s); + + // low, then restart + if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + if (single_key->long_press) { + single_key->long_press(); + } + } +} + +/****************************************************************************** + * FunctionName : key_50ms_cb + * Description : 50ms timer callback to check it's a real key push + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_50ms_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_50ms); + + // high, then key is up + if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + os_timer_disarm(&single_key->key_5s); + single_key->key_level = 1; + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE); + + if (single_key->short_press) { + single_key->short_press(); + } + } else { + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE); + } +} + +/****************************************************************************** + * FunctionName : key_intr_handler + * Description : key interrupt handler + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +LOCAL void +key_intr_handler(void *arg) +{ + uint8 i; + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + struct keys_param *keys = (struct keys_param *)arg; + + for (i = 0; i < keys->key_num; i++) { + if (gpio_status & BIT(keys->single_key[i]->gpio_id)) { + //disable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE); + + //clear interrupt status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id)); + + if (keys->single_key[i]->key_level == 1) { + // 5s, restart & enter softap mode + os_timer_disarm(&keys->single_key[i]->key_5s); + os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0); + keys->single_key[i]->key_level = 0; + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE); + } else { + // 50ms, check if this is a real key up + os_timer_disarm(&keys->single_key[i]->key_50ms); + os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0); + } + } + } +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.sh new file mode 100755 index 0000000000..7f70c784e5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/gen_misc.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/driver/i2c_master.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/driver/i2c_master.h new file mode 100644 index 0000000000..acbd5f26d8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/driver/i2c_master.h @@ -0,0 +1,81 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __I2C_MASTER_H__ +#define __I2C_MASTER_H__ + +#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U +#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U +#define I2C_MASTER_SDA_GPIO 2 +#define I2C_MASTER_SCL_GPIO 14 +#define I2C_MASTER_SDA_FUNC FUNC_GPIO2 +#define I2C_MASTER_SCL_FUNC FUNC_GPIO14 + +//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U +//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U +//#define I2C_MASTER_SDA_GPIO 2 +//#define I2C_MASTER_SCL_GPIO 0 +//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2 +//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0 + +#if 0 +#define I2C_MASTER_GPIO_SET(pin) \ + gpio_output_set(1< + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#include "gpio.h" + +typedef void (* key_function)(void); + +struct single_key_param { + uint8 key_level; + uint8 gpio_id; + uint8 gpio_func; + uint32 gpio_name; + os_timer_t key_5s; + os_timer_t key_50ms; + key_function short_press; + key_function long_press; +}; + +struct keys_param { + uint8 key_num; + struct single_key_param **single_key; +}; + +struct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press); +void key_init(struct keys_param *key); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/cert.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/cert.h new file mode 100644 index 0000000000..2fd39c1cce --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/cert.h @@ -0,0 +1,60 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +unsigned char default_certificate[] = { + 0x30, 0x82, 0x01, 0x82, 0x30, 0x81, 0xec, 0x02, 0x09, 0x00, 0x88, 0xf2, + 0x5f, 0x46, 0x12, 0x2e, 0x3d, 0x3a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1c, 0x31, + 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x77, 0x77, + 0x77, 0x2e, 0x65, 0x73, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x66, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x32, + 0x34, 0x31, 0x30, 0x32, 0x32, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x38, + 0x30, 0x33, 0x30, 0x32, 0x31, 0x30, 0x32, 0x32, 0x33, 0x33, 0x5a, 0x30, + 0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, + 0x65, 0x73, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x66, 0x31, 0x1e, 0x30, + 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x65, 0x73, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x66, 0x20, 0x49, 0x6f, 0x54, 0x20, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, + 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xb9, 0x83, 0x30, 0xca, 0xfb, 0xec, + 0x11, 0x9e, 0x94, 0xb7, 0x89, 0xf2, 0x84, 0x2c, 0xda, 0xe1, 0x9a, 0x53, + 0x3a, 0x1b, 0x6e, 0xc9, 0x85, 0x81, 0xf9, 0xa3, 0x41, 0xdb, 0xe2, 0x82, + 0x3b, 0xfa, 0x80, 0x22, 0x3b, 0x81, 0x6d, 0x25, 0x73, 0x7e, 0xf6, 0x49, + 0xcc, 0x69, 0x3c, 0x6c, 0xd8, 0x05, 0xfb, 0x92, 0x02, 0xcf, 0x19, 0x2a, + 0x10, 0x7d, 0x69, 0x7a, 0xd8, 0x9d, 0xd3, 0xcf, 0x6c, 0xef, 0x02, 0x03, + 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x2d, 0x63, + 0x58, 0x21, 0xe3, 0x8b, 0x37, 0x0d, 0x28, 0x68, 0x11, 0x0e, 0x4d, 0xdd, + 0xf3, 0xea, 0xdb, 0xec, 0xd7, 0x09, 0x47, 0x2c, 0xa1, 0xd8, 0xd1, 0x71, + 0x83, 0x11, 0xb4, 0x17, 0xbc, 0x83, 0xea, 0x5a, 0xd6, 0x73, 0x02, 0x25, + 0x87, 0x01, 0x76, 0xfc, 0x59, 0x1a, 0xcf, 0xd9, 0x49, 0xc9, 0xf9, 0x1f, + 0x5c, 0x3b, 0x24, 0x6a, 0x5c, 0xa5, 0xca, 0xe6, 0x5d, 0x34, 0x5b, 0x5f, + 0xcf, 0x56, 0x9c, 0x71, 0xd2, 0x6b, 0xdd, 0x1f, 0x15, 0xae, 0x4d, 0xf1, + 0xca, 0x35, 0xc8, 0xdd, 0x93, 0x1b, 0x58, 0x1e, 0x94, 0x08, 0xcf, 0xa0, + 0x20, 0xb9, 0x75, 0xa5, 0x4c, 0x77, 0xf5, 0x7f, 0xed, 0xd5, 0xcd, 0x53, + 0xaa, 0x87, 0xa6, 0x3c, 0xf5, 0x72, 0xd8, 0xd2, 0xb0, 0xf7, 0x11, 0xb0, + 0x0e, 0xe9, 0x41, 0xd6, 0x8e, 0xd9, 0x07, 0xf8, 0xed, 0xf8, 0x67, 0x7f, + 0x28, 0x18, 0xf0, 0x1b, 0x29, 0x11 +}; +unsigned int default_certificate_len = 390; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/private_key.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/private_key.h new file mode 100644 index 0000000000..daf8515811 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/ssl/private_key.h @@ -0,0 +1,54 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +unsigned char default_private_key[] = { + 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xb9, 0x83, + 0x30, 0xca, 0xfb, 0xec, 0x11, 0x9e, 0x94, 0xb7, 0x89, 0xf2, 0x84, 0x2c, + 0xda, 0xe1, 0x9a, 0x53, 0x3a, 0x1b, 0x6e, 0xc9, 0x85, 0x81, 0xf9, 0xa3, + 0x41, 0xdb, 0xe2, 0x82, 0x3b, 0xfa, 0x80, 0x22, 0x3b, 0x81, 0x6d, 0x25, + 0x73, 0x7e, 0xf6, 0x49, 0xcc, 0x69, 0x3c, 0x6c, 0xd8, 0x05, 0xfb, 0x92, + 0x02, 0xcf, 0x19, 0x2a, 0x10, 0x7d, 0x69, 0x7a, 0xd8, 0x9d, 0xd3, 0xcf, + 0x6c, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x1d, 0x13, 0x92, + 0xf2, 0x3d, 0xca, 0x22, 0x78, 0xd8, 0x96, 0x6b, 0xe8, 0xb7, 0x0e, 0xd0, + 0xbf, 0xcb, 0x90, 0x7f, 0xeb, 0x0c, 0xd2, 0x49, 0x3a, 0xb6, 0x06, 0x00, + 0xac, 0x96, 0x34, 0x13, 0x72, 0x4b, 0x8c, 0xd2, 0xb9, 0x35, 0xf5, 0x64, + 0x18, 0xb2, 0x47, 0x5b, 0x9f, 0xbb, 0xf2, 0x5b, 0x2f, 0x66, 0x78, 0x2d, + 0x0a, 0x76, 0x44, 0xc5, 0x4f, 0xdb, 0x7d, 0x13, 0xcf, 0xa5, 0x08, 0xdc, + 0x01, 0x02, 0x21, 0x00, 0xdf, 0x9a, 0x89, 0xd0, 0xef, 0x23, 0xcf, 0x12, + 0xac, 0x8a, 0x63, 0x1a, 0x8c, 0xc0, 0x3f, 0xf4, 0x38, 0x52, 0x3c, 0x9f, + 0x19, 0x0a, 0x37, 0xd2, 0xcb, 0x5d, 0xeb, 0xb6, 0x2a, 0x33, 0xb0, 0x91, + 0x02, 0x21, 0x00, 0xd4, 0x63, 0xd9, 0x6a, 0x18, 0x5b, 0xe8, 0xa8, 0x57, + 0x4d, 0xd1, 0x9a, 0xa8, 0xd7, 0xe1, 0x65, 0x75, 0xb3, 0xb9, 0x5c, 0x94, + 0x14, 0xca, 0x98, 0x41, 0x47, 0x9c, 0x0a, 0x22, 0x38, 0x05, 0x7f, 0x02, + 0x20, 0x6a, 0xce, 0xfd, 0xef, 0xe0, 0x9b, 0x61, 0x49, 0x91, 0x43, 0x95, + 0x6d, 0x54, 0x38, 0x6d, 0x14, 0x32, 0x67, 0x0d, 0xf0, 0x0d, 0x5c, 0xf5, + 0x27, 0x6a, 0xdf, 0x55, 0x3d, 0xb1, 0xd0, 0xf9, 0x11, 0x02, 0x21, 0x00, + 0xba, 0x94, 0xa0, 0xf9, 0xb0, 0x3e, 0x85, 0x8b, 0xe5, 0x6e, 0x4a, 0x95, + 0x88, 0x80, 0x65, 0xd5, 0x00, 0xea, 0x8b, 0x0b, 0x46, 0x57, 0x61, 0x87, + 0x11, 0xc9, 0xfb, 0xcd, 0x77, 0x34, 0x29, 0xb7, 0x02, 0x20, 0x06, 0x8d, + 0x41, 0x11, 0x47, 0x93, 0xcb, 0xad, 0xda, 0x5d, 0xe1, 0x9d, 0x49, 0x8d, + 0xe0, 0xab, 0x48, 0xe6, 0x18, 0x28, 0x4a, 0x94, 0xae, 0xf9, 0xad, 0xc5, + 0x5b, 0x0b, 0x15, 0xc6, 0x73, 0x17 +}; +unsigned int default_private_key_len = 318; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_config.h new file mode 100644 index 0000000000..4018671c88 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_config.h @@ -0,0 +1,88 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define ESP_PLATFORM 1 +#define LEWEI_PLATFORM 0 + +#define USE_OPTIMIZE_PRINTF + +#if ESP_PLATFORM +#define PLUG_DEVICE 0 +#define LIGHT_DEVICE 1 +#define SENSOR_DEVICE 0 + +#if SENSOR_DEVICE +#define HUMITURE_SUB_DEVICE 1 +#define FLAMMABLE_GAS_SUB_DEVICE 0 +#endif + +//#define SERVER_SSL_ENABLE +//#define CLIENT_SSL_ENABLE +//#define UPGRADE_SSL_ENABLE + +#define USE_DNS + +#ifdef USE_DNS +#define ESP_DOMAIN "iot.espressif.cn" +#endif + +//#define SOFTAP_ENCRYPT + +#ifdef SOFTAP_ENCRYPT +#define PASSWORD "v*%W>L<@i&Nxe!" +#endif + +#if SENSOR_DEVICE +#define SENSOR_DEEP_SLEEP + +#if HUMITURE_SUB_DEVICE +#define SENSOR_DEEP_SLEEP_TIME 30000000 +#elif FLAMMABLE_GAS_SUB_DEVICE +#define SENSOR_DEEP_SLEEP_TIME 60000000 +#endif +#endif + +#if LIGHT_DEVICE +#define USE_US_TIMER +#endif + +#if PLUG_DEVICE || LIGHT_DEVICE +#define BEACON_TIMEOUT 150000000 +#define BEACON_TIME 50000 +#endif + +#define AP_CACHE 1 + +#if AP_CACHE +#define AP_CACHE_NUMBER 5 +#endif + +#elif LEWEI_PLATFORM +#endif + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_devicefind.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_devicefind.h new file mode 100644 index 0000000000..352b1f997f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_devicefind.h @@ -0,0 +1,30 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_DEVICEFIND_H__ +#define __USER_DEVICEFIND_H__ + +void user_devicefind_init(void); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform.h new file mode 100644 index 0000000000..f3ae1b0d89 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform.h @@ -0,0 +1,57 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_DEVICE_H__ +#define __USER_DEVICE_H__ + +/* NOTICE---this is for 512KB spi flash. + * you can change to other sector if you use other size spi flash. */ +#define ESP_PARAM_START_SEC 0x3D + +#define packet_size (2 * 1024) + +#define token_size 41 + +struct esp_platform_saved_param { + uint8 devkey[40]; + uint8 token[40]; + uint8 activeflag; + uint8 pad[3]; +}; + +enum { + DEVICE_CONNECTING = 40, + DEVICE_ACTIVE_DONE, + DEVICE_ACTIVE_FAIL, + DEVICE_CONNECT_SERVER_FAIL +}; + +struct dhcp_client_info { + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; + uint8 flag; + uint8 pad[3]; +}; +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform_timer.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform_timer.h new file mode 100644 index 0000000000..52b17b7db4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_esp_platform_timer.h @@ -0,0 +1,30 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_DEVICEFIND_H__ +#define __USER_DEVICEFIND_H__ + +void user_platform_timer_start(char* pbuffer, struct espconn *pespconn); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_iot_version.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_iot_version.h new file mode 100644 index 0000000000..8ef646157e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_iot_version.h @@ -0,0 +1,67 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_IOT_VERSION_H__ +#define __USER_IOT_VERSION_H__ + +#include "user_config.h" + +#define IOT_VERSION_MAJOR 1U +#define IOT_VERSION_MINOR 0U +#define IOT_VERSION_REVISION 5U + +#define VERSION_NUM (IOT_VERSION_MAJOR * 1000 + IOT_VERSION_MINOR * 100 + IOT_VERSION_REVISION) + +//#define VERSION_TYPE "b" +#define VERSION_TYPE "v" + +#if LIGHT_DEVICE +#define device_type 45772 +#elif PLUG_DEVICE +#define device_type 23701 +#elif SENSOR_DEVICE +#define device_type 12335 +#endif + + +#define ONLINE_UPGRADE 0 +#define LOCAL_UPGRADE 0 +#define ALL_UPGRADE 1 +#define NONE_UPGRADE 0 + +#if ONLINE_UPGRADE +#define UPGRADE_FALG "O" +#elif LOCAL_UPGRADE +#define UPGRADE_FALG "l" +#elif ALL_UPGRADE +#define UPGRADE_FALG "a" +#elif NONE_UPGRADE +#define UPGRADE_FALG "n" +#endif + +#define IOT_VERSION + + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_json.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_json.h new file mode 100644 index 0000000000..61e84c59b5 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_json.h @@ -0,0 +1,41 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_JSON_H__ +#define __USER_JSON_H__ + +#include "json/jsonparse.h" +#include "json/jsontree.h" + +#define jsonSize 2*1024 + +void json_parse(struct jsontree_context *json, char *ptrJSONMessage); + +void json_ws_send(struct jsontree_value *tree, const char *path, char *pbuf); + +int json_putchar(int c); + +struct jsontree_value *find_json_path(struct jsontree_context *json, const char *path); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light.h new file mode 100644 index 0000000000..ed86b62725 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light.h @@ -0,0 +1,88 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_LIGHT_H__ +#define __USER_LIGHT_H__ +/*pwm.h: function and macro definition of PWM API , driver level */ +/*user_light.h: user interface for light API, user level*/ +/*user_light_adj: API for color changing and lighting effects, user level*/ + + +#include "pwm.h" + + +/* NOTICE !!! ---this is for 512KB spi flash.*/ +/* You can change to other sector if you use other size spi flash. */ +/* Refer to the documentation about OTA support and flash mapping*/ +#define PRIV_PARAM_START_SEC 0x3C +#define PRIV_PARAM_SAVE 0 + + + +/*Define the channel number of PWM*/ +/*In this demo, we can set 3 for 3 PWM channels: RED, GREEN, BLUE*/ +/*Or , we can choose 5 channels : RED,GREEN,BLUE,COLD-WHITE,WARM-WHITE*/ +#define PWM_CHANNEL 5 // 5:5channel ; 3:3channel + +#define LIGHT_RED 0 +#define LIGHT_GREEN 1 +#define LIGHT_BLUE 2 +#define LIGHT_COLD_WHITE 3 +#define LIGHT_WARM_WHITE 4 + + +/*Definition of GPIO PIN params, for GPIO initialization*/ +#define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U +#define PWM_0_OUT_IO_NUM 12 +#define PWM_0_OUT_IO_FUNC FUNC_GPIO12 + +#define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDO_U +#define PWM_1_OUT_IO_NUM 15 +#define PWM_1_OUT_IO_FUNC FUNC_GPIO15 + +#define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U +#define PWM_2_OUT_IO_NUM 13 +#define PWM_2_OUT_IO_FUNC FUNC_GPIO13 + +#define PWM_3_OUT_IO_MUX PERIPHS_IO_MUX_MTMS_U +#define PWM_3_OUT_IO_NUM 14 +#define PWM_3_OUT_IO_FUNC FUNC_GPIO14 + +#define PWM_4_OUT_IO_MUX PERIPHS_IO_MUX_GPIO5_U +#define PWM_4_OUT_IO_NUM 5 +#define PWM_4_OUT_IO_FUNC FUNC_GPIO5 + +struct light_saved_param { + uint32 pwm_period; + uint32 pwm_duty[PWM_CHANNEL]; +}; + +void user_light_init(void); +uint32 user_light_get_duty(uint8 channel); +void user_light_set_duty(uint32 duty, uint8 channel); +uint32 user_light_get_period(void); +void user_light_set_period(uint32 period); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light_adj.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light_adj.h new file mode 100644 index 0000000000..20ee8147d2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_light_adj.h @@ -0,0 +1,57 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_LIGHT_ADJ_H__ +#define __USER_LIGHT_ADJ_H__ +/*pwm.h: function and macro definition of PWM API , driver level */ +/*user_light.h: user interface for light setting, user level*/ +/*user_light_adj: API for color changing and lighting effects, user level*/ + + + + +/*save RGB params to flash when calling light_set_aim*/ +#define SAVE_LIGHT_PARAM 0 //set to 0: do not save color params + +/*check current consumption and limit the total current for LED driver IC*/ +/*NOTE: YOU SHOULD REPLACE WIHT THE LIMIT CURRENT OF YOUR OWN APPLICATION*/ +#define LIGHT_CURRENT_LIMIT 0 //set to 0: do not limit total current +#if LIGHT_CURRENT_LIMIT +#define LIGHT_TOTAL_CURRENT_MAX (450*1000) //450000/1000 MA AT MOST +#define LIGHT_CURRENT_MARGIN (80*1000) //80000/1000 MA CURRENT RAISES WHILE TEMPERATURE INCREASING +#define LIGHT_CURRENT_MARGIN_L2 (110*1000) //110000/1000 MA +#define LIGHT_CURRENT_MARGIN_L3 (140*1000) //140000/1000 MA +#endif + + +/*set target duty for PWM channels, change each channel duty gradually */ +void light_set_aim(uint32 r,uint32 g,uint32 b,uint32 cw,uint32 ww,uint32 period);//'white' channel is not used in default demo +void light_set_aim_r(uint32 r); +void light_set_aim_g(uint32 g); +void light_set_aim_b(uint32 b); +void light_set_aim_cw(uint32 cw); +void light_set_aim_ww(uint32 ww); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_plug.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_plug.h new file mode 100644 index 0000000000..3949bf3b92 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_plug.h @@ -0,0 +1,67 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_ESPSWITCH_H__ +#define __USER_ESPSWITCH_H__ + +#include "driver/key.h" + +/* NOTICE---this is for 512KB spi flash. + * you can change to other sector if you use other size spi flash. */ +#define PRIV_PARAM_START_SEC 0x3C + +#define PRIV_PARAM_SAVE 0 + +#define PLUG_KEY_NUM 1 + +#define PLUG_KEY_0_IO_MUX PERIPHS_IO_MUX_MTCK_U +#define PLUG_KEY_0_IO_NUM 13 +#define PLUG_KEY_0_IO_FUNC FUNC_GPIO13 + +#define PLUG_WIFI_LED_IO_MUX PERIPHS_IO_MUX_GPIO0_U +#define PLUG_WIFI_LED_IO_NUM 0 +#define PLUG_WIFI_LED_IO_FUNC FUNC_GPIO0 + +#define PLUG_LINK_LED_IO_MUX PERIPHS_IO_MUX_MTDI_U +#define PLUG_LINK_LED_IO_NUM 12 +#define PLUG_LINK_LED_IO_FUNC FUNC_GPIO12 + +#define PLUG_RELAY_LED_IO_MUX PERIPHS_IO_MUX_MTDO_U +#define PLUG_RELAY_LED_IO_NUM 15 +#define PLUG_RELAY_LED_IO_FUNC FUNC_GPIO15 + +#define PLUG_STATUS_OUTPUT(pin, on) GPIO_OUTPUT_SET(pin, on) + +struct plug_saved_param { + uint8_t status; + uint8_t pad[3]; +}; + +void user_plug_init(void); +uint8 user_plug_get_status(void); +void user_plug_set_status(bool status); + + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_sensor.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_sensor.h new file mode 100644 index 0000000000..150bc24cfa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_sensor.h @@ -0,0 +1,56 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_SENSOR_H__ +#define __USER_SENSOR_H__ + +#include "user_config.h" +#include "driver/key.h" + +#define SENSOR_KEY_NUM 1 + +#define SENSOR_KEY_IO_MUX PERIPHS_IO_MUX_MTCK_U +#define SENSOR_KEY_IO_NUM 13 +#define SENSOR_KEY_IO_FUNC FUNC_GPIO13 + +#define SENSOR_WIFI_LED_IO_MUX PERIPHS_IO_MUX_GPIO0_U +#define SENSOR_WIFI_LED_IO_NUM 0 +#define SENSOR_WIFI_LED_IO_FUNC FUNC_GPIO0 + +#define SENSOR_LINK_LED_IO_MUX PERIPHS_IO_MUX_MTDI_U +#define SENSOR_LINK_LED_IO_NUM 12 +#define SENSOR_LINK_LED_IO_FUNC FUNC_GPIO12 + +#define SENSOR_UNUSED_LED_IO_MUX PERIPHS_IO_MUX_MTDO_U +#define SENSOR_UNUSED_LED_IO_NUM 15 +#define SENSOR_UNUSED_LED_IO_FUNC FUNC_GPIO15 + +#if HUMITURE_SUB_DEVICE +bool user_mvh3004_read_th(uint8 *data); +void user_mvh3004_init(void); +#endif + +void user_sensor_init(uint8 active); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_webserver.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_webserver.h new file mode 100644 index 0000000000..978a6f73de --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/include/user_webserver.h @@ -0,0 +1,69 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_WEBSERVER_H__ +#define __USER_WEBSERVER_H__ + +#define SERVER_PORT 80 +#define SERVER_SSL_PORT 443 + +#define URLSize 10 + +typedef enum Result_Resp { + RespFail = 0, + RespSuc, +} Result_Resp; + +typedef enum ProtocolType { + GET = 0, + POST, +} ProtocolType; + +typedef enum _ParmType { + SWITCH_STATUS = 0, + INFOMATION, + WIFI, + SCAN, + REBOOT, + DEEP_SLEEP, + LIGHT_STATUS, + CONNECT_STATUS, + USER_BIN +} ParmType; + +typedef struct URL_Frame { + enum ProtocolType Type; + char pSelect[URLSize]; + char pCommand[URLSize]; + char pFilename[URLSize]; +} URL_Frame; + +typedef struct _rst_parm { + ParmType parmtype; + struct espconn *pespconn; +} rst_parm; + +void user_webserver_init(uint32 port); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_devicefind.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_devicefind.c new file mode 100644 index 0000000000..454ca06b1e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_devicefind.c @@ -0,0 +1,134 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" + +#include "espconn.h" +#include "user_json.h" +#include "user_devicefind.h" + +const char *device_find_request = "Are You Espressif IOT Smart Device?"; +#if PLUG_DEVICE +const char *device_find_response_ok = "I'm Plug."; +#elif LIGHT_DEVICE +const char *device_find_response_ok = "I'm Light."; +#elif SENSOR_DEVICE +#if HUMITURE_SUB_DEVICE +const char *device_find_response_ok = "I'm Humiture."; +#elif FLAMMABLE_GAS_SUB_DEVICE +const char *device_find_response_ok = "I'm Flammable Gas."; +#endif +#endif + +/*---------------------------------------------------------------------------*/ +LOCAL struct espconn ptrespconn; + +/****************************************************************************** + * FunctionName : user_devicefind_recv + * Description : Processing the received data from the host + * Parameters : arg -- Additional argument to pass to the callback function + * pusrdata -- The received data (or NULL when the connection has been closed!) + * length -- The length of received data + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_devicefind_recv(void *arg, char *pusrdata, unsigned short length) +{ + char DeviceBuffer[40] = {0}; + char Device_mac_buffer[60] = {0}; + char hwaddr[6]; + remot_info *premot = NULL; + struct ip_info ipconfig; + + if (wifi_get_opmode() != STATION_MODE) { + wifi_get_ip_info(SOFTAP_IF, &ipconfig); + wifi_get_macaddr(SOFTAP_IF, hwaddr); + + if (!ip_addr_netcmp((struct ip_addr *)ptrespconn.proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) { + wifi_get_ip_info(STATION_IF, &ipconfig); + wifi_get_macaddr(STATION_IF, hwaddr); + } + } else { + wifi_get_ip_info(STATION_IF, &ipconfig); + wifi_get_macaddr(STATION_IF, hwaddr); + } + + if (pusrdata == NULL) { + return; + } + + if (length == os_strlen(device_find_request) && + os_strncmp(pusrdata, device_find_request, os_strlen(device_find_request)) == 0) { + os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok, + MAC2STR(hwaddr), IP2STR(&ipconfig.ip)); + + os_printf("%s\n", DeviceBuffer); + length = os_strlen(DeviceBuffer); + if (espconn_get_connection_info(&ptrespconn, &premot, 0) != ESPCONN_OK) + return; + os_memcpy(ptrespconn.proto.udp->remote_ip, premot->remote_ip, 4); + ptrespconn.proto.udp->remote_port = premot->remote_port; + espconn_sent(&ptrespconn, DeviceBuffer, length); + } else if (length == (os_strlen(device_find_request) + 18)) { + os_sprintf(Device_mac_buffer, "%s " MACSTR , device_find_request, MAC2STR(hwaddr)); + os_printf("%s", Device_mac_buffer); + + if (os_strncmp(Device_mac_buffer, pusrdata, os_strlen(device_find_request) + 18) == 0) { + //os_printf("%s\n", Device_mac_buffer); + length = os_strlen(DeviceBuffer); + os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok, + MAC2STR(hwaddr), IP2STR(&ipconfig.ip)); + + os_printf("%s\n", DeviceBuffer); + length = os_strlen(DeviceBuffer); + if (espconn_get_connection_info(&ptrespconn, &premot, 0) != ESPCONN_OK) + return; + os_memcpy(ptrespconn.proto.udp->remote_ip, premot->remote_ip, 4); + ptrespconn.proto.udp->remote_port = premot->remote_port; + espconn_sent(&ptrespconn, DeviceBuffer, length); + } else { + return; + } + } +} + +/****************************************************************************** + * FunctionName : user_devicefind_init + * Description : the espconn struct parame init + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_devicefind_init(void) +{ + ptrespconn.type = ESPCONN_UDP; + ptrespconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); + ptrespconn.proto.udp->local_port = 1025; + espconn_regist_recvcb(&ptrespconn, user_devicefind_recv); + espconn_create(&ptrespconn); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform.c new file mode 100644 index 0000000000..d910e10491 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform.c @@ -0,0 +1,1396 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "mem.h" +#include "osapi.h" +#include "user_interface.h" + +#include "espconn.h" +#include "user_esp_platform.h" +#include "user_iot_version.h" +#include "upgrade.h" + +#if ESP_PLATFORM + +#define ESP_DEBUG + +#ifdef ESP_DEBUG +#define ESP_DBG os_printf +#else +#define ESP_DBG +#endif + +#define ACTIVE_FRAME "{\"nonce\": %d,\"path\": \"/v1/device/activate/\", \"method\": \"POST\", \"body\": {\"encrypt_method\": \"PLAIN\", \"token\": \"%s\", \"bssid\": \""MACSTR"\",\"rom_version\":\"%s\"}, \"meta\": {\"Authorization\": \"token %s\"}}\n" + +#if PLUG_DEVICE +#include "user_plug.h" + +#define RESPONSE_FRAME "{\"status\": 200, \"datapoint\": {\"x\": %d}, \"nonce\": %d, \"deliver_to_device\": true}\n" +#define FIRST_FRAME "{\"nonce\": %d, \"path\": \"/v1/device/identify\", \"method\": \"GET\",\"meta\": {\"Authorization\": \"token %s\"}}\n" + +#elif LIGHT_DEVICE +#include "user_light.h" + +#define RESPONSE_FRAME "{\"status\": 200,\"nonce\": %d, \"datapoint\": {\"x\": %d,\"y\": %d,\"z\": %d,\"k\": %d,\"l\": %d},\"deliver_to_device\":true}\n" +#define FIRST_FRAME "{\"nonce\": %d, \"path\": \"/v1/device/identify\", \"method\": \"GET\",\"meta\": {\"Authorization\": \"token %s\"}}\n" + +#elif SENSOR_DEVICE +#include "user_sensor.h" + +#if HUMITURE_SUB_DEVICE +#define UPLOAD_FRAME "{\"nonce\": %d, \"path\": \"/v1/datastreams/tem_hum/datapoint/\", \"method\": \"POST\", \ +\"body\": {\"datapoint\": {\"x\": %s%d.%02d,\"y\": %d.%02d}}, \"meta\": {\"Authorization\": \"token %s\"}}\n" +#elif FLAMMABLE_GAS_SUB_DEVICE +#define UPLOAD_FRAME "{\"nonce\": %d, \"path\": \"/v1/datastreams/flammable_gas/datapoint/\", \"method\": \"POST\", \ +\"body\": {\"datapoint\": {\"x\": %d.%03d}}, \"meta\": {\"Authorization\": \"token %s\"}}\n" +#endif + +LOCAL uint32 count = 0; +#endif + +#define UPGRADE_FRAME "{\"path\": \"/v1/messages/\", \"method\": \"POST\", \"meta\": {\"Authorization\": \"token %s\"},\ +\"get\":{\"action\":\"%s\"},\"body\":{\"pre_rom_version\":\"%s\",\"rom_version\":\"%s\"}}\n" + +#if PLUG_DEVICE || LIGHT_DEVICE +#define BEACON_FRAME "{\"path\": \"/v1/ping/\", \"method\": \"POST\",\"meta\": {\"Authorization\": \"token %s\"}}\n" +#define RPC_RESPONSE_FRAME "{\"status\": 200, \"nonce\": %d, \"deliver_to_device\": true}\n" +#define TIMER_FRAME "{\"body\": {}, \"get\":{\"is_humanize_format_simple\":\"true\"},\"meta\": {\"Authorization\": \"Token %s\"},\"path\": \"/v1/device/timers/\",\"post\":{},\"method\": \"GET\"}\n" +#define pheadbuffer "Connection: keep-alive\r\n\ +Cache-Control: no-cache\r\n\ +User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 \r\n\ +Accept: */*\r\n\ +Authorization: token %s\r\n\ +Accept-Encoding: gzip,deflate,sdch\r\n\ +Accept-Language: zh-CN,zh;q=0.8\r\n\r\n" + +LOCAL uint8 ping_status; +LOCAL os_timer_t beacon_timer; +#endif + +#ifdef USE_DNS +ip_addr_t esp_server_ip; +#endif + +LOCAL struct espconn user_conn; +LOCAL struct _esp_tcp user_tcp; +LOCAL os_timer_t client_timer; + struct esp_platform_saved_param esp_param; +LOCAL uint8 device_status; +LOCAL uint8 device_recon_count = 0; +LOCAL uint32 active_nonce = 0; +LOCAL uint8 iot_version[20] = {0}; +struct rst_info rtc_info; +void user_esp_platform_check_ip(uint8 reset_flag); + +/****************************************************************************** + * FunctionName : user_esp_platform_get_token + * Description : get the espressif's device token + * Parameters : token -- the parame point which write the flash + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_get_token(uint8_t *token) +{ + if (token == NULL) { + return; + } + + os_memcpy(token, esp_param.token, sizeof(esp_param.token)); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_set_token + * Description : save the token for the espressif's device + * Parameters : token -- the parame point which write the flash + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_set_token(uint8_t *token) +{ + if (token == NULL) { + return; + } + + esp_param.activeflag = 0; + os_memcpy(esp_param.token, token, os_strlen(token)); + + system_param_save_with_protect(ESP_PARAM_START_SEC, &esp_param, sizeof(esp_param)); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_set_active + * Description : set active flag + * Parameters : activeflag -- 0 or 1 + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_set_active(uint8 activeflag) +{ + esp_param.activeflag = activeflag; + + system_param_save_with_protect(ESP_PARAM_START_SEC, &esp_param, sizeof(esp_param)); +} + +void ICACHE_FLASH_ATTR +user_esp_platform_set_connect_status(uint8 status) +{ + device_status = status; +} + +/****************************************************************************** + * FunctionName : user_esp_platform_get_connect_status + * Description : get each connection step's status + * Parameters : none + * Returns : status +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +user_esp_platform_get_connect_status(void) +{ + uint8 status = wifi_station_get_connect_status(); + + if (status == STATION_GOT_IP) { + status = (device_status == 0) ? DEVICE_CONNECTING : device_status; + } + + ESP_DBG("status %d\n", status); + return status; +} + +/****************************************************************************** + * FunctionName : user_esp_platform_parse_nonce + * Description : parse the device nonce + * Parameters : pbuffer -- the recivce data point + * Returns : the nonce +*******************************************************************************/ +int ICACHE_FLASH_ATTR +user_esp_platform_parse_nonce(char *pbuffer) +{ + char *pstr = NULL; + char *pparse = NULL; + char noncestr[11] = {0}; + int nonce = 0; + pstr = (char *)os_strstr(pbuffer, "\"nonce\": "); + + if (pstr != NULL) { + pstr += 9; + pparse = (char *)os_strstr(pstr, ","); + + if (pparse != NULL) { + os_memcpy(noncestr, pstr, pparse - pstr); + } else { + pparse = (char *)os_strstr(pstr, "}"); + + if (pparse != NULL) { + os_memcpy(noncestr, pstr, pparse - pstr); + } else { + pparse = (char *)os_strstr(pstr, "]"); + + if (pparse != NULL) { + os_memcpy(noncestr, pstr, pparse - pstr); + } else { + return 0; + } + } + } + + nonce = atoi(noncestr); + } + + return nonce; +} + +/****************************************************************************** + * FunctionName : user_esp_platform_get_info + * Description : get and update the espressif's device status + * Parameters : pespconn -- the espconn used to connect with host + * pbuffer -- prossing the data point + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_get_info(struct espconn *pconn, uint8 *pbuffer) +{ + char *pbuf = NULL; + int nonce = 0; + + pbuf = (char *)os_zalloc(packet_size); + + nonce = user_esp_platform_parse_nonce(pbuffer); + + if (pbuf != NULL) { +#if PLUG_DEVICE + os_sprintf(pbuf, RESPONSE_FRAME, user_plug_get_status(), nonce); +#elif LIGHT_DEVICE + uint32 white_val; + white_val = (PWM_CHANNEL>LIGHT_COLD_WHITE?user_light_get_duty(LIGHT_COLD_WHITE):0); + os_sprintf(pbuf, RESPONSE_FRAME, nonce, user_light_get_period(), + user_light_get_duty(LIGHT_RED), user_light_get_duty(LIGHT_GREEN), + user_light_get_duty(LIGHT_BLUE),white_val );//50); +#endif + + ESP_DBG("%s\n", pbuf); +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pconn, pbuf, os_strlen(pbuf)); +#endif + os_free(pbuf); + pbuf = NULL; + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_set_info + * Description : prossing the data and controling the espressif's device + * Parameters : pespconn -- the espconn used to connect with host + * pbuffer -- prossing the data point + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_set_info(struct espconn *pconn, uint8 *pbuffer) +{ +#if PLUG_DEVICE + char *pstr = NULL; + pstr = (char *)os_strstr(pbuffer, "plug-status"); + + if (pstr != NULL) { + pstr = (char *)os_strstr(pbuffer, "body"); + + if (pstr != NULL) { + + if (os_strncmp(pstr + 27, "1", 1) == 0) { + user_plug_set_status(0x01); + } else if (os_strncmp(pstr + 27, "0", 1) == 0) { + user_plug_set_status(0x00); + } + } + } + +#elif LIGHT_DEVICE + char *pstr = NULL; + char *pdata = NULL; + char *pbuf = NULL; + char recvbuf[10]; + uint16 length = 0; + uint32 data = 0; + static uint32 rr,gg,bb,cw,ww,period; + ww=0; + cw=0; + extern uint8 light_sleep_flg; + pstr = (char *)os_strstr(pbuffer, "\"path\": \"/v1/datastreams/light/datapoint/\""); + + if (pstr != NULL) { + pstr = (char *)os_strstr(pbuffer, "{\"datapoint\": "); + + if (pstr != NULL) { + pbuf = (char *)os_strstr(pbuffer, "}}"); + length = pbuf - pstr; + length += 2; + pdata = (char *)os_zalloc(length + 1); + os_memcpy(pdata, pstr, length); + + pstr = (char *)os_strchr(pdata, 'x'); + + if (pstr != NULL) { + pstr += 4; + pbuf = (char *)os_strchr(pstr, ','); + + if (pbuf != NULL) { + length = pbuf - pstr; + os_memset(recvbuf, 0, 10); + os_memcpy(recvbuf, pstr, length); + data = atoi(recvbuf); + period = data; + //user_light_set_period(data); + } + } + + pstr = (char *)os_strchr(pdata, 'y'); + + if (pstr != NULL) { + pstr += 4; + pbuf = (char *)os_strchr(pstr, ','); + + if (pbuf != NULL) { + length = pbuf - pstr; + os_memset(recvbuf, 0, 10); + os_memcpy(recvbuf, pstr, length); + data = atoi(recvbuf); + rr=data; + os_printf("r: %d\r\n",rr); + //user_light_set_duty(data, 0); + } + } + + pstr = (char *)os_strchr(pdata, 'z'); + + if (pstr != NULL) { + pstr += 4; + pbuf = (char *)os_strchr(pstr, ','); + + if (pbuf != NULL) { + length = pbuf - pstr; + os_memset(recvbuf, 0, 10); + os_memcpy(recvbuf, pstr, length); + data = atoi(recvbuf); + gg=data; + os_printf("g: %d\r\n",gg); + //user_light_set_duty(data, 1); + } + } + + pstr = (char *)os_strchr(pdata, 'k'); + + if (pstr != NULL) { + pstr += 4;; + pbuf = (char *)os_strchr(pstr, ','); + + if (pbuf != NULL) { + length = pbuf - pstr; + os_memset(recvbuf, 0, 10); + os_memcpy(recvbuf, pstr, length); + data = atoi(recvbuf); + bb=data; + os_printf("b: %d\r\n",bb); + //user_light_set_duty(data, 2); + } + } + + pstr = (char *)os_strchr(pdata, 'l'); + + if (pstr != NULL) { + pstr += 4;; + pbuf = (char *)os_strchr(pstr, ','); + + if (pbuf != NULL) { + length = pbuf - pstr; + os_memset(recvbuf, 0, 10); + os_memcpy(recvbuf, pstr, length); + data = atoi(recvbuf); + cw=data; + ww=data; + os_printf("cw: %d\r\n",cw); + os_printf("ww:%d\r\n",ww); //chg + //user_light_set_duty(data, 2); + } + } + + os_free(pdata); + } + } + + if((rr|gg|bb|cw|ww) == 0){ + if(light_sleep_flg==0){ + + } + + }else{ + if(light_sleep_flg==1){ + os_printf("modem sleep en\r\n"); + wifi_set_sleep_type(MODEM_SLEEP_T); + light_sleep_flg =0; + } + } + + light_set_aim(rr,gg,bb,cw,ww,period); + //user_light_restart(); + +#endif + + user_esp_platform_get_info(pconn, pbuffer); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_reconnect + * Description : reconnect with host after get ip + * Parameters : pespconn -- the espconn used to reconnect with host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_reconnect(struct espconn *pespconn) +{ + ESP_DBG("user_esp_platform_reconnect\n"); + + user_esp_platform_check_ip(0); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_discon_cb + * Description : disconnect successfully with the host + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_discon_cb(void *arg) +{ + struct espconn *pespconn = arg; + struct ip_info ipconfig; + struct dhcp_client_info dhcp_info; + ESP_DBG("user_esp_platform_discon_cb\n"); + +#if (PLUG_DEVICE || LIGHT_DEVICE) + os_timer_disarm(&beacon_timer); +#endif + + if (pespconn == NULL) { + return; + } + + pespconn->proto.tcp->local_port = espconn_port(); + +#if (PLUG_DEVICE || SENSOR_DEVICE) + user_link_led_output(1); +#endif + +#if SENSOR_DEVICE +#ifdef SENSOR_DEEP_SLEEP + + if (wifi_get_opmode() == STATION_MODE) { + /***add by tzx for saving ip_info to avoid dhcp_client start****/ + wifi_get_ip_info(STATION_IF, &ipconfig); + + dhcp_info.ip_addr = ipconfig.ip; + dhcp_info.netmask = ipconfig.netmask; + dhcp_info.gw = ipconfig.gw ; + dhcp_info.flag = 0x01; + os_printf("dhcp_info.ip_addr = %d\n",dhcp_info.ip_addr); + system_rtc_mem_write(64,&dhcp_info,sizeof(struct dhcp_client_info)); + user_sensor_deep_sleep_enter(); + } else { + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn); + os_timer_arm(&client_timer, SENSOR_DEEP_SLEEP_TIME / 1000, 0); + } + +#else + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn); + os_timer_arm(&client_timer, 1000, 0); +#endif +#else + user_esp_platform_reconnect(pespconn); +#endif +} + +/****************************************************************************** + * FunctionName : user_esp_platform_discon + * Description : A new incoming connection has been disconnected. + * Parameters : espconn -- the espconn used to disconnect with host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_discon(struct espconn *pespconn) +{ + ESP_DBG("user_esp_platform_discon\n"); + +#if (PLUG_DEVICE || SENSOR_DEVICE) + user_link_led_output(1); +#endif + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_disconnect(pespconn); +#else + espconn_disconnect(pespconn); +#endif +} + +/****************************************************************************** + * FunctionName : user_esp_platform_sent_cb + * Description : Data has been sent successfully and acknowledged by the remote host. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_sent_cb(void *arg) +{ + struct espconn *pespconn = arg; + + ESP_DBG("user_esp_platform_sent_cb\n"); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_sent + * Description : Processing the application data and sending it to the host + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_sent(struct espconn *pespconn) +{ + uint8 devkey[token_size] = {0}; + uint32 nonce; + char *pbuf = (char *)os_zalloc(packet_size); + + os_memcpy(devkey, esp_param.devkey, 40); + + if (esp_param.activeflag == 0xFF) { + esp_param.activeflag = 0; + } + + if (pbuf != NULL) { + if (esp_param.activeflag == 0) { + uint8 token[token_size] = {0}; + uint8 bssid[6]; + active_nonce = os_random() & 0x7FFFFFFF; + + os_memcpy(token, esp_param.token, 40); + + wifi_get_macaddr(STATION_IF, bssid); + + os_sprintf(pbuf, ACTIVE_FRAME, active_nonce, token, MAC2STR(bssid),iot_version, devkey); + } + +#if SENSOR_DEVICE +#if HUMITURE_SUB_DEVICE + else { +#if 0 + uint16 tp, rh; + uint8 data[4]; + + if (user_mvh3004_read_th(data)) { + rh = data[0] << 8 | data[1]; + tp = data[2] << 8 | data[3]; + } + +#else + uint16 tp, rh; + uint8 *data; + uint32 tp_t, rh_t; + data = (uint8 *)user_mvh3004_get_poweron_th(); + + rh = data[0] << 8 | data[1]; + tp = data[2] << 8 | data[3]; +#endif + tp_t = (tp >> 2) * 165 * 100 / (16384 - 1); + rh_t = (rh & 0x3fff) * 100 * 100 / (16384 - 1); + + if (tp_t >= 4000) { + os_sprintf(pbuf, UPLOAD_FRAME, count, "", tp_t / 100 - 40, tp_t % 100, rh_t / 100, rh_t % 100, devkey); + } else { + tp_t = 4000 - tp_t; + os_sprintf(pbuf, UPLOAD_FRAME, count, "-", tp_t / 100, tp_t % 100, rh_t / 100, rh_t % 100, devkey); + } + } + +#elif FLAMMABLE_GAS_SUB_DEVICE + else { + uint32 adc_value = system_adc_read(); + + os_sprintf(pbuf, UPLOAD_FRAME, count, adc_value / 1024, adc_value * 1000 / 1024, devkey); + } + +#endif +#else + else { + nonce = os_random() & 0x7FFFFFFF; + os_sprintf(pbuf, FIRST_FRAME, nonce , devkey); + } + +#endif + ESP_DBG("%s\n", pbuf); + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + + os_free(pbuf); + } +} + +#if PLUG_DEVICE || LIGHT_DEVICE +/****************************************************************************** + * FunctionName : user_esp_platform_sent_beacon + * Description : sent beacon frame for connection with the host is activate + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_sent_beacon(struct espconn *pespconn) +{ + if (pespconn == NULL) { + return; + } + + if (pespconn->state == ESPCONN_CONNECT) { + if (esp_param.activeflag == 0) { + ESP_DBG("please check device is activated.\n"); + user_esp_platform_sent(pespconn); + } else { + uint8 devkey[token_size] = {0}; + os_memcpy(devkey, esp_param.devkey, 40); + + ESP_DBG("user_esp_platform_sent_beacon %u\n", system_get_time()); + + if (ping_status == 0) { + ESP_DBG("user_esp_platform_sent_beacon sent fail!\n"); + user_esp_platform_discon(pespconn); + } else { + char *pbuf = (char *)os_zalloc(packet_size); + + if (pbuf != NULL) { + os_sprintf(pbuf, BEACON_FRAME, devkey); + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + + ping_status = 0; + os_timer_arm(&beacon_timer, BEACON_TIME, 0); + os_free(pbuf); + } + } + } + } else { + ESP_DBG("user_esp_platform_sent_beacon sent fail!\n"); + user_esp_platform_discon(pespconn); + } +} + +/****************************************************************************** + * FunctionName : user_platform_rpc_set_rsp + * Description : response the message to server to show setting info is received + * Parameters : pespconn -- the espconn used to connetion with the host + * nonce -- mark the message received from server + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_platform_rpc_set_rsp(struct espconn *pespconn, int nonce) +{ + char *pbuf = (char *)os_zalloc(packet_size); + + if (pespconn == NULL) { + return; + } + + os_sprintf(pbuf, RPC_RESPONSE_FRAME, nonce); + ESP_DBG("%s\n", pbuf); +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + os_free(pbuf); +} + +/****************************************************************************** + * FunctionName : user_platform_timer_get + * Description : get the timers from server + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_platform_timer_get(struct espconn *pespconn) +{ + uint8 devkey[token_size] = {0}; + char *pbuf = (char *)os_zalloc(packet_size); + os_memcpy(devkey, esp_param.devkey, 40); + + if (pespconn == NULL) { + return; + } + + os_sprintf(pbuf, TIMER_FRAME, devkey); + ESP_DBG("%s\n", pbuf); +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + os_free(pbuf); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_upgrade_cb + * Description : Processing the downloaded data from the server + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_upgrade_rsp(void *arg) +{ + struct upgrade_server_info *server = arg; + struct espconn *pespconn = server->pespconn; + uint8 devkey[41] = {0}; + uint8 *pbuf = NULL; + char *action = NULL; + + os_memcpy(devkey, esp_param.devkey, 40); + pbuf = (char *)os_zalloc(packet_size); + + if (server->upgrade_flag == true) { + ESP_DBG("user_esp_platform_upgarde_successfully\n"); + action = "device_upgrade_success"; + os_sprintf(pbuf, UPGRADE_FRAME, devkey, action, server->pre_version, server->upgrade_version); + ESP_DBG("%s\n",pbuf); + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + + if (pbuf != NULL) { + os_free(pbuf); + pbuf = NULL; + } + } else { + ESP_DBG("user_esp_platform_upgrade_failed\n"); + action = "device_upgrade_failed"; + os_sprintf(pbuf, UPGRADE_FRAME, devkey, action,server->pre_version, server->upgrade_version); + ESP_DBG("%s\n",pbuf); + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf)); +#else + espconn_sent(pespconn, pbuf, os_strlen(pbuf)); +#endif + + if (pbuf != NULL) { + os_free(pbuf); + pbuf = NULL; + } + } + + os_free(server->url); + server->url = NULL; + os_free(server); + server = NULL; +} + +/****************************************************************************** + * FunctionName : user_esp_platform_upgrade_begin + * Description : Processing the received data from the server + * Parameters : pespconn -- the espconn used to connetion with the host + * server -- upgrade param + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_upgrade_begin(struct espconn *pespconn, struct upgrade_server_info *server) +{ + uint8 user_bin[9] = {0}; + uint8 devkey[41] = {0}; + + server->pespconn = pespconn; + + os_memcpy(devkey, esp_param.devkey, 40); + os_memcpy(server->ip, pespconn->proto.tcp->remote_ip, 4); + +#ifdef UPGRADE_SSL_ENABLE + server->port = 443; +#else + server->port = 80; +#endif + + server->check_cb = user_esp_platform_upgrade_rsp; + server->check_times = 120000; + + if (server->url == NULL) { + server->url = (uint8 *)os_zalloc(512); + } + + if (system_upgrade_userbin_check() == UPGRADE_FW_BIN1) { + os_memcpy(user_bin, "user2.bin", 10); + } else if (system_upgrade_userbin_check() == UPGRADE_FW_BIN2) { + os_memcpy(user_bin, "user1.bin", 10); + } + + os_sprintf(server->url, "GET /v1/device/rom/?action=download_rom&version=%s&filename=%s HTTP/1.0\r\nHost: "IPSTR":%d\r\n"pheadbuffer"", + server->upgrade_version, user_bin, IP2STR(server->ip), + server->port, devkey); + ESP_DBG("%s\n",server->url); + +#ifdef UPGRADE_SSL_ENABLE + + if (system_upgrade_start_ssl(server) == false) { +#else + + if (system_upgrade_start(server) == false) { +#endif + ESP_DBG("upgrade is already started\n"); + } +} +#endif + +/****************************************************************************** + * FunctionName : user_esp_platform_recv_cb + * Description : Processing the received data from the server + * Parameters : arg -- Additional argument to pass to the callback function + * pusrdata -- The received data (or NULL when the connection has been closed!) + * length -- The length of received data + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_recv_cb(void *arg, char *pusrdata, unsigned short length) +{ + char *pstr = NULL; + LOCAL char pbuffer[1024 * 2] = {0}; + struct espconn *pespconn = arg; + + ESP_DBG("user_esp_platform_recv_cb %s\n", pusrdata); + +#if (PLUG_DEVICE || LIGHT_DEVICE) + os_timer_disarm(&beacon_timer); +#endif + + if (length == 1460) { + os_memcpy(pbuffer, pusrdata, length); + } else { + struct espconn *pespconn = (struct espconn *)arg; + + os_memcpy(pbuffer + os_strlen(pbuffer), pusrdata, length); + + if ((pstr = (char *)os_strstr(pbuffer, "\"activate_status\": ")) != NULL && + user_esp_platform_parse_nonce(pbuffer) == active_nonce) { + if (os_strncmp(pstr + 19, "1", 1) == 0) { + ESP_DBG("device activates successful.\n"); + + device_status = DEVICE_ACTIVE_DONE; + esp_param.activeflag = 1; + system_param_save_with_protect(ESP_PARAM_START_SEC, &esp_param, sizeof(esp_param)); + user_esp_platform_sent(pespconn); + if(LIGHT_DEVICE){ + system_restart(); + } + } else { + ESP_DBG("device activates failed.\n"); + device_status = DEVICE_ACTIVE_FAIL; + } + } + +#if (PLUG_DEVICE || LIGHT_DEVICE) + else if ((pstr = (char *)os_strstr(pbuffer, "\"action\": \"sys_upgrade\"")) != NULL) { + if ((pstr = (char *)os_strstr(pbuffer, "\"version\":")) != NULL) { + struct upgrade_server_info *server = NULL; + int nonce = user_esp_platform_parse_nonce(pbuffer); + user_platform_rpc_set_rsp(pespconn, nonce); + + server = (struct upgrade_server_info *)os_zalloc(sizeof(struct upgrade_server_info)); + os_memcpy(server->upgrade_version, pstr + 12, 16); + server->upgrade_version[15] = '\0'; + os_sprintf(server->pre_version,"%s%d.%d.%dt%d(%s)",VERSION_TYPE,IOT_VERSION_MAJOR,\ + IOT_VERSION_MINOR,IOT_VERSION_REVISION,device_type,UPGRADE_FALG); + user_esp_platform_upgrade_begin(pespconn, server); + } + } else if ((pstr = (char *)os_strstr(pbuffer, "\"action\": \"sys_reboot\"")) != NULL) { + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)system_upgrade_reboot, NULL); + os_timer_arm(&client_timer, 1000, 0); + } else if ((pstr = (char *)os_strstr(pbuffer, "/v1/device/timers/")) != NULL) { + int nonce = user_esp_platform_parse_nonce(pbuffer); + user_platform_rpc_set_rsp(pespconn, nonce); + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_platform_timer_get, pespconn); + os_timer_arm(&client_timer, 2000, 0); + } else if ((pstr = (char *)os_strstr(pbuffer, "\"method\": ")) != NULL) { + if (os_strncmp(pstr + 11, "GET", 3) == 0) { + user_esp_platform_get_info(pespconn, pbuffer); + } else if (os_strncmp(pstr + 11, "POST", 4) == 0) { + user_esp_platform_set_info(pespconn, pbuffer); + } + } else if ((pstr = (char *)os_strstr(pbuffer, "ping success")) != NULL) { + ESP_DBG("ping success\n"); + ping_status = 1; + } else if ((pstr = (char *)os_strstr(pbuffer, "send message success")) != NULL) { + } else if ((pstr = (char *)os_strstr(pbuffer, "timers")) != NULL) { + user_platform_timer_start(pusrdata , pespconn); + } + +#elif SENSOR_DEVICE + else if ((pstr = (char *)os_strstr(pbuffer, "\"status\":")) != NULL) { + if (os_strncmp(pstr + 10, "200", 3) != 0) { + ESP_DBG("message upload failed.\n"); + } else { + count++; + ESP_DBG("message upload sucessful.\n"); + } + + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_discon, pespconn); + os_timer_arm(&client_timer, 10, 0); + } + +#endif + else if ((pstr = (char *)os_strstr(pbuffer, "device")) != NULL) { +#if PLUG_DEVICE || LIGHT_DEVICE + user_platform_timer_get(pespconn); +#elif SENSOR_DEVICE + +#endif + } + + os_memset(pbuffer, 0, sizeof(pbuffer)); + } + +#if (PLUG_DEVICE || LIGHT_DEVICE) + os_timer_arm(&beacon_timer, BEACON_TIME, 0); +#endif +} + +#if AP_CACHE +/****************************************************************************** + * FunctionName : user_esp_platform_ap_change + * Description : add the user interface for changing to next ap ID. + * Parameters : + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_ap_change(void) +{ + uint8 current_id; + uint8 i = 0; + ESP_DBG("user_esp_platform_ap_is_changing\n"); + + current_id = wifi_station_get_current_ap_id(); + ESP_DBG("current ap id =%d\n", current_id); + + if (current_id == AP_CACHE_NUMBER - 1) { + i = 0; + } else { + i = current_id + 1; + } + while (wifi_station_ap_change(i) != true) { + i++; + if (i == AP_CACHE_NUMBER - 1) { + i = 0; + } + } + + /* just need to re-check ip while change AP */ + device_recon_count = 0; + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL); + os_timer_arm(&client_timer, 100, 0); +} +#endif + +LOCAL bool ICACHE_FLASH_ATTR +user_esp_platform_reset_mode(void) +{ + if (wifi_get_opmode() == STATION_MODE) { + wifi_set_opmode(STATIONAP_MODE); + } + +#if AP_CACHE + /* delay 5s to change AP */ + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_ap_change, NULL); + os_timer_arm(&client_timer, 5000, 0); + + return true; +#endif + + return false; +} + +/****************************************************************************** + * FunctionName : user_esp_platform_recon_cb + * Description : The connection had an error and is already deallocated. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_recon_cb(void *arg, sint8 err) +{ + struct espconn *pespconn = (struct espconn *)arg; + + ESP_DBG("user_esp_platform_recon_cb\n"); + +#if (PLUG_DEVICE || LIGHT_DEVICE) + os_timer_disarm(&beacon_timer); +#endif + +#if (PLUG_DEVICE || SENSOR_DEVICE) + user_link_led_output(1); +#endif + + if (++device_recon_count == 5) { + device_status = DEVICE_CONNECT_SERVER_FAIL; + + if (user_esp_platform_reset_mode()) { + return; + } + } + +#if SENSOR_DEVICE +#ifdef SENSOR_DEEP_SLEEP + + if (wifi_get_opmode() == STATION_MODE) { + user_esp_platform_reset_mode(); + + //user_sensor_deep_sleep_enter(); + } else { + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn); + os_timer_arm(&client_timer, 1000, 0); + } + +#else + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn); + os_timer_arm(&client_timer, 1000, 0); +#endif +#else + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_reconnect, pespconn); + os_timer_arm(&client_timer, 1000, 0); +#endif +} + +/****************************************************************************** + * FunctionName : user_esp_platform_connect_cb + * Description : A new incoming connection has been connected. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_connect_cb(void *arg) +{ + struct espconn *pespconn = arg; + + ESP_DBG("user_esp_platform_connect_cb\n"); + if (wifi_get_opmode() == STATIONAP_MODE ) { + wifi_set_opmode(STATION_MODE); + } + +#if (PLUG_DEVICE || SENSOR_DEVICE) + user_link_led_timer_done(); +#endif + device_recon_count = 0; + espconn_regist_recvcb(pespconn, user_esp_platform_recv_cb); + espconn_regist_sentcb(pespconn, user_esp_platform_sent_cb); + user_esp_platform_sent(pespconn); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_connect + * Description : The function given as the connect with the host + * Parameters : espconn -- the espconn used to connect the connection + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_connect(struct espconn *pespconn) +{ + ESP_DBG("user_esp_platform_connect\n"); + +#ifdef CLIENT_SSL_ENABLE + espconn_secure_connect(pespconn); +#else + espconn_connect(pespconn); +#endif +} + +#ifdef USE_DNS +/****************************************************************************** + * FunctionName : user_esp_platform_dns_found + * Description : dns found callback + * Parameters : name -- pointer to the name that was looked up. + * ipaddr -- pointer to an ip_addr_t containing the IP address of + * the hostname, or NULL if the name could not be found (or on any + * other error). + * callback_arg -- a user-specified callback argument passed to + * dns_gethostbyname + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + + if (ipaddr == NULL) { + ESP_DBG("user_esp_platform_dns_found NULL\n"); + + if (++device_recon_count == 5) { + device_status = DEVICE_CONNECT_SERVER_FAIL; + + user_esp_platform_reset_mode(); + } + + return; + } + + ESP_DBG("user_esp_platform_dns_found %d.%d.%d.%d\n", + *((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1), + *((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3)); + + if (esp_server_ip.addr == 0 && ipaddr->addr != 0) { + os_timer_disarm(&client_timer); + esp_server_ip.addr = ipaddr->addr; + os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr, 4); + + pespconn->proto.tcp->local_port = espconn_port(); + +#ifdef CLIENT_SSL_ENABLE + pespconn->proto.tcp->remote_port = 8443; +#else + pespconn->proto.tcp->remote_port = 8000; +#endif + +#if (PLUG_DEVICE || LIGHT_DEVICE) + ping_status = 1; +#endif + + espconn_regist_connectcb(pespconn, user_esp_platform_connect_cb); + espconn_regist_disconcb(pespconn, user_esp_platform_discon_cb); + espconn_regist_reconcb(pespconn, user_esp_platform_recon_cb); + user_esp_platform_connect(pespconn); + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_dns_check_cb + * Description : 1s time callback to check dns found + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_dns_check_cb(void *arg) +{ + struct espconn *pespconn = arg; + + ESP_DBG("user_esp_platform_dns_check_cb\n"); + + espconn_gethostbyname(pespconn, ESP_DOMAIN, &esp_server_ip, user_esp_platform_dns_found); + + os_timer_arm(&client_timer, 1000, 0); +} + +LOCAL void ICACHE_FLASH_ATTR +user_esp_platform_start_dns(struct espconn *pespconn) +{ + esp_server_ip.addr = 0; + espconn_gethostbyname(pespconn, ESP_DOMAIN, &esp_server_ip, user_esp_platform_dns_found); + + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_dns_check_cb, pespconn); + os_timer_arm(&client_timer, 1000, 0); +} +#endif + + +#if LIGHT_DEVICE +void user_mdns_conf() +{ + +struct ip_info ipconfig; +wifi_get_ip_info(STATION_IF, &ipconfig); + +struct mdns_info *info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); +info->host_name = "espressif_light_demo"; +info->ipAddr= ipconfig.ip.addr; //sation ip +info->server_name = "espLight"; +info->server_port = 80; +info->txt_data[0] = "version = 1.0.1"; +espconn_mdns_init(info); + + +} +#endif + +/****************************************************************************** + * FunctionName : user_esp_platform_check_ip + * Description : espconn struct parame init when get ip addr + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_check_ip(uint8 reset_flag) +{ + struct ip_info ipconfig; + + os_timer_disarm(&client_timer); + + wifi_get_ip_info(STATION_IF, &ipconfig); + + if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) { +#if (PLUG_DEVICE || SENSOR_DEVICE) + user_link_led_timer_init(); +#endif + +//*************************** +#if LIGHT_DEVICE + user_mdns_conf(); +#endif +//*************************** + user_conn.proto.tcp = &user_tcp; + user_conn.type = ESPCONN_TCP; + user_conn.state = ESPCONN_NONE; + + device_status = DEVICE_CONNECTING; + + if (reset_flag) { + device_recon_count = 0; + } + +#if (PLUG_DEVICE || LIGHT_DEVICE) + os_timer_disarm(&beacon_timer); + os_timer_setfn(&beacon_timer, (os_timer_func_t *)user_esp_platform_sent_beacon, &user_conn); +#endif + +#ifdef USE_DNS + user_esp_platform_start_dns(&user_conn); +#else + const char esp_server_ip[4] = {114, 215, 177, 97}; + + os_memcpy(user_conn.proto.tcp->remote_ip, esp_server_ip, 4); + user_conn.proto.tcp->local_port = espconn_port(); + +#ifdef CLIENT_SSL_ENABLE + user_conn.proto.tcp->remote_port = 8443; +#else + user_conn.proto.tcp->remote_port = 8000; +#endif + + espconn_regist_connectcb(&user_conn, user_esp_platform_connect_cb); + espconn_regist_reconcb(&user_conn, user_esp_platform_recon_cb); + user_esp_platform_connect(&user_conn); +#endif + } else { + /* if there are wrong while connecting to some AP, then reset mode */ + if ((wifi_station_get_connect_status() == STATION_WRONG_PASSWORD || + wifi_station_get_connect_status() == STATION_NO_AP_FOUND || + wifi_station_get_connect_status() == STATION_CONNECT_FAIL)) { + user_esp_platform_reset_mode(); + } else { + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, NULL); + os_timer_arm(&client_timer, 100, 0); + } + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_init + * Description : device parame init based on espressif platform + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_init(void) +{ + + os_sprintf(iot_version,"%s%d.%d.%dt%d(%s)",VERSION_TYPE,IOT_VERSION_MAJOR,\ + IOT_VERSION_MINOR,IOT_VERSION_REVISION,device_type,UPGRADE_FALG); + os_printf("IOT VERSION = %s\n",iot_version); + + system_param_load(ESP_PARAM_START_SEC, 0, &esp_param, sizeof(esp_param)); + + struct rst_info *rtc_info = system_get_rst_info(); + + os_printf("reset reason: %x\n", rtc_info->reason); + + if (rtc_info->reason == REASON_WDT_RST || + rtc_info->reason == REASON_EXCEPTION_RST || + rtc_info->reason == REASON_SOFT_WDT_RST) { + if (rtc_info->reason == REASON_EXCEPTION_RST) { + os_printf("Fatal exception (%d):\n", rtc_info->exccause); + } + os_printf("epc1=0x%08x, epc2=0x%08x, epc3=0x%08x, excvaddr=0x%08x, depc=0x%08x\n", + rtc_info->epc1, rtc_info->epc2, rtc_info->epc3, rtc_info->excvaddr, rtc_info->depc); + } + + /***add by tzx for saving ip_info to avoid dhcp_client start****/ + struct dhcp_client_info dhcp_info; + struct ip_info sta_info; + system_rtc_mem_read(64,&dhcp_info,sizeof(struct dhcp_client_info)); + if(dhcp_info.flag == 0x01 ) { + if (true == wifi_station_dhcpc_status()) + { + wifi_station_dhcpc_stop(); + } + sta_info.ip = dhcp_info.ip_addr; + sta_info.gw = dhcp_info.gw; + sta_info.netmask = dhcp_info.netmask; + if ( true != wifi_set_ip_info(STATION_IF,&sta_info)) { + os_printf("set default ip wrong\n"); + } + } + os_memset(&dhcp_info,0,sizeof(struct dhcp_client_info)); + system_rtc_mem_write(64,&dhcp_info,sizeof(struct rst_info)); + + +#if AP_CACHE + wifi_station_ap_number_set(AP_CACHE_NUMBER); +#endif + +#if 0 + { + char sofap_mac[6] = {0x16, 0x34, 0x56, 0x78, 0x90, 0xab}; + char sta_mac[6] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab}; + struct ip_info info; + + wifi_set_macaddr(SOFTAP_IF, sofap_mac); + wifi_set_macaddr(STATION_IF, sta_mac); + + IP4_ADDR(&info.ip, 192, 168, 3, 200); + IP4_ADDR(&info.gw, 192, 168, 3, 1); + IP4_ADDR(&info.netmask, 255, 255, 255, 0); + wifi_set_ip_info(STATION_IF, &info); + + IP4_ADDR(&info.ip, 10, 10, 10, 1); + IP4_ADDR(&info.gw, 10, 10, 10, 1); + IP4_ADDR(&info.netmask, 255, 255, 255, 0); + wifi_set_ip_info(SOFTAP_IF, &info); + } +#endif + + if (esp_param.activeflag != 1) { +#ifdef SOFTAP_ENCRYPT + struct softap_config config; + char password[33]; + char macaddr[6]; + + wifi_softap_get_config(&config); + wifi_get_macaddr(SOFTAP_IF, macaddr); + + os_memset(config.password, 0, sizeof(config.password)); + os_sprintf(password, MACSTR "_%s", MAC2STR(macaddr), PASSWORD); + os_memcpy(config.password, password, os_strlen(password)); + config.authmode = AUTH_WPA_WPA2_PSK; + + wifi_softap_set_config(&config); +#endif + + wifi_set_opmode(STATIONAP_MODE); + } + +#if PLUG_DEVICE + user_plug_init(); +#elif LIGHT_DEVICE + user_light_init(); +#elif SENSOR_DEVICE + user_sensor_init(esp_param.activeflag); +#endif + + if (wifi_get_opmode() != SOFTAP_MODE) { + os_timer_disarm(&client_timer); + os_timer_setfn(&client_timer, (os_timer_func_t *)user_esp_platform_check_ip, (void *)1); + os_timer_arm(&client_timer, 100, 0); + } +} + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform_timer.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform_timer.c new file mode 100644 index 0000000000..1263c350ee --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_esp_platform_timer.c @@ -0,0 +1,358 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "mem.h" +#include "osapi.h" +#include "user_interface.h" + +#include "espconn.h" +#include "user_esp_platform.h" + +#define ESP_DEBUG + +#ifdef ESP_DEBUG +#define ESP_DBG os_printf +#else +#define ESP_DBG +#endif + +LOCAL os_timer_t device_timer; +uint32 min_wait_second; +char timestamp_str[11]; +int timestamp = 0; +char *timer_splits[20] = {NULL}; + +struct esp_platform_wait_timer_param { + uint8 wait_time_param[11]; + uint8 wait_action[15]; + int wait_time_second; +}; + +struct wait_param { + uint8 action[20][15]; + uint16 action_number; + uint16 count; + uint32 min_time_backup; +}; + +void esp_platform_timer_action(struct esp_platform_wait_timer_param *timer_wait_param, uint16 count); + +/****************************************************************************** + * FunctionName : split + * Description : split string p1 according to sting p2 and save the splits + * Parameters : p1 , p2 ,splits[] + * Returns : the number of splits +*******************************************************************************/ +uint16 ICACHE_FLASH_ATTR +split(char *p1, char *p2, char *splits[]) +{ + int i = 0; + int j = 0; + + while (i != -1) { + int start = i; + int end = indexof(p1, p2, start); + + if (end == -1) { + end = os_strlen(p1); + } + + char *p = (char *) os_zalloc(100); + os_memcpy(p, p1 + start, end - start); + p[end - start] = '\0'; + splits[j] = p; + j++; + i = end + 1; + + if (i > os_strlen(p1)) { + break; + } + } + + return j; +} + +/****************************************************************************** + * FunctionName : indexof + * Description : calculate the offset of p2 relate to start of p1 + * Parameters : p1,p1,start + * Returns : the offset of p2 relate to the start +*******************************************************************************/ +int ICACHE_FLASH_ATTR +indexof(char *p1, char *p2, int start) +{ + char *find = (char *)os_strstr(p1 + start, p2); + + if (find != NULL) { + return (find - p1); + } + + return -1; +} + +/****************************************************************************** + * FunctionName : esp_platform_find_min_time + * Description : find the minimum wait second in timer list + * Parameters : timer_wait_param -- param of timer action and wait time param + * count -- The number of timers given by server + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +esp_platform_find_min_time(struct esp_platform_wait_timer_param *timer_wait_param , uint16 count) +{ + uint16 i = 0; + min_wait_second = 0xFFFFFFF; + + for (i = 0; i < count ; i++) { + if (timer_wait_param[i].wait_time_second < min_wait_second && timer_wait_param[i].wait_time_second >= 0) { + min_wait_second = timer_wait_param[i].wait_time_second; + } + } +} + +/****************************************************************************** + * FunctionName : user_platform_timer_first_start + * Description : calculate the wait time of each timer + * Parameters : count -- The number of timers given by server + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_platform_timer_first_start(uint16 count) +{ + int i = 0; + struct esp_platform_wait_timer_param timer_wait_param[100] = {0}; + + ESP_DBG("current timestamp= %ds\n", timestamp); + + timestamp = timestamp + min_wait_second; + + for (i = 0 ; i < count ; i++) { + char *str = timer_splits[i]; + + if (indexof(str, "f", 0) == 0) { + char *fixed_wait[2]; + + ESP_DBG("timer is fixed mode\n"); + + split(str, "=", fixed_wait); + os_memcpy(timer_wait_param[i].wait_time_param, fixed_wait[0] + 1, os_strlen(fixed_wait[0]) - 1); + os_memcpy(timer_wait_param[i].wait_action, fixed_wait[1], os_strlen(fixed_wait[1])); + timer_wait_param[i].wait_time_second = atoi(timer_wait_param[i].wait_time_param) - timestamp; + os_free(fixed_wait[0]); + os_free(fixed_wait[1]); + } + + else if (indexof(str, "l", 0) == 0) { + char *loop_wait[2]; + + ESP_DBG("timer is loop mode\n"); + + split(str, "=", loop_wait); + os_memcpy(timer_wait_param[i].wait_time_param, loop_wait[0] + 1, os_strlen(loop_wait[0]) - 1); + os_memcpy(timer_wait_param[i].wait_action, loop_wait[1], os_strlen(loop_wait[1])); + timer_wait_param[i].wait_time_second = atoi(timer_wait_param[i].wait_time_param) - (timestamp % atoi(timer_wait_param[i].wait_time_param)); + os_free(loop_wait[0]); + os_free(loop_wait[1]); + } else if (indexof(str, "w", 0) == 0) { + char *week_wait[2]; + int monday_wait_time = 0; + + ESP_DBG("timer is weekend mode\n"); + + split(str, "=", week_wait); + os_memcpy(timer_wait_param[i].wait_time_param, week_wait[0] + 1, os_strlen(week_wait[0]) - 1); + os_memcpy(timer_wait_param[i].wait_action, week_wait[1], os_strlen(week_wait[1])); + monday_wait_time = (timestamp - 1388937600) % (7 * 24 * 3600); + + ESP_DBG("monday_wait_time == %d", monday_wait_time); + + if (atoi(timer_wait_param[i].wait_time_param) > monday_wait_time) { + timer_wait_param[i].wait_time_second = atoi(timer_wait_param[i].wait_time_param) - monday_wait_time; + } else { + timer_wait_param[i].wait_time_second = 7 * 24 * 3600 - monday_wait_time + atoi(timer_wait_param[i].wait_time_param); + } + + os_free(week_wait[0]); + os_free(week_wait[1]); + } + } + + esp_platform_find_min_time(timer_wait_param, count); + if(min_wait_second == 0) { + return; + } + + esp_platform_timer_action(timer_wait_param, count); +} + +/****************************************************************************** + * FunctionName : user_esp_platform_device_action + * Description : Execute the actions of minimum wait time + * Parameters : pwait_action -- point the list of actions which need execute + * + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_device_action(struct wait_param *pwait_action) +{ + uint8 i = 0; + uint16 count = pwait_action->count; + uint16 action_number = pwait_action->action_number; + + ESP_DBG("there is %d action at the same time\n", pwait_action->action_number); + +#if PLUG_DEVICE + for (i = 0; i < action_number && pwait_action->action[i][0] != '0'; i++) { + ESP_DBG("%s\n",pwait_action->action[i]); + + if (os_strcmp(pwait_action->action[i], "on_switch", 9) == 0) { + user_plug_set_status(0x01); + } else if (os_strcmp(pwait_action->action[i], "off_switch", 10) == 0) { + user_plug_set_status(0x00); + } else if (os_strcmp(pwait_action->action[i], "on_off_switch", 13) == 0) { + if (user_plug_get_status() == 0) { + user_plug_set_status(0x01); + } else { + user_plug_set_status(0x00); + } + } else { + return; + } + } + user_platform_timer_first_start(count); +#endif +} + +/****************************************************************************** + * FunctionName : user_platform_timer_start + * Description : Processing the message about timer from the server + * Parameters : timer_wait_param -- The received data from the server + * count -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_esp_platform_wait_time_overflow_check(struct wait_param *pwait_action) +{ + ESP_DBG("min_wait_second = %d", min_wait_second); + + if (pwait_action->min_time_backup >= 3600) { + os_timer_disarm(&device_timer); + os_timer_setfn(&device_timer, (os_timer_func_t *)user_esp_platform_wait_time_overflow_check, pwait_action); + os_timer_arm(&device_timer, 3600000, 0); + ESP_DBG("min_wait_second is extended\n"); + } else { + os_timer_disarm(&device_timer); + os_timer_setfn(&device_timer, (os_timer_func_t *)user_esp_platform_device_action, pwait_action); + os_timer_arm(&device_timer, pwait_action->min_time_backup * 1000, 0); + ESP_DBG("min_wait_second is = %dms\n", pwait_action->min_time_backup * 1000); + } + + pwait_action->min_time_backup -= 3600; +} + +/****************************************************************************** + * FunctionName : user_platform_timer_start + * Description : Processing the message about timer from the server + * Parameters : timer_wait_param -- The received data from the server + * count -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +esp_platform_timer_action(struct esp_platform_wait_timer_param *timer_wait_param, uint16 count) +{ + uint16 i = 0; + uint16 action_number; + struct wait_param pwait_action = {0}; + + pwait_action.count = count; + action_number = 0; + + for (i = 0; i < count ; i++) { + if (timer_wait_param[i].wait_time_second == min_wait_second) { + os_memcpy(pwait_action.action[action_number], timer_wait_param[i].wait_action, os_strlen(timer_wait_param[i].wait_action)); + ESP_DBG("*****%s*****\n", timer_wait_param[i].wait_action); + action_number++; + } + } + + pwait_action.action_number = action_number; + pwait_action.min_time_backup = min_wait_second; + user_esp_platform_wait_time_overflow_check(&pwait_action); +} + +/****************************************************************************** + * FunctionName : user_platform_timer_start + * Description : Processing the message about timer from the server + * Parameters : pbuffer -- The received data from the server + + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_platform_timer_start(char *pbuffer) +{ + int str_begin = 0; + int str_end = 0; + uint8 i = 0; + char *pstr_start = NULL; + char *pstr_end = NULL; + struct esp_platform_wait_timer_param timer_wait_param[20]; + char *pstr = NULL; + + min_wait_second = 0; + + if ((pstr = (char *)os_strstr(pbuffer, "\"timestamp\":")) != NULL) { + pstr_start = pstr + 13; + pstr_end = (char *)os_strstr(pstr_start, ","); + + if (pstr != NULL) { + os_memcpy(timestamp_str, pstr_start, pstr_end - pstr_start); + timestamp = atoi(timestamp_str); + } + } + + for (i = 0 ; i < 20 ; i++) { + if (timer_splits[i] != NULL) { + os_free(timer_splits[i]); + timer_splits[i] = NULL; + } + } + + if ((pstr_start = (char *)os_strstr(pbuffer, "\"timers\": \"")) != NULL) { + str_begin = 11; + str_end = indexof(pstr_start, "\"", str_begin); + + if (str_begin == str_end) { + os_timer_disarm(&device_timer); + return; + } + + char *split_buffer = (char *)os_zalloc(str_end - str_begin + 1); + os_memcpy(split_buffer, pstr_start + str_begin, str_end - str_begin); + uint16 count = split(split_buffer , ";" , timer_splits); + os_free(split_buffer); + user_platform_timer_first_start(count); + } +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_json.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_json.c new file mode 100644 index 0000000000..6c98553eb0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_json.c @@ -0,0 +1,177 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +#include "mem.h" + +#include "user_json.h" + +LOCAL char *json_buf; +LOCAL int pos; +LOCAL int size; + +/****************************************************************************** + * FunctionName : find_json_path + * Description : find the JSON format tree's path + * Parameters : json -- A pointer to a JSON set up + * path -- A pointer to the JSON format tree's path + * Returns : A pointer to the JSON format tree +*******************************************************************************/ +struct jsontree_value *ICACHE_FLASH_ATTR +find_json_path(struct jsontree_context *json, const char *path) +{ + struct jsontree_value *v; + const char *start; + const char *end; + int len; + + v = json->values[0]; + start = path; + + do { + end = (const char *)os_strstr(start, "/"); + + if (end == start) { + break; + } + + if (end != NULL) { + len = end - start; + end++; + } else { + len = os_strlen(start); + } + + if (v->type != JSON_TYPE_OBJECT) { + v = NULL; + } else { + struct jsontree_object *o; + int i; + + o = (struct jsontree_object *)v; + v = NULL; + + for (i = 0; i < o->count; i++) { + if (os_strncmp(start, o->pairs[i].name, len) == 0) { + v = o->pairs[i].value; + json->index[json->depth] = i; + json->depth++; + json->values[json->depth] = v; + json->index[json->depth] = 0; + break; + } + } + } + + start = end; + } while (end != NULL && *end != '\0' && v != NULL); + + json->callback_state = 0; + return v; +} + +/****************************************************************************** + * FunctionName : json_putchar + * Description : write the value to the JSON format tree + * Parameters : c -- the value which write the JSON format tree + * Returns : result +*******************************************************************************/ +int ICACHE_FLASH_ATTR +json_putchar(int c) +{ + if (json_buf != NULL && pos <= size) { + json_buf[pos++] = c; + return c; + } + + return 0; +} + +/****************************************************************************** + * FunctionName : json_ws_send + * Description : set up the JSON format tree for string + * Parameters : tree -- A pointer to the JSON format tree + * path -- A pointer to the JSON format tree's path + * pbuf -- A pointer for the data sent + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +json_ws_send(struct jsontree_value *tree, const char *path, char *pbuf) +{ + struct jsontree_context json; + /* maxsize = 128 bytes */ + json_buf = (char *)os_malloc(jsonSize); + + /* reset state and set max-size */ + /* NOTE: packet will be truncated at 512 bytes */ + pos = 0; + size = jsonSize; + + json.values[0] = (struct jsontree_value *)tree; + jsontree_reset(&json); + find_json_path(&json, path); + json.path = json.depth; + json.putchar = json_putchar; + + while (jsontree_print_next(&json) && json.path <= json.depth); + + json_buf[pos] = 0; + os_memcpy(pbuf, json_buf, pos); + os_free(json_buf); +} + +/****************************************************************************** + * FunctionName : json_parse + * Description : parse the data as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * ptrJSONMessage -- A pointer to the data + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +json_parse(struct jsontree_context *json, char *ptrJSONMessage) +{ + /* Set value */ + struct jsontree_value *v; + struct jsontree_callback *c; + struct jsontree_callback *c_bak = NULL; + + while ((v = jsontree_find_next(json, JSON_TYPE_CALLBACK)) != NULL) { + c = (struct jsontree_callback *)v; + + if (c == c_bak) { + continue; + } + + c_bak = c; + + if (c->set != NULL) { + struct jsonparse_state js; + + jsonparse_setup(&js, ptrJSONMessage, os_strlen(ptrJSONMessage)); + c->set(json, &js); + } + } +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light.c new file mode 100644 index 0000000000..dddba533a8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light.c @@ -0,0 +1,155 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +#include "mem.h" +#include "user_interface.h" + +#include "user_light.h" +#include "pwm.h" + +#if LIGHT_DEVICE + +struct light_saved_param light_param; + +/****************************************************************************** + * FunctionName : user_light_get_duty + * Description : get duty of each channel + * Parameters : uint8 channel : LIGHT_RED/LIGHT_GREEN/LIGHT_BLUE + * Returns : NONE +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_light_get_duty(uint8 channel) +{ + return light_param.pwm_duty[channel]; +} + +/****************************************************************************** + * FunctionName : user_light_set_duty + * Description : set each channel's duty params + * Parameters : uint8 duty : 0 ~ PWM_DEPTH + * uint8 channel : LIGHT_RED/LIGHT_GREEN/LIGHT_BLUE + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_light_set_duty(uint32 duty, uint8 channel) +{ + if (duty != light_param.pwm_duty[channel]) { + pwm_set_duty(duty, channel); + + light_param.pwm_duty[channel] = pwm_get_duty(channel); + } +} + +/****************************************************************************** + * FunctionName : user_light_get_period + * Description : get pwm period + * Parameters : NONE + * Returns : uint32 : pwm period +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_light_get_period(void) +{ + return light_param.pwm_period; +} + +/****************************************************************************** + * FunctionName : user_light_set_duty + * Description : set pwm frequency + * Parameters : uint16 freq : 100hz typically + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_light_set_period(uint32 period) +{ + if (period != light_param.pwm_period) { + pwm_set_period(period); + + light_param.pwm_period = pwm_get_period(); + } +} + +void ICACHE_FLASH_ATTR +user_light_restart(void) +{ + spi_flash_erase_sector(PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE); + spi_flash_write((PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE) * SPI_FLASH_SEC_SIZE, + (uint32 *)&light_param, sizeof(struct light_saved_param)); + + pwm_start(); +} + +/****************************************************************************** + * FunctionName : user_light_init + * Description : light demo init, mainy init pwm + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_light_init(void) +{ + spi_flash_read((PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE) * SPI_FLASH_SEC_SIZE, + (uint32 *)&light_param, sizeof(struct light_saved_param)); + if(light_param.pwm_period>10000 || light_param.pwm_period <1000){ + light_param.pwm_period = 1000; + } + + uint32 io_info[][3] = { {PWM_0_OUT_IO_MUX,PWM_0_OUT_IO_FUNC,PWM_0_OUT_IO_NUM}, + {PWM_1_OUT_IO_MUX,PWM_1_OUT_IO_FUNC,PWM_1_OUT_IO_NUM}, + {PWM_2_OUT_IO_MUX,PWM_2_OUT_IO_FUNC,PWM_2_OUT_IO_NUM}, + {PWM_3_OUT_IO_MUX,PWM_3_OUT_IO_FUNC,PWM_3_OUT_IO_NUM}, + {PWM_4_OUT_IO_MUX,PWM_4_OUT_IO_FUNC,PWM_4_OUT_IO_NUM}, + }; + + uint32 pwm_duty_init[PWM_CHANNEL] = {0}; + + /*PIN FUNCTION INIT FOR PWM OUTPUT*/ + pwm_init(light_param.pwm_period, pwm_duty_init ,PWM_CHANNEL,io_info); + + os_printf("LIGHT PARAM: R: %d \r\n",light_param.pwm_duty[LIGHT_RED]); + os_printf("LIGHT PARAM: G: %d \r\n",light_param.pwm_duty[LIGHT_GREEN]); + os_printf("LIGHT PARAM: B: %d \r\n",light_param.pwm_duty[LIGHT_BLUE]); + if(PWM_CHANNEL>LIGHT_COLD_WHITE){ + os_printf("LIGHT PARAM: CW: %d \r\n",light_param.pwm_duty[LIGHT_COLD_WHITE]); + os_printf("LIGHT PARAM: WW: %d \r\n",light_param.pwm_duty[LIGHT_WARM_WHITE]); + } + os_printf("LIGHT PARAM: P: %d \r\n",light_param.pwm_period); + + uint32 light_init_target[8]={0}; + os_memcpy(light_init_target,light_param.pwm_duty,sizeof(light_param.pwm_duty)); + + light_set_aim( + light_init_target[LIGHT_RED], + light_init_target[LIGHT_GREEN], + light_init_target[LIGHT_BLUE], + light_init_target[LIGHT_COLD_WHITE], + light_init_target[LIGHT_WARM_WHITE], + light_param.pwm_period); + set_pwm_debug_en(0);//disable debug print in pwm driver + os_printf("PWM version : %08x \r\n",get_pwm_version()); +} +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light_adj.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light_adj.c new file mode 100644 index 0000000000..288a9675cb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_light_adj.c @@ -0,0 +1,357 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +#include "mem.h" +#include "user_interface.h" + +#include "user_light.h" +#include "user_light_adj.h" +#include "pwm.h" + +#define ABS_MINUS(x,y) (x LIGHT_EVT_QNUM ){ + TotalUsedLightEvtNum--; + } + else{ + tmp = &(LightEvtArr[CurFreeLightEvtIdx]); + CurFreeLightEvtIdx++; + if( CurFreeLightEvtIdx > (LIGHT_EVT_QNUM-1) ) + CurFreeLightEvtIdx = 0; + } + os_printf("malloc:%u\n",TotalUsedLightEvtNum); + return tmp; +} + +static void ICACHE_FLASH_ATTR LightEvtFree(void) +{ + TotalUsedLightEvtNum--; +os_printf("free:%u\n",TotalUsedLightEvtNum); +} +//------------------------------------------------------------------------------------ + +static void ICACHE_FLASH_ATTR light_pwm_smooth_adj_proc(void); + + +void ICACHE_FLASH_ATTR + light_save_target_duty() +{ + extern struct light_saved_param light_param; + + os_memcpy(light_param.pwm_duty,current_duty,sizeof(light_param.pwm_duty)); + light_param.pwm_period = pwm_get_period(); + +#if SAVE_LIGHT_PARAM + spi_flash_erase_sector(PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE); + spi_flash_write((PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE) * SPI_FLASH_SEC_SIZE, + (uint32 *)&light_param, sizeof(struct light_saved_param)); +#endif + +} + + +void ICACHE_FLASH_ATTR +light_set_aim_r(uint32 r) +{ + current_duty[LIGHT_RED]=r; + light_pwm_smooth_adj_proc(); +} + +void ICACHE_FLASH_ATTR +light_set_aim_g(uint32 g) +{ + current_duty[LIGHT_GREEN]=g; + light_pwm_smooth_adj_proc(); +} + +void ICACHE_FLASH_ATTR +light_set_aim_b(uint32 b) +{ + current_duty[LIGHT_BLUE]=b; + light_pwm_smooth_adj_proc(); +} + +void ICACHE_FLASH_ATTR +light_set_aim_cw(uint32 cw) +{ + current_duty[LIGHT_COLD_WHITE]=cw; + light_pwm_smooth_adj_proc(); +} + +void ICACHE_FLASH_ATTR +light_set_aim_ww(uint32 ww) +{ + current_duty[LIGHT_WARM_WHITE]=ww; + light_pwm_smooth_adj_proc(); +} + +LOCAL bool ICACHE_FLASH_ATTR + check_pwm_current_duty_diff() +{ + int i; + + for(i=0;i>4; + if( ABS_MINUS(duty_now[i],current_duty[i])<20 ) + duty_now[i] = current_duty[i]; + user_light_set_duty(duty_now[i],i); + } + + //os_printf("duty:%u,%u,%u\r\n", pwm.duty[0],pwm.duty[1],pwm.duty[2] ); + pwm_start(); + + if(check_pwm_current_duty_diff()){ + change_finish = 0; + os_timer_disarm(&timer_pwm_adj); + os_timer_setfn(&timer_pwm_adj, (os_timer_func_t *)light_dh_pwm_adj_proc, NULL); + os_timer_arm(&timer_pwm_adj, min_ms, 0); + } + else{ + os_printf("finish\n"); + change_finish = 1; + //light_save_target_duty(); + os_timer_disarm(&timer_pwm_adj); + light_pwm_smooth_adj_proc(); + } + +} + +LOCAL bool ICACHE_FLASH_ATTR + check_pwm_duty_zero() +{ + int i; + for(i=0;i0 ){ + user_light_set_period( LightEvtArr[CurEvtIdxToBeUse].period ); + + os_memcpy(current_duty,LightEvtArr[CurEvtIdxToBeUse].duty,sizeof(current_duty)); + CurEvtIdxToBeUse++; + if(CurEvtIdxToBeUse > (LIGHT_EVT_QNUM-1) ){ + CurEvtIdxToBeUse = 0; + } + LightEvtFree(); + + if(change_finish){ + light_dh_pwm_adj_proc(NULL); + } + } + + if(change_finish){ + light_save_target_duty(); + if(check_pwm_duty_zero()){ + if(light_sleep_flg==0){ + os_printf("light sleep en\r\n"); + wifi_set_sleep_type(LIGHT_SLEEP_T); + light_sleep_flg = 1; + } + } + } +} + + + +#if LIGHT_CURRENT_LIMIT +uint32 light_get_cur(uint32 duty , uint8 channel, uint32 period) +{ + uint32 duty_max_limit = (period*1000/45); + uint32 duty_mapped = duty*22727/duty_max_limit; + switch(channel){ + + case LIGHT_RED : + if(duty_mapped>=0 && duty_mapped<23000){ + return (duty_mapped*151000/22727); + } + + break; + + case LIGHT_GREEN: + if(duty_mapped>=0 && duty_mapped<23000){ + return (duty_mapped*82000/22727); + } + break; + + case LIGHT_BLUE: + if(duty_mapped>=0 && duty_mapped<23000){ + return (duty_mapped*70000/22727); + } + break; + + case LIGHT_COLD_WHITE: + case LIGHT_WARM_WHITE: + if(duty_mapped>=0 && duty_mapped<23000){ + return (duty_mapped*115000/22727); + } + break; + + default: + os_printf("CHANNEL ERROR IN GET_CUR\r\n"); + break; + + + + } + +} + +#endif + + + +void ICACHE_FLASH_ATTR +light_set_aim(uint32 r,uint32 g,uint32 b,uint32 cw,uint32 ww,uint32 period) +{ + struct pwm_param *tmp = LightEvtMalloc(); + if(tmp != NULL){ + tmp->period = (period<10000?period:10000); + uint32 duty_max_limit = (period*1000/45); + + tmp->duty[LIGHT_RED] = (rduty[LIGHT_GREEN] = (gduty[LIGHT_BLUE] = (bduty[LIGHT_COLD_WHITE] = (cwduty[LIGHT_WARM_WHITE] = (ww0 || ww>0){ + cur_r = light_get_cur(tmp->duty[LIGHT_RED] , LIGHT_RED, tmp->period); + + cur_g = light_get_cur(tmp->duty[LIGHT_GREEN] , LIGHT_GREEN, tmp->period); + cur_b = light_get_cur(tmp->duty[LIGHT_BLUE] , LIGHT_BLUE, tmp->period); + cur_rgb = (cur_r+cur_g+cur_b); + //} + uint32 cur_cw = light_get_cur( tmp->duty[LIGHT_COLD_WHITE],LIGHT_COLD_WHITE, tmp->period); + uint32 cur_ww = light_get_cur( tmp->duty[LIGHT_WARM_WHITE],LIGHT_WARM_WHITE, tmp->period); + uint32 cur_remain,cur_mar; + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN); + cur_mar = LIGHT_CURRENT_MARGIN; + +/* + if((cur_cw < 50000) || (cur_ww < 50000)){ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN); + cur_mar = LIGHT_CURRENT_MARGIN; + }else if((cur_cw < 99000) || (cur_ww < 99000)){ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN_L2); + cur_mar = LIGHT_CURRENT_MARGIN_L2; + }else{ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN_L3); + cur_mar = LIGHT_CURRENT_MARGIN_L2; + } + + */ + + /* + if((LIGHT_TOTAL_CURRENT_MAX-cur_rgb)>120){ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN); + cur_mar = LIGHT_CURRENT_MARGIN; + }else if((LIGHT_TOTAL_CURRENT_MAX-cur_rgb)>100){ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN_L2); + cur_mar = LIGHT_CURRENT_MARGIN_L2; + }else{ + cur_remain = (LIGHT_TOTAL_CURRENT_MAX - cur_rgb -LIGHT_CURRENT_MARGIN_L3); + cur_mar = LIGHT_CURRENT_MARGIN_L2; + } + */ + + + + os_printf("cur_remain: %d \r\n",cur_remain); + while((cur_cw+cur_ww) > cur_remain){ + tmp->duty[LIGHT_COLD_WHITE] = tmp->duty[LIGHT_COLD_WHITE] * 9 / 10; + tmp->duty[LIGHT_WARM_WHITE] = tmp->duty[LIGHT_WARM_WHITE] * 9 / 10; + cur_cw = light_get_cur( tmp->duty[LIGHT_COLD_WHITE],LIGHT_COLD_WHITE, tmp->period); + cur_ww = light_get_cur( tmp->duty[LIGHT_WARM_WHITE],LIGHT_WARM_WHITE, tmp->period); + } + os_printf("debug : %d %d %d %d %d\r\n",cur_r/1000,cur_g/1000,cur_b/1000,cur_cw/1000,cur_ww/1000); + + os_printf("debug:total current after adj : %d + %d mA \r\n",(cur_cw+cur_ww+cur_r+cur_g+cur_b)/1000,cur_mar/1000); +#endif + + + + + os_printf("prd:%u r : %u g: %u b: %u cw: %u ww: %u \r\n",period, + tmp->duty[0],tmp->duty[1],tmp->duty[2],tmp->duty[3],tmp->duty[4]); + light_pwm_smooth_adj_proc(); + } + else{ + os_printf("light para full\n"); + } +} + + + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_main.c new file mode 100644 index 0000000000..deae2a425b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_main.c @@ -0,0 +1,128 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" + +#include "user_interface.h" + +#include "user_devicefind.h" +#include "user_webserver.h" + +#if ESP_PLATFORM +#include "user_esp_platform.h" +#endif + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + + + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_init(void) +{ + os_printf("SDK version:%s\n", system_get_sdk_version()); + +#if ESP_PLATFORM + /*Initialization of the peripheral drivers*/ + /*For light demo , it is user_light_init();*/ + /* Also check whether assigned ip addr by the router.If so, connect to ESP-server */ + user_esp_platform_init(); +#endif + /*Establish a udp socket to receive local device detect info.*/ + /*Listen to the port 1025, as well as udp broadcast. + /*If receive a string of device_find_request, it rely its IP address and MAC.*/ + user_devicefind_init(); + + /*Establish a TCP server for http(with JSON) POST or GET command to communicate with the device.*/ + /*You can find the command in "2B-SDK-Espressif IoT Demo.pdf" to see the details.*/ + /*the JSON command for curl is like:*/ + /*3 Channel mode: curl -X POST -H "Content-Type:application/json" -d "{\"period\":1000,\"rgb\":{\"red\":16000,\"green\":16000,\"blue\":16000}}" http://192.168.4.1/config?command=light */ + /*5 Channel mode: curl -X POST -H "Content-Type:application/json" -d "{\"period\":1000,\"rgb\":{\"red\":16000,\"green\":16000,\"blue\":16000,\"cwhite\":3000,\"wwhite\",3000}}" http://192.168.4.1/config?command=light */ +#ifdef SERVER_SSL_ENABLE + user_webserver_init(SERVER_SSL_PORT); +#else + user_webserver_init(SERVER_PORT); +#endif +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_plug.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_plug.c new file mode 100644 index 0000000000..90a1698760 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_plug.c @@ -0,0 +1,173 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +#include "mem.h" +#include "user_interface.h" + +#include "user_plug.h" + +#if PLUG_DEVICE + +LOCAL struct plug_saved_param plug_param; +LOCAL struct keys_param keys; +LOCAL struct single_key_param *single_key[PLUG_KEY_NUM]; +LOCAL os_timer_t link_led_timer; +LOCAL uint8 link_led_level = 0; + +/****************************************************************************** + * FunctionName : user_plug_get_status + * Description : get plug's status, 0x00 or 0x01 + * Parameters : none + * Returns : uint8 - plug's status +*******************************************************************************/ +uint8 ICACHE_FLASH_ATTR +user_plug_get_status(void) +{ + return plug_param.status; +} + +/****************************************************************************** + * FunctionName : user_plug_set_status + * Description : set plug's status, 0x00 or 0x01 + * Parameters : uint8 - status + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_plug_set_status(bool status) +{ + if (status != plug_param.status) { + if (status > 1) { + os_printf("error status input!\n"); + return; + } + + plug_param.status = status; + PLUG_STATUS_OUTPUT(PLUG_RELAY_LED_IO_NUM, status); + } +} + +/****************************************************************************** + * FunctionName : user_plug_short_press + * Description : key's short press function, needed to be installed + * Parameters : none + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_plug_short_press(void) +{ + user_plug_set_status((~plug_param.status) & 0x01); + + spi_flash_erase_sector(PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE); + spi_flash_write((PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE) * SPI_FLASH_SEC_SIZE, + (uint32 *)&plug_param, sizeof(struct plug_saved_param)); +} + +/****************************************************************************** + * FunctionName : user_plug_long_press + * Description : key's long press function, needed to be installed + * Parameters : none + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_plug_long_press(void) +{ + user_esp_platform_set_active(0); + system_restore(); + system_restart(); +} + +LOCAL void ICACHE_FLASH_ATTR +user_link_led_init(void) +{ + PIN_FUNC_SELECT(PLUG_LINK_LED_IO_MUX, PLUG_LINK_LED_IO_FUNC); +} + +void ICACHE_FLASH_ATTR +user_link_led_output(uint8 level) +{ + GPIO_OUTPUT_SET(GPIO_ID_PIN(PLUG_LINK_LED_IO_NUM), level); +} + +LOCAL void ICACHE_FLASH_ATTR +user_link_led_timer_cb(void) +{ + link_led_level = (~link_led_level) & 0x01; + GPIO_OUTPUT_SET(GPIO_ID_PIN(PLUG_LINK_LED_IO_NUM), link_led_level); +} + +void ICACHE_FLASH_ATTR +user_link_led_timer_init(void) +{ + os_timer_disarm(&link_led_timer); + os_timer_setfn(&link_led_timer, (os_timer_func_t *)user_link_led_timer_cb, NULL); + os_timer_arm(&link_led_timer, 50, 1); + link_led_level = 0; + GPIO_OUTPUT_SET(GPIO_ID_PIN(PLUG_LINK_LED_IO_NUM), link_led_level); +} + +void ICACHE_FLASH_ATTR +user_link_led_timer_done(void) +{ + os_timer_disarm(&link_led_timer); + GPIO_OUTPUT_SET(GPIO_ID_PIN(PLUG_LINK_LED_IO_NUM), 0); +} + +/****************************************************************************** + * FunctionName : user_plug_init + * Description : init plug's key function and relay output + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_plug_init(void) +{ + user_link_led_init(); + + wifi_status_led_install(PLUG_WIFI_LED_IO_NUM, PLUG_WIFI_LED_IO_MUX, PLUG_WIFI_LED_IO_FUNC); + + single_key[0] = key_init_single(PLUG_KEY_0_IO_NUM, PLUG_KEY_0_IO_MUX, PLUG_KEY_0_IO_FUNC, + user_plug_long_press, user_plug_short_press); + + keys.key_num = PLUG_KEY_NUM; + keys.single_key = single_key; + + key_init(&keys); + + spi_flash_read((PRIV_PARAM_START_SEC + PRIV_PARAM_SAVE) * SPI_FLASH_SEC_SIZE, + (uint32 *)&plug_param, sizeof(struct plug_saved_param)); + + PIN_FUNC_SELECT(PLUG_RELAY_LED_IO_MUX, PLUG_RELAY_LED_IO_FUNC); + + // no used SPI Flash + if (plug_param.status == 0xff) { + plug_param.status = 1; + } + + PLUG_STATUS_OUTPUT(PLUG_RELAY_LED_IO_NUM, plug_param.status); +} +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_sensor.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_sensor.c new file mode 100644 index 0000000000..c4be4430f1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_sensor.c @@ -0,0 +1,244 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +#include "user_interface.h" + +#if SENSOR_DEVICE +#include "user_sensor.h" + +LOCAL struct keys_param keys; +LOCAL struct single_key_param *single_key[SENSOR_KEY_NUM]; +LOCAL os_timer_t sensor_sleep_timer; +LOCAL os_timer_t link_led_timer; +LOCAL uint8 link_led_level = 0; +LOCAL uint32 link_start_time; + +#if HUMITURE_SUB_DEVICE +#include "driver/i2c_master.h" + +#define MVH3004_Addr 0x88 + +LOCAL uint8 humiture_data[4]; + +/****************************************************************************** + * FunctionName : user_mvh3004_burst_read + * Description : burst read mvh3004's internal data + * Parameters : uint8 addr - mvh3004's address + * uint8 *pData - data point to put read data + * uint16 len - read length + * Returns : bool - true or false +*******************************************************************************/ +LOCAL bool ICACHE_FLASH_ATTR +user_mvh3004_burst_read(uint8 addr, uint8 *pData, uint16 len) +{ + uint8 ack; + uint16 i; + + i2c_master_start(); + i2c_master_writeByte(addr); + ack = i2c_master_getAck(); + + if (ack) { + os_printf("addr not ack when tx write cmd \n"); + i2c_master_stop(); + return false; + } + + i2c_master_stop(); + i2c_master_wait(40000); + + i2c_master_start(); + i2c_master_writeByte(addr + 1); + ack = i2c_master_getAck(); + + if (ack) { + os_printf("addr not ack when tx write cmd \n"); + i2c_master_stop(); + return false; + } + + for (i = 0; i < len; i++) { + pData[i] = i2c_master_readByte(); + + i2c_master_setAck((i == (len - 1)) ? 1 : 0); + } + + i2c_master_stop(); + + return true; +} + +/****************************************************************************** + * FunctionName : user_mvh3004_read_th + * Description : read mvh3004's humiture data + * Parameters : uint8 *data - where data to put + * Returns : bool - ture or false +*******************************************************************************/ +bool ICACHE_FLASH_ATTR +user_mvh3004_read_th(uint8 *data) +{ + return user_mvh3004_burst_read(MVH3004_Addr, data, 4); +} + +/****************************************************************************** + * FunctionName : user_mvh3004_init + * Description : init mvh3004, mainly i2c master gpio + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_mvh3004_init(void) +{ + i2c_master_gpio_init(); +} + +uint8 *ICACHE_FLASH_ATTR +user_mvh3004_get_poweron_th(void) +{ + return humiture_data; +} +#endif + +/****************************************************************************** + * FunctionName : user_humiture_long_press + * Description : humiture key's function, needed to be installed + * Parameters : none + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +user_sensor_long_press(void) +{ + user_esp_platform_set_active(0); + system_restore(); + system_restart(); +} + +LOCAL void ICACHE_FLASH_ATTR +user_link_led_init(void) +{ + PIN_FUNC_SELECT(SENSOR_LINK_LED_IO_MUX, SENSOR_LINK_LED_IO_FUNC); + PIN_FUNC_SELECT(SENSOR_UNUSED_LED_IO_MUX, SENSOR_UNUSED_LED_IO_FUNC); + GPIO_OUTPUT_SET(GPIO_ID_PIN(SENSOR_UNUSED_LED_IO_NUM), 0); +} + +void ICACHE_FLASH_ATTR +user_link_led_output(uint8 level) +{ + GPIO_OUTPUT_SET(GPIO_ID_PIN(SENSOR_LINK_LED_IO_NUM), level); +} + +LOCAL void ICACHE_FLASH_ATTR +user_link_led_timer_cb(void) +{ + link_led_level = (~link_led_level) & 0x01; + GPIO_OUTPUT_SET(GPIO_ID_PIN(SENSOR_LINK_LED_IO_NUM), link_led_level); +} + +void ICACHE_FLASH_ATTR +user_link_led_timer_init(void) +{ + link_start_time = system_get_time(); + + os_timer_disarm(&link_led_timer); + os_timer_setfn(&link_led_timer, (os_timer_func_t *)user_link_led_timer_cb, NULL); + os_timer_arm(&link_led_timer, 50, 1); + link_led_level = 0; + GPIO_OUTPUT_SET(GPIO_ID_PIN(SENSOR_LINK_LED_IO_NUM), link_led_level); +} + +void ICACHE_FLASH_ATTR +user_link_led_timer_done(void) +{ + os_timer_disarm(&link_led_timer); + GPIO_OUTPUT_SET(GPIO_ID_PIN(SENSOR_LINK_LED_IO_NUM), 0); +} + +void ICACHE_FLASH_ATTR +user_sensor_deep_sleep_enter(void) +{ + system_deep_sleep(SENSOR_DEEP_SLEEP_TIME > link_start_time \ + ? SENSOR_DEEP_SLEEP_TIME - link_start_time : 30000000); +} + +void ICACHE_FLASH_ATTR +user_sensor_deep_sleep_disable(void) +{ + os_timer_disarm(&sensor_sleep_timer); +} + +void ICACHE_FLASH_ATTR +user_sensor_deep_sleep_init(uint32 time) +{ + os_timer_disarm(&sensor_sleep_timer); + os_timer_setfn(&sensor_sleep_timer, (os_timer_func_t *)user_sensor_deep_sleep_enter, NULL); + os_timer_arm(&sensor_sleep_timer, time, 0); +} + +/****************************************************************************** + * FunctionName : user_humiture_init + * Description : init humiture function, include key and mvh3004 + * Parameters : none + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_sensor_init(uint8 active) +{ + user_link_led_init(); + + wifi_status_led_install(SENSOR_WIFI_LED_IO_NUM, SENSOR_WIFI_LED_IO_MUX, SENSOR_WIFI_LED_IO_FUNC); + + if (wifi_get_opmode() != SOFTAP_MODE) { + single_key[0] = key_init_single(SENSOR_KEY_IO_NUM, SENSOR_KEY_IO_MUX, SENSOR_KEY_IO_FUNC, + user_sensor_long_press, NULL); + + keys.key_num = SENSOR_KEY_NUM; + keys.single_key = single_key; + + key_init(&keys); + + if (GPIO_INPUT_GET(GPIO_ID_PIN(SENSOR_KEY_IO_NUM)) == 0) { + user_sensor_long_press(); + } + } + +#if HUMITURE_SUB_DEVICE + user_mvh3004_init(); + user_mvh3004_read_th(humiture_data); +#endif + +#ifdef SENSOR_DEEP_SLEEP + if (wifi_get_opmode() != STATIONAP_MODE) { + if (active == 1) { + user_sensor_deep_sleep_init(SENSOR_DEEP_SLEEP_TIME / 1000 ); + } else { + user_sensor_deep_sleep_init(SENSOR_DEEP_SLEEP_TIME / 1000 / 3 * 2); + } + } +#endif +} +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_webserver.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_webserver.c new file mode 100644 index 0000000000..a4fc3eb081 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/IoT_Demo/user/user_webserver.c @@ -0,0 +1,1804 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" + +#include "user_iot_version.h" +#include "espconn.h" +#include "user_json.h" +#include "user_webserver.h" + +#include "upgrade.h" +#if ESP_PLATFORM +#include "user_esp_platform.h" +#endif + +#ifdef SERVER_SSL_ENABLE +#include "ssl/cert.h" +#include "ssl/private_key.h" +#endif + +#if LIGHT_DEVICE +#include "user_light.h" +#endif + +LOCAL struct station_config *sta_conf; +LOCAL struct softap_config *ap_conf; + +//LOCAL struct secrty_server_info *sec_server; +//LOCAL struct upgrade_server_info *server; +//struct lewei_login_info *login_info; +LOCAL scaninfo *pscaninfo; +struct bss_info *bss; +struct bss_info *bss_temp; +struct bss_info *bss_head; + +extern u16 scannum; + +LOCAL uint32 PostCmdNeeRsp = 1; + +uint8 upgrade_lock = 0; +LOCAL os_timer_t app_upgrade_10s; +LOCAL os_timer_t upgrade_check_timer; + +/****************************************************************************** + * FunctionName : device_get + * Description : set up the device information parmer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +device_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + + if (os_strncmp(path, "manufacture", 11) == 0) { + jsontree_write_string(js_ctx, "Espressif Systems"); + } else if (os_strncmp(path, "product", 7) == 0) { +#if SENSOR_DEVICE +#if HUMITURE_SUB_DEVICE + jsontree_write_string(js_ctx, "Humiture"); +#elif FLAMMABLE_GAS_SUB_DEVICE + jsontree_write_string(js_ctx, "Flammable Gas"); +#endif +#endif +#if PLUG_DEVICE + jsontree_write_string(js_ctx, "Plug"); +#endif +#if LIGHT_DEVICE + jsontree_write_string(js_ctx, "Light"); +#endif + } + + return 0; +} + +LOCAL struct jsontree_callback device_callback = + JSONTREE_CALLBACK(device_get, NULL); +/****************************************************************************** + * FunctionName : userbin_get + * Description : get up the user bin paramer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +userbin_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + char string[32]; + + if (os_strncmp(path, "status", 8) == 0) { + os_sprintf(string, "200"); + } else if (os_strncmp(path, "user_bin", 8) == 0) { + if (system_upgrade_userbin_check() == 0x00) { + os_sprintf(string, "user1.bin"); + } else if (system_upgrade_userbin_check() == 0x01) { + os_sprintf(string, "user2.bin"); + } else{ + return 0; + } + } + + jsontree_write_string(js_ctx, string); + + return 0; +} + +LOCAL struct jsontree_callback userbin_callback = + JSONTREE_CALLBACK(userbin_get, NULL); + +JSONTREE_OBJECT(userbin_tree, + JSONTREE_PAIR("status", &userbin_callback), + JSONTREE_PAIR("user_bin", &userbin_callback)); +JSONTREE_OBJECT(userinfo_tree,JSONTREE_PAIR("user_info",&userbin_tree)); +/****************************************************************************** + * FunctionName : version_get + * Description : set up the device version paramer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +version_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + char string[32]; + + if (os_strncmp(path, "hardware", 8) == 0) { +#if SENSOR_DEVICE + os_sprintf(string, "0.3"); +#else + os_sprintf(string, "0.1"); +#endif + } else if (os_strncmp(path, "sdk_version", 11) == 0) { + os_sprintf(string, "%s", system_get_sdk_version()); + } else if (os_strncmp(path, "iot_version", 11) == 0) { + os_sprintf(string,"%s%d.%d.%dt%d(%s)",VERSION_TYPE,IOT_VERSION_MAJOR,\ + IOT_VERSION_MINOR,IOT_VERSION_REVISION,device_type,UPGRADE_FALG); + } + + jsontree_write_string(js_ctx, string); + + return 0; +} + +LOCAL struct jsontree_callback version_callback = + JSONTREE_CALLBACK(version_get, NULL); + +JSONTREE_OBJECT(device_tree, + JSONTREE_PAIR("product", &device_callback), + JSONTREE_PAIR("manufacturer", &device_callback)); +JSONTREE_OBJECT(version_tree, + JSONTREE_PAIR("hardware", &version_callback), + JSONTREE_PAIR("sdk_version", &version_callback), + JSONTREE_PAIR("iot_version", &version_callback), + ); +JSONTREE_OBJECT(info_tree, + JSONTREE_PAIR("Version", &version_tree), + JSONTREE_PAIR("Device", &device_tree)); + +JSONTREE_OBJECT(INFOTree, + JSONTREE_PAIR("info", &info_tree)); + +LOCAL int ICACHE_FLASH_ATTR +connect_status_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + + if (os_strncmp(path, "status", 8) == 0) { + jsontree_write_int(js_ctx, user_esp_platform_get_connect_status()); + } + + return 0; +} + +LOCAL struct jsontree_callback connect_status_callback = + JSONTREE_CALLBACK(connect_status_get, NULL); + +JSONTREE_OBJECT(status_sub_tree, + JSONTREE_PAIR("status", &connect_status_callback)); + +JSONTREE_OBJECT(connect_status_tree, + JSONTREE_PAIR("Status", &status_sub_tree)); + +JSONTREE_OBJECT(con_status_tree, + JSONTREE_PAIR("info", &connect_status_tree)); + +#if PLUG_DEVICE +/****************************************************************************** + * FunctionName : status_get + * Description : set up the device status as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +status_get(struct jsontree_context *js_ctx) +{ + if (user_plug_get_status() == 1) { + jsontree_write_int(js_ctx, 1); + } else { + jsontree_write_int(js_ctx, 0); + } + + return 0; +} + +/****************************************************************************** + * FunctionName : status_set + * Description : parse the device status parmer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * parser -- A pointer to a JSON parser state + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +status_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser) +{ + int type; + + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_PAIR_NAME) { + if (jsonparse_strcmp_value(parser, "status") == 0) { + uint8 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + user_plug_set_status(status); + } + } + } + + return 0; +} + +LOCAL struct jsontree_callback status_callback = + JSONTREE_CALLBACK(status_get, status_set); + +JSONTREE_OBJECT(status_tree, + JSONTREE_PAIR("status", &status_callback)); +JSONTREE_OBJECT(response_tree, + JSONTREE_PAIR("Response", &status_tree)); +JSONTREE_OBJECT(StatusTree, + JSONTREE_PAIR("switch", &response_tree)); +#endif + +#if LIGHT_DEVICE +LOCAL int ICACHE_FLASH_ATTR +light_status_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + + if (os_strncmp(path, "red", 3) == 0) { + jsontree_write_int(js_ctx, user_light_get_duty(LIGHT_RED)); + } else if (os_strncmp(path, "green", 5) == 0) { + jsontree_write_int(js_ctx, user_light_get_duty(LIGHT_GREEN)); + } else if (os_strncmp(path, "blue", 4) == 0) { + jsontree_write_int(js_ctx, user_light_get_duty(LIGHT_BLUE)); + } else if (os_strncmp(path, "wwhite", 6) == 0) { + if(PWM_CHANNEL>LIGHT_WARM_WHITE){ + jsontree_write_int(js_ctx, user_light_get_duty(LIGHT_WARM_WHITE)); + }else{ + jsontree_write_int(js_ctx, 0); + } + } else if (os_strncmp(path, "cwhite", 6) == 0) { + if(PWM_CHANNEL>LIGHT_COLD_WHITE){ + jsontree_write_int(js_ctx, user_light_get_duty(LIGHT_COLD_WHITE)); + }else{ + jsontree_write_int(js_ctx, 0); + } + } else if (os_strncmp(path, "period", 6) == 0) { + jsontree_write_int(js_ctx, user_light_get_period()); + } + + return 0; +} + +LOCAL int ICACHE_FLASH_ATTR +light_status_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser) +{ + int type; + static uint32 r,g,b,cw,ww,period; + period = 1000; + cw=0; + ww=0; + extern uint8 light_sleep_flg; + + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_PAIR_NAME) { + if (jsonparse_strcmp_value(parser, "red") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + r=status; + os_printf("R: %d \n",status); + //user_light_set_duty(status, LIGHT_RED); + //light_set_aim_r( r); + } else if (jsonparse_strcmp_value(parser, "green") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + g=status; + os_printf("G: %d \n",status); + //user_light_set_duty(status, LIGHT_GREEN); + //light_set_aim_g( g); + } else if (jsonparse_strcmp_value(parser, "blue") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + b=status; + os_printf("B: %d \n",status); + //user_light_set_duty(status, LIGHT_BLUE); + //set_aim_b( b); + } else if (jsonparse_strcmp_value(parser, "cwhite") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + cw=status; + os_printf("CW: %d \n",status); + //user_light_set_duty(status, LIGHT_BLUE); + //set_aim_b( b); + } else if (jsonparse_strcmp_value(parser, "wwhite") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + ww=status; + os_printf("WW: %d \n",status); + //user_light_set_duty(status, LIGHT_BLUE); + //set_aim_b( b); + } else if (jsonparse_strcmp_value(parser, "period") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + os_printf("PERIOD: %d \n",status); + period=status; + //user_light_set_period(status); + }else if (jsonparse_strcmp_value(parser, "response") == 0) { + uint32 status; + jsonparse_next(parser); + jsonparse_next(parser); + status = jsonparse_get_value_as_int(parser); + os_printf("rspneed: %d \n",status); + PostCmdNeeRsp = status; + + } + } + } + + if((r|g|b|ww|cw) == 0){ + if(light_sleep_flg==0){ + + } + + }else{ + if(light_sleep_flg==1){ + os_printf("modem sleep en\r\n"); + wifi_set_sleep_type(MODEM_SLEEP_T); + light_sleep_flg =0; + } + } + light_set_aim(r,g,b,cw,ww,period); + return 0; +} + +LOCAL struct jsontree_callback light_callback = + JSONTREE_CALLBACK(light_status_get, light_status_set); + +JSONTREE_OBJECT(rgb_tree, + JSONTREE_PAIR("red", &light_callback), + JSONTREE_PAIR("green", &light_callback), + JSONTREE_PAIR("blue", &light_callback), + JSONTREE_PAIR("cwhite", &light_callback), + JSONTREE_PAIR("wwhite", &light_callback), + ); +JSONTREE_OBJECT(sta_tree, + JSONTREE_PAIR("period", &light_callback), + JSONTREE_PAIR("rgb", &rgb_tree)); +JSONTREE_OBJECT(PwmTree, + JSONTREE_PAIR("light", &sta_tree)); +#endif + +/****************************************************************************** + * FunctionName : wifi_station_get + * Description : set up the station paramer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +wifi_station_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + struct ip_info ipconfig; + uint8 buf[20]; + os_bzero(buf, sizeof(buf)); + wifi_station_get_config(sta_conf); + wifi_get_ip_info(STATION_IF, &ipconfig); + + if (os_strncmp(path, "ssid", 4) == 0) { + jsontree_write_string(js_ctx, sta_conf->ssid); + } else if (os_strncmp(path, "password", 8) == 0) { + jsontree_write_string(js_ctx, sta_conf->password); + } else if (os_strncmp(path, "ip", 2) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.ip)); + jsontree_write_string(js_ctx, buf); + } else if (os_strncmp(path, "mask", 4) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.netmask)); + jsontree_write_string(js_ctx, buf); + } else if (os_strncmp(path, "gw", 2) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.gw)); + jsontree_write_string(js_ctx, buf); + } + + return 0; +} + +/****************************************************************************** + * FunctionName : wifi_station_set + * Description : parse the station parmer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * parser -- A pointer to a JSON parser state + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +wifi_station_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser) +{ + int type; + uint8 station_tree; + + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_PAIR_NAME) { + char buffer[64]; + os_bzero(buffer, 64); + + if (jsonparse_strcmp_value(parser, "Station") == 0) { + station_tree = 1; + } else if (jsonparse_strcmp_value(parser, "Softap") == 0) { + station_tree = 0; + } + + if (station_tree) { + if (jsonparse_strcmp_value(parser, "ssid") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + os_memcpy(sta_conf->ssid, buffer, os_strlen(buffer)); + } else if (jsonparse_strcmp_value(parser, "password") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + os_memcpy(sta_conf->password, buffer, os_strlen(buffer)); + } + +#if ESP_PLATFORM + + else if (jsonparse_strcmp_value(parser, "token") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + user_esp_platform_set_token(buffer); + } + +#endif + } + } + } + + return 0; +} + +LOCAL struct jsontree_callback wifi_station_callback = + JSONTREE_CALLBACK(wifi_station_get, wifi_station_set); + +JSONTREE_OBJECT(get_station_config_tree, + JSONTREE_PAIR("ssid", &wifi_station_callback), + JSONTREE_PAIR("password", &wifi_station_callback)); +JSONTREE_OBJECT(set_station_config_tree, + JSONTREE_PAIR("ssid", &wifi_station_callback), + JSONTREE_PAIR("password", &wifi_station_callback), + JSONTREE_PAIR("token", &wifi_station_callback)); + +JSONTREE_OBJECT(ip_tree, + JSONTREE_PAIR("ip", &wifi_station_callback), + JSONTREE_PAIR("mask", &wifi_station_callback), + JSONTREE_PAIR("gw", &wifi_station_callback)); +JSONTREE_OBJECT(get_station_tree, + JSONTREE_PAIR("Connect_Station", &get_station_config_tree), + JSONTREE_PAIR("Ipinfo_Station", &ip_tree)); +JSONTREE_OBJECT(set_station_tree, + JSONTREE_PAIR("Connect_Station", &set_station_config_tree)); + +//JSONTREE_OBJECT(get_wifi_station_info_tree, +// JSONTREE_PAIR("Station", &get_station_tree)); +//JSONTREE_OBJECT(set_wifi_station_info_tree, +// JSONTREE_PAIR("station", &set_station_tree)); + +/****************************************************************************** + * FunctionName : wifi_softap_get + * Description : set up the softap paramer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +wifi_softap_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + struct ip_info ipconfig; + uint8 buf[20]; + os_bzero(buf, sizeof(buf)); + wifi_softap_get_config(ap_conf); + wifi_get_ip_info(SOFTAP_IF, &ipconfig); + + if (os_strncmp(path, "ssid", 4) == 0) { + jsontree_write_string(js_ctx, ap_conf->ssid); + } else if (os_strncmp(path, "password", 8) == 0) { + jsontree_write_string(js_ctx, ap_conf->password); + } else if (os_strncmp(path, "channel", 7) == 0) { + jsontree_write_int(js_ctx, ap_conf->channel); + } else if (os_strncmp(path, "authmode", 8) == 0) { + switch (ap_conf->authmode) { + case AUTH_OPEN: + jsontree_write_string(js_ctx, "OPEN"); + break; + + case AUTH_WEP: + jsontree_write_string(js_ctx, "WEP"); + break; + + case AUTH_WPA_PSK: + jsontree_write_string(js_ctx, "WPAPSK"); + break; + + case AUTH_WPA2_PSK: + jsontree_write_string(js_ctx, "WPA2PSK"); + break; + + case AUTH_WPA_WPA2_PSK: + jsontree_write_string(js_ctx, "WPAPSK/WPA2PSK"); + break; + + default : + jsontree_write_int(js_ctx, ap_conf->authmode); + break; + } + } else if (os_strncmp(path, "ip", 2) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.ip)); + jsontree_write_string(js_ctx, buf); + } else if (os_strncmp(path, "mask", 4) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.netmask)); + jsontree_write_string(js_ctx, buf); + } else if (os_strncmp(path, "gw", 2) == 0) { + os_sprintf(buf, IPSTR, IP2STR(&ipconfig.gw)); + jsontree_write_string(js_ctx, buf); + } + + return 0; +} + +/****************************************************************************** + * FunctionName : wifi_softap_set + * Description : parse the softap parmer as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * parser -- A pointer to a JSON parser state + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +wifi_softap_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser) +{ + int type; + uint8 softap_tree; + + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_PAIR_NAME) { + char buffer[64]; + os_bzero(buffer, 64); + + if (jsonparse_strcmp_value(parser, "Station") == 0) { + softap_tree = 0; + } else if (jsonparse_strcmp_value(parser, "Softap") == 0) { + softap_tree = 1; + } + + if (softap_tree) { + if (jsonparse_strcmp_value(parser, "authmode") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + + // other mode will be supported later... + if (os_strcmp(buffer, "OPEN") == 0) { + ap_conf->authmode = AUTH_OPEN; + } else if (os_strcmp(buffer, "WPAPSK") == 0) { + ap_conf->authmode = AUTH_WPA_PSK; + os_printf("%d %s\n", ap_conf->authmode, buffer); + } else if (os_strcmp(buffer, "WPA2PSK") == 0) { + ap_conf->authmode = AUTH_WPA2_PSK; + } else if (os_strcmp(buffer, "WPAPSK/WPA2PSK") == 0) { + ap_conf->authmode = AUTH_WPA_WPA2_PSK; + } else { + ap_conf->authmode = AUTH_OPEN; + return 0; + } + } + + if (jsonparse_strcmp_value(parser, "channel") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + ap_conf->channel = jsonparse_get_value_as_int(parser); + } else if (jsonparse_strcmp_value(parser, "ssid") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + os_memcpy(ap_conf->ssid, buffer, os_strlen(buffer)); + } else if (jsonparse_strcmp_value(parser, "password") == 0) { + jsonparse_next(parser); + jsonparse_next(parser); + jsonparse_copy_value(parser, buffer, sizeof(buffer)); + os_memcpy(ap_conf->password, buffer, os_strlen(buffer)); + } + } + } + } + + return 0; +} + +LOCAL struct jsontree_callback wifi_softap_callback = + JSONTREE_CALLBACK(wifi_softap_get, wifi_softap_set); + +JSONTREE_OBJECT(softap_config_tree, + JSONTREE_PAIR("authmode", &wifi_softap_callback), + JSONTREE_PAIR("channel", &wifi_softap_callback), + JSONTREE_PAIR("ssid", &wifi_softap_callback), + JSONTREE_PAIR("password", &wifi_softap_callback)); +JSONTREE_OBJECT(softap_ip_tree, + JSONTREE_PAIR("ip", &wifi_softap_callback), + JSONTREE_PAIR("mask", &wifi_softap_callback), + JSONTREE_PAIR("gw", &wifi_softap_callback)); +JSONTREE_OBJECT(get_softap_tree, + JSONTREE_PAIR("Connect_Softap", &softap_config_tree), + JSONTREE_PAIR("Ipinfo_Softap", &softap_ip_tree)); +JSONTREE_OBJECT(set_softap_tree, + JSONTREE_PAIR("Ipinfo_Softap", &softap_config_tree)); + +JSONTREE_OBJECT(get_wifi_tree, + JSONTREE_PAIR("Station", &get_station_tree), + JSONTREE_PAIR("Softap", &get_softap_tree)); +JSONTREE_OBJECT(set_wifi_tree, + JSONTREE_PAIR("Station", &set_station_tree), + JSONTREE_PAIR("Softap", &set_softap_tree)); + +JSONTREE_OBJECT(wifi_response_tree, + JSONTREE_PAIR("Response", &get_wifi_tree)); +JSONTREE_OBJECT(wifi_request_tree, + JSONTREE_PAIR("Request", &set_wifi_tree)); + +JSONTREE_OBJECT(wifi_info_tree, + JSONTREE_PAIR("wifi", &wifi_response_tree)); +JSONTREE_OBJECT(wifi_req_tree, + JSONTREE_PAIR("wifi", &wifi_request_tree)); + + +/****************************************************************************** + * FunctionName : scan_get + * Description : set up the scan data as a JSON format + * Parameters : js_ctx -- A pointer to a JSON set up + * Returns : result +*******************************************************************************/ +LOCAL int ICACHE_FLASH_ATTR +scan_get(struct jsontree_context *js_ctx) +{ + const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); + // STAILQ_HEAD(, bss_info) *pbss = scanarg; +// LOCAL struct bss_info *bss; + + if (os_strncmp(path, "TotalPage", 9) == 0) { + jsontree_write_int(js_ctx, pscaninfo->totalpage); + } else if (os_strncmp(path, "PageNum", 7) == 0) { + jsontree_write_int(js_ctx, pscaninfo->pagenum); + } else if (os_strncmp(path, "bssid", 5) == 0) { + if( bss == NULL ) + bss = bss_head; + u8 buffer[32]; + //if (bss != NULL){ + os_memset(buffer, 0, sizeof(buffer)); + os_sprintf(buffer, MACSTR, MAC2STR(bss->bssid)); + jsontree_write_string(js_ctx, buffer); + //} + } else if (os_strncmp(path, "ssid", 4) == 0) { + //if (bss != NULL) + jsontree_write_string(js_ctx, bss->ssid); + } else if (os_strncmp(path, "rssi", 4) == 0) { + //if (bss != NULL) + jsontree_write_int(js_ctx, -(bss->rssi)); + } else if (os_strncmp(path, "channel", 7) == 0) { + //if (bss != NULL) + jsontree_write_int(js_ctx, bss->channel); + } else if (os_strncmp(path, "authmode", 8) == 0) { + //if (bss != NULL){ + switch (bss->authmode) { + case AUTH_OPEN: + jsontree_write_string(js_ctx, "OPEN"); + break; + + case AUTH_WEP: + jsontree_write_string(js_ctx, "WEP"); + break; + + case AUTH_WPA_PSK: + jsontree_write_string(js_ctx, "WPAPSK"); + break; + + case AUTH_WPA2_PSK: + jsontree_write_string(js_ctx, "WPA2PSK"); + break; + + case AUTH_WPA_WPA2_PSK: + jsontree_write_string(js_ctx, "WPAPSK/WPA2PSK"); + break; + + default : + jsontree_write_int(js_ctx, bss->authmode); + break; + } + + bss = STAILQ_NEXT(bss, next); +// os_free(bss); + //} + } + + return 0; +} + +LOCAL struct jsontree_callback scan_callback = + JSONTREE_CALLBACK(scan_get, NULL); + +JSONTREE_OBJECT(scaninfo_tree, + JSONTREE_PAIR("bssid", &scan_callback), + JSONTREE_PAIR("ssid", &scan_callback), + JSONTREE_PAIR("rssi", &scan_callback), + JSONTREE_PAIR("channel", &scan_callback), + JSONTREE_PAIR("authmode", &scan_callback)); +JSONTREE_ARRAY(scanrslt_tree, + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree), + JSONTREE_PAIR_ARRAY(&scaninfo_tree)); + +JSONTREE_OBJECT(scantree, + JSONTREE_PAIR("TotalPage", &scan_callback), + JSONTREE_PAIR("PageNum", &scan_callback), + JSONTREE_PAIR("ScanResult", &scanrslt_tree)); +JSONTREE_OBJECT(scanres_tree, + JSONTREE_PAIR("Response", &scantree)); +JSONTREE_OBJECT(scan_tree, + JSONTREE_PAIR("scan", &scanres_tree)); + +/****************************************************************************** + * FunctionName : parse_url + * Description : parse the received data from the server + * Parameters : precv -- the received data + * purl_frame -- the result of parsing the url + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +parse_url(char *precv, URL_Frame *purl_frame) +{ + char *str = NULL; + uint8 length = 0; + char *pbuffer = NULL; + char *pbufer = NULL; + + if (purl_frame == NULL || precv == NULL) { + return; + } + + pbuffer = (char *)os_strstr(precv, "Host:"); + + if (pbuffer != NULL) { + length = pbuffer - precv; + pbufer = (char *)os_zalloc(length + 1); + pbuffer = pbufer; + os_memcpy(pbuffer, precv, length); + os_memset(purl_frame->pSelect, 0, URLSize); + os_memset(purl_frame->pCommand, 0, URLSize); + os_memset(purl_frame->pFilename, 0, URLSize); + + if (os_strncmp(pbuffer, "GET ", 4) == 0) { + purl_frame->Type = GET; + pbuffer += 4; + } else if (os_strncmp(pbuffer, "POST ", 5) == 0) { + purl_frame->Type = POST; + pbuffer += 5; + } + + pbuffer ++; + str = (char *)os_strstr(pbuffer, "?"); + + if (str != NULL) { + length = str - pbuffer; + os_memcpy(purl_frame->pSelect, pbuffer, length); + str ++; + pbuffer = (char *)os_strstr(str, "="); + + if (pbuffer != NULL) { + length = pbuffer - str; + os_memcpy(purl_frame->pCommand, str, length); + pbuffer ++; + str = (char *)os_strstr(pbuffer, "&"); + + if (str != NULL) { + length = str - pbuffer; + os_memcpy(purl_frame->pFilename, pbuffer, length); + } else { + str = (char *)os_strstr(pbuffer, " HTTP"); + + if (str != NULL) { + length = str - pbuffer; + os_memcpy(purl_frame->pFilename, pbuffer, length); + } + } + } + } + + os_free(pbufer); + } else { + return; + } +} + +LOCAL char *precvbuffer; +static uint32 dat_sumlength = 0; +LOCAL bool ICACHE_FLASH_ATTR +save_data(char *precv, uint16 length) +{ + bool flag = false; + char length_buf[10] = {0}; + char *ptemp = NULL; + char *pdata = NULL; + uint16 headlength = 0; + static uint32 totallength = 0; + + ptemp = (char *)os_strstr(precv, "\r\n\r\n"); + + if (ptemp != NULL) { + length -= ptemp - precv; + length -= 4; + totallength += length; + headlength = ptemp - precv + 4; + pdata = (char *)os_strstr(precv, "Content-Length: "); + + if (pdata != NULL) { + pdata += 16; + precvbuffer = (char *)os_strstr(pdata, "\r\n"); + + if (precvbuffer != NULL) { + os_memcpy(length_buf, pdata, precvbuffer - pdata); + dat_sumlength = atoi(length_buf); + } + } else { + if (totallength != 0x00){ + totallength = 0; + dat_sumlength = 0; + return false; + } + } + if ((dat_sumlength + headlength) >= 1024) { + precvbuffer = (char *)os_zalloc(headlength + 1); + os_memcpy(precvbuffer, precv, headlength + 1); + } else { + precvbuffer = (char *)os_zalloc(dat_sumlength + headlength + 1); + os_memcpy(precvbuffer, precv, os_strlen(precv)); + } + } else { + if (precvbuffer != NULL) { + totallength += length; + os_memcpy(precvbuffer + os_strlen(precvbuffer), precv, length); + } else { + totallength = 0; + dat_sumlength = 0; + return false; + } + } + + if (totallength == dat_sumlength) { + totallength = 0; + dat_sumlength = 0; + return true; + } else { + return false; + } +} + +LOCAL bool ICACHE_FLASH_ATTR +check_data(char *precv, uint16 length) +{ + //bool flag = true; + char length_buf[10] = {0}; + char *ptemp = NULL; + char *pdata = NULL; + char *tmp_precvbuffer; + uint16 tmp_length = length; + uint32 tmp_totallength = 0; + + ptemp = (char *)os_strstr(precv, "\r\n\r\n"); + + if (ptemp != NULL) { + tmp_length -= ptemp - precv; + tmp_length -= 4; + tmp_totallength += tmp_length; + + pdata = (char *)os_strstr(precv, "Content-Length: "); + + if (pdata != NULL){ + pdata += 16; + tmp_precvbuffer = (char *)os_strstr(pdata, "\r\n"); + + if (tmp_precvbuffer != NULL){ + os_memcpy(length_buf, pdata, tmp_precvbuffer - pdata); + dat_sumlength = atoi(length_buf); + os_printf("A_dat:%u,tot:%u,lenght:%u\n",dat_sumlength,tmp_totallength,tmp_length); + if(dat_sumlength != tmp_totallength){ + return false; + } + } + } + } + return true; +} + +LOCAL os_timer_t *restart_10ms; +LOCAL rst_parm *rstparm; + +/****************************************************************************** + * FunctionName : restart_10ms_cb + * Description : system restart or wifi reconnected after a certain time. + * Parameters : arg -- Additional argument to pass to the function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +restart_10ms_cb(void *arg) +{ + if (rstparm != NULL && rstparm->pespconn != NULL) { + switch (rstparm->parmtype) { + case WIFI: + //if (rstparm->pespconn->state == ESPCONN_CLOSE) { + if (sta_conf->ssid[0] != 0x00) { + wifi_station_set_config(sta_conf); + wifi_station_disconnect(); + wifi_station_connect(); + user_esp_platform_check_ip(1); + } + + if (ap_conf->ssid[0] != 0x00) { + wifi_softap_set_config(ap_conf); + system_restart(); + } + + os_free(ap_conf); + ap_conf = NULL; + os_free(sta_conf); + sta_conf = NULL; + os_free(rstparm); + rstparm = NULL; + os_free(restart_10ms); + restart_10ms = NULL; + //} else { + // os_timer_arm(restart_10ms, 10, 0); + //} + + break; + + case DEEP_SLEEP: + case REBOOT: + if (rstparm->pespconn->state == ESPCONN_CLOSE) { + wifi_set_opmode(STATION_MODE); + + if (rstparm->parmtype == DEEP_SLEEP) { +#if SENSOR_DEVICE + system_deep_sleep(SENSOR_DEEP_SLEEP_TIME); +#endif + } + } else { + os_timer_arm(restart_10ms, 10, 0); + } + + break; + + default: + break; + } + } +} + +/****************************************************************************** + * FunctionName : data_send + * Description : processing the data as http format and send to the client or server + * Parameters : arg -- argument to set for client or server + * responseOK -- true or false + * psend -- The send data + * Returns : +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +data_send(void *arg, bool responseOK, char *psend) +{ + uint16 length = 0; + char *pbuf = NULL; + char httphead[256]; + struct espconn *ptrespconn = arg; + os_memset(httphead, 0, 256); + + if (responseOK) { + os_sprintf(httphead, + "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n", + psend ? os_strlen(psend) : 0); + + if (psend) { + os_sprintf(httphead + os_strlen(httphead), + "Content-type: application/json\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"); + length = os_strlen(httphead) + os_strlen(psend); + pbuf = (char *)os_zalloc(length + 1); + os_memcpy(pbuf, httphead, os_strlen(httphead)); + os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend)); + } else { + os_sprintf(httphead + os_strlen(httphead), "\n"); + length = os_strlen(httphead); + } + } else { + os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\ +Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n"); + length = os_strlen(httphead); + } + + if (psend) { +#ifdef SERVER_SSL_ENABLE + espconn_secure_sent(ptrespconn, pbuf, length); +#else + espconn_sent(ptrespconn, pbuf, length); +#endif + } else { +#ifdef SERVER_SSL_ENABLE + espconn_secure_sent(ptrespconn, httphead, length); +#else + espconn_sent(ptrespconn, httphead, length); +#endif + } + + if (pbuf) { + os_free(pbuf); + pbuf = NULL; + } +} + +/****************************************************************************** + * FunctionName : json_send + * Description : processing the data as json format and send to the client or server + * Parameters : arg -- argument to set for client or server + * ParmType -- json format type + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +json_send(void *arg, ParmType ParmType) +{ + char *pbuf = NULL; + pbuf = (char *)os_zalloc(jsonSize); + struct espconn *ptrespconn = arg; + + switch (ParmType) { +#if LIGHT_DEVICE + + case LIGHT_STATUS: + json_ws_send((struct jsontree_value *)&PwmTree, "light", pbuf); + break; +#endif + +#if PLUG_DEVICE + + case SWITCH_STATUS: + json_ws_send((struct jsontree_value *)&StatusTree, "switch", pbuf); + break; +#endif + + case INFOMATION: + json_ws_send((struct jsontree_value *)&INFOTree, "info", pbuf); + break; + + case WIFI: + json_ws_send((struct jsontree_value *)&wifi_info_tree, "wifi", pbuf); + break; + + case CONNECT_STATUS: + json_ws_send((struct jsontree_value *)&con_status_tree, "info", pbuf); + break; + + case USER_BIN: + json_ws_send((struct jsontree_value *)&userinfo_tree, "user_info", pbuf); + break; + case SCAN: { + u8 i = 0; + u8 scancount = 0; + struct bss_info *bss = NULL; +// bss = STAILQ_FIRST(pscaninfo->pbss); + bss = bss_head; + if (bss == NULL) { + os_free(pscaninfo); + pscaninfo = NULL; + os_sprintf(pbuf, "{\n\"successful\": false,\n\"data\": null\n}"); + } else { + do { + if (pscaninfo->page_sn == pscaninfo->pagenum) { + pscaninfo->page_sn = 0; + os_sprintf(pbuf, "{\n\"successful\": false,\n\"meessage\": \"repeated page\"\n}"); + break; + } + + scancount = scannum - (pscaninfo->pagenum - 1) * 8; + + if (scancount >= 8) { + pscaninfo->data_cnt += 8; + pscaninfo->page_sn = pscaninfo->pagenum; + + if (pscaninfo->data_cnt > scannum) { + pscaninfo->data_cnt -= 8; + os_sprintf(pbuf, "{\n\"successful\": false,\n\"meessage\": \"error page\"\n}"); + break; + } + + json_ws_send((struct jsontree_value *)&scan_tree, "scan", pbuf); + } else { + pscaninfo->data_cnt += scancount; + pscaninfo->page_sn = pscaninfo->pagenum; + + if (pscaninfo->data_cnt > scannum) { + pscaninfo->data_cnt -= scancount; + os_sprintf(pbuf, "{\n\"successful\": false,\n\"meessage\": \"error page\"\n}"); + break; + } + + char *ptrscanbuf = (char *)os_zalloc(jsonSize); + char *pscanbuf = ptrscanbuf; + os_sprintf(pscanbuf, ",\n\"ScanResult\": [\n"); + pscanbuf += os_strlen(pscanbuf); + + for (i = 0; i < scancount; i ++) { + JSONTREE_OBJECT(page_tree, + JSONTREE_PAIR("page", &scaninfo_tree)); + json_ws_send((struct jsontree_value *)&page_tree, "page", pscanbuf); + os_sprintf(pscanbuf + os_strlen(pscanbuf), ",\n"); + pscanbuf += os_strlen(pscanbuf); + } + + os_sprintf(pscanbuf - 2, "]\n"); + JSONTREE_OBJECT(scantree, + JSONTREE_PAIR("TotalPage", &scan_callback), + JSONTREE_PAIR("PageNum", &scan_callback)); + JSONTREE_OBJECT(scanres_tree, + JSONTREE_PAIR("Response", &scantree)); + JSONTREE_OBJECT(scan_tree, + JSONTREE_PAIR("scan", &scanres_tree)); + json_ws_send((struct jsontree_value *)&scan_tree, "scan", pbuf); + os_memcpy(pbuf + os_strlen(pbuf) - 4, ptrscanbuf, os_strlen(ptrscanbuf)); + os_sprintf(pbuf + os_strlen(pbuf), "}\n}"); + os_free(ptrscanbuf); + } + } while (0); + } + + break; + } + + default : + break; + } + + data_send(ptrespconn, true, pbuf); + os_free(pbuf); + pbuf = NULL; +} + +/****************************************************************************** + * FunctionName : response_send + * Description : processing the send result + * Parameters : arg -- argument to set for client or server + * responseOK -- true or false + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +response_send(void *arg, bool responseOK) +{ + struct espconn *ptrespconn = arg; + + data_send(ptrespconn, responseOK, NULL); +} + +/****************************************************************************** + * FunctionName : json_scan_cb + * Description : processing the scan result + * Parameters : arg -- Additional argument to pass to the callback function + * status -- scan status + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR json_scan_cb(void *arg, STATUS status) +{ + pscaninfo->pbss = arg; + + if (scannum % 8 == 0) { + pscaninfo->totalpage = scannum / 8; + } else { + pscaninfo->totalpage = scannum / 8 + 1; + } + + JSONTREE_OBJECT(totaltree, + JSONTREE_PAIR("TotalPage", &scan_callback)); + JSONTREE_OBJECT(totalres_tree, + JSONTREE_PAIR("Response", &totaltree)); + JSONTREE_OBJECT(total_tree, + JSONTREE_PAIR("total", &totalres_tree)); + + bss_temp = bss_head; + while(bss_temp !=NULL) { + bss_head = bss_temp->next.stqe_next; + os_free(bss_temp); + bss_temp = bss_head; + } + bss_head = NULL; + bss_temp = NULL; + bss = STAILQ_FIRST(pscaninfo->pbss); + while(bss != NULL) { + if(bss_temp == NULL){ + bss_temp = (struct bss_info *)os_zalloc(sizeof(struct bss_info)); + bss_head = bss_temp; + } else { + bss_temp->next.stqe_next = (struct bss_info *)os_zalloc(sizeof(struct bss_info)); + bss_temp = bss_temp->next.stqe_next; + } + if(bss_temp == NULL) { + os_printf("malloc scan info failed\n"); + break; + } else{ + os_memcpy(bss_temp->bssid,bss->bssid,sizeof(bss->bssid)); + os_memcpy(bss_temp->ssid,bss->ssid,sizeof(bss->ssid)); + bss_temp->authmode = bss->authmode; + bss_temp->rssi = bss->rssi; + bss_temp->channel = bss->channel; + } + bss = STAILQ_NEXT(bss,next); + } + char *pbuf = NULL; + pbuf = (char *)os_zalloc(jsonSize); + json_ws_send((struct jsontree_value *)&total_tree, "total", pbuf); + data_send(pscaninfo->pespconn, true, pbuf); + os_free(pbuf); +} + +void ICACHE_FLASH_ATTR +upgrade_check_func(void *arg) +{ + struct espconn *ptrespconn = arg; + os_timer_disarm(&upgrade_check_timer); + if(system_upgrade_flag_check() == UPGRADE_FLAG_START) { + response_send(ptrespconn, false); + system_upgrade_deinit(); + system_upgrade_flag_set(UPGRADE_FLAG_IDLE); + upgrade_lock = 0; + os_printf("local upgrade failed\n"); + } else if( system_upgrade_flag_check() == UPGRADE_FLAG_FINISH ) { + os_printf("local upgrade success\n"); + response_send(ptrespconn, true); + upgrade_lock = 0; + } else { + + } + + +} +/****************************************************************************** + * FunctionName : upgrade_deinit + * Description : disconnect the connection with the host + * Parameters : bin -- server number + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +LOCAL local_upgrade_deinit(void) +{ + if (system_upgrade_flag_check() != UPGRADE_FLAG_START) { + os_printf("system upgrade deinit\n"); + system_upgrade_deinit(); + } +} + + +/****************************************************************************** + * FunctionName : upgrade_download + * Description : Processing the upgrade data from the host + * Parameters : bin -- server number + * pusrdata -- The upgrade data (or NULL when the connection has been closed!) + * length -- The length of upgrade data + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +local_upgrade_download(void * arg,char *pusrdata, unsigned short length) +{ + char *ptr = NULL; + char *ptmp2 = NULL; + char lengthbuffer[32]; + static uint32 totallength = 0; + static uint32 sumlength = 0; + static uint32 erase_length = 0; + char A_buf[2] = {0xE9 ,0x03}; char B_buf[2] = {0xEA,0x04}; + struct espconn *pespconn = arg; + if (totallength == 0 && (ptr = (char *)os_strstr(pusrdata, "\r\n\r\n")) != NULL && + (ptr = (char *)os_strstr(pusrdata, "Content-Length")) != NULL) { + ptr = (char *)os_strstr(pusrdata, "Content-Length: "); + if (ptr != NULL) { + ptr += 16; + ptmp2 = (char *)os_strstr(ptr, "\r\n"); + + if (ptmp2 != NULL) { + os_memset(lengthbuffer, 0, sizeof(lengthbuffer)); + os_memcpy(lengthbuffer, ptr, ptmp2 - ptr); + sumlength = atoi(lengthbuffer); + if (sumlength == 0) { + os_timer_disarm(&upgrade_check_timer); + os_timer_setfn(&upgrade_check_timer, (os_timer_func_t *)upgrade_check_func, pespconn); + os_timer_arm(&upgrade_check_timer, 10, 0); + return; + } + } else { + os_printf("sumlength failed\n"); + } + } else { + os_printf("Content-Length: failed\n"); + } + if (sumlength != 0) { + if (sumlength >= LIMIT_ERASE_SIZE){ + system_upgrade_erase_flash(0xFFFF); + erase_length = sumlength - LIMIT_ERASE_SIZE; + } else { + system_upgrade_erase_flash(sumlength); + erase_length = 0; + } + } + ptr = (char *)os_strstr(pusrdata, "\r\n\r\n"); + length -= ptr - pusrdata; + length -= 4; + totallength += length; + os_printf("upgrade file download start.\n"); + system_upgrade(ptr + 4, length); + + } else { + totallength += length; + if (erase_length >= LIMIT_ERASE_SIZE){ + system_upgrade_erase_flash(0xFFFF); + erase_length -= LIMIT_ERASE_SIZE; + } else { + system_upgrade_erase_flash(erase_length); + erase_length = 0; + } + system_upgrade(pusrdata, length); + } + + if (totallength == sumlength) { + os_printf("upgrade file download finished.\n"); + system_upgrade_flag_set(UPGRADE_FLAG_FINISH); + totallength = 0; + sumlength = 0; + upgrade_check_func(pespconn); + os_timer_disarm(&app_upgrade_10s); + os_timer_setfn(&app_upgrade_10s, (os_timer_func_t *)local_upgrade_deinit, NULL); + os_timer_arm(&app_upgrade_10s, 10, 0); + } +} + +/****************************************************************************** + * FunctionName : webserver_recv + * Description : Processing the received data from the server + * Parameters : arg -- Additional argument to pass to the callback function + * pusrdata -- The received data (or NULL when the connection has been closed!) + * length -- The length of received data + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +webserver_recv(void *arg, char *pusrdata, unsigned short length) +{ + URL_Frame *pURL_Frame = NULL; + char *pParseBuffer = NULL; + bool parse_flag = false; + struct espconn *ptrespconn = arg; + + if(upgrade_lock == 0){ + + os_printf("len:%u\n",length); + if(check_data(pusrdata, length) == false) + { + os_printf("goto\n"); + goto _temp_exit; + } + + parse_flag = save_data(pusrdata, length); + if (parse_flag == false) { + response_send(ptrespconn, false); + } + +// os_printf(precvbuffer); + pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame)); + parse_url(precvbuffer, pURL_Frame); + + switch (pURL_Frame->Type) { + case GET: + os_printf("We have a GET request.\n"); + + if (os_strcmp(pURL_Frame->pSelect, "client") == 0 && + os_strcmp(pURL_Frame->pCommand, "command") == 0) { + if (os_strcmp(pURL_Frame->pFilename, "info") == 0) { + json_send(ptrespconn, INFOMATION); + } + + if (os_strcmp(pURL_Frame->pFilename, "status") == 0) { + json_send(ptrespconn, CONNECT_STATUS); + } else if (os_strcmp(pURL_Frame->pFilename, "scan") == 0) { + char *strstr = NULL; + strstr = (char *)os_strstr(pusrdata, "&"); + + if (strstr == NULL) { + if (pscaninfo == NULL) { + pscaninfo = (scaninfo *)os_zalloc(sizeof(scaninfo)); + } + + pscaninfo->pespconn = ptrespconn; + pscaninfo->pagenum = 0; + pscaninfo->page_sn = 0; + pscaninfo->data_cnt = 0; + wifi_station_scan(NULL, json_scan_cb); + } else { + strstr ++; + + if (os_strncmp(strstr, "page", 4) == 0) { + if (pscaninfo != NULL) { + pscaninfo->pagenum = *(strstr + 5); + pscaninfo->pagenum -= 0x30; + + if (pscaninfo->pagenum > pscaninfo->totalpage || pscaninfo->pagenum == 0) { + response_send(ptrespconn, false); + } else { + json_send(ptrespconn, SCAN); + } + } else { + response_send(ptrespconn, false); + } + } else if(os_strncmp(strstr, "finish", 6) == 0){ + bss_temp = bss_head; + while(bss_temp != NULL) { + bss_head = bss_temp->next.stqe_next; + os_free(bss_temp); + bss_temp = bss_head; + } + bss_head = NULL; + bss_temp = NULL; + response_send(ptrespconn, true); + } else { + response_send(ptrespconn, false); + } + } + } else { + response_send(ptrespconn, false); + } + } else if (os_strcmp(pURL_Frame->pSelect, "config") == 0 && + os_strcmp(pURL_Frame->pCommand, "command") == 0) { + if (os_strcmp(pURL_Frame->pFilename, "wifi") == 0) { + ap_conf = (struct softap_config *)os_zalloc(sizeof(struct softap_config)); + sta_conf = (struct station_config *)os_zalloc(sizeof(struct station_config)); + json_send(ptrespconn, WIFI); + os_free(sta_conf); + os_free(ap_conf); + sta_conf = NULL; + ap_conf = NULL; + } + +#if PLUG_DEVICE + else if (os_strcmp(pURL_Frame->pFilename, "switch") == 0) { + json_send(ptrespconn, SWITCH_STATUS); + } + +#endif + +#if LIGHT_DEVICE + else if (os_strcmp(pURL_Frame->pFilename, "light") == 0) { + json_send(ptrespconn, LIGHT_STATUS); + } + + +#endif + + else if (os_strcmp(pURL_Frame->pFilename, "reboot") == 0) { + json_send(ptrespconn, REBOOT); + } else { + response_send(ptrespconn, false); + } + } else if (os_strcmp(pURL_Frame->pSelect, "upgrade") == 0 && + os_strcmp(pURL_Frame->pCommand, "command") == 0) { + if (os_strcmp(pURL_Frame->pFilename, "getuser") == 0) { + json_send(ptrespconn , USER_BIN); + } + } else { + response_send(ptrespconn, false); + } + + break; + + case POST: + os_printf("We have a POST request.\n"); + pParseBuffer = (char *)os_strstr(precvbuffer, "\r\n\r\n"); + + if (pParseBuffer == NULL) { + break; + } + + pParseBuffer += 4; + + if (os_strcmp(pURL_Frame->pSelect, "config") == 0 && + os_strcmp(pURL_Frame->pCommand, "command") == 0) { +#if SENSOR_DEVICE + + if (os_strcmp(pURL_Frame->pFilename, "sleep") == 0) { +#else + + if (os_strcmp(pURL_Frame->pFilename, "reboot") == 0) { +#endif + + if (pParseBuffer != NULL) { + if (restart_10ms != NULL) { + os_timer_disarm(restart_10ms); + } + + if (rstparm == NULL) { + rstparm = (rst_parm *)os_zalloc(sizeof(rst_parm)); + } + + rstparm->pespconn = ptrespconn; +#if SENSOR_DEVICE + rstparm->parmtype = DEEP_SLEEP; +#else + rstparm->parmtype = REBOOT; +#endif + + if (restart_10ms == NULL) { + restart_10ms = (os_timer_t *)os_malloc(sizeof(os_timer_t)); + } + + os_timer_setfn(restart_10ms, (os_timer_func_t *)restart_10ms_cb, NULL); + os_timer_arm(restart_10ms, 10, 0); // delay 10ms, then do + + response_send(ptrespconn, true); + } else { + response_send(ptrespconn, false); + } + } else if (os_strcmp(pURL_Frame->pFilename, "wifi") == 0) { + if (pParseBuffer != NULL) { + struct jsontree_context js; + user_esp_platform_set_connect_status(DEVICE_CONNECTING); + + if (restart_10ms != NULL) { + os_timer_disarm(restart_10ms); + } + + if (ap_conf == NULL) { + ap_conf = (struct softap_config *)os_zalloc(sizeof(struct softap_config)); + } + + if (sta_conf == NULL) { + sta_conf = (struct station_config *)os_zalloc(sizeof(struct station_config)); + } + + jsontree_setup(&js, (struct jsontree_value *)&wifi_req_tree, json_putchar); + json_parse(&js, pParseBuffer); + + if (rstparm == NULL) { + rstparm = (rst_parm *)os_zalloc(sizeof(rst_parm)); + } + + rstparm->pespconn = ptrespconn; + rstparm->parmtype = WIFI; + + if (sta_conf->ssid[0] != 0x00 || ap_conf->ssid[0] != 0x00) { + ap_conf->ssid_hidden = 0; + ap_conf->max_connection = 4; + + if (restart_10ms == NULL) { + restart_10ms = (os_timer_t *)os_malloc(sizeof(os_timer_t)); + } + + os_timer_disarm(restart_10ms); + os_timer_setfn(restart_10ms, (os_timer_func_t *)restart_10ms_cb, NULL); + os_timer_arm(restart_10ms, 10, 0); // delay 10ms, then do + } else { + os_free(ap_conf); + os_free(sta_conf); + os_free(rstparm); + sta_conf = NULL; + ap_conf = NULL; + rstparm =NULL; + } + + response_send(ptrespconn, true); + } else { + response_send(ptrespconn, false); + } + } + +#if PLUG_DEVICE + else if (os_strcmp(pURL_Frame->pFilename, "switch") == 0) { + if (pParseBuffer != NULL) { + struct jsontree_context js; + jsontree_setup(&js, (struct jsontree_value *)&StatusTree, json_putchar); + json_parse(&js, pParseBuffer); + response_send(ptrespconn, true); + } else { + response_send(ptrespconn, false); + } + } + +#endif + +#if LIGHT_DEVICE + else if (os_strcmp(pURL_Frame->pFilename, "light") == 0) { + if (pParseBuffer != NULL) { + struct jsontree_context js; + + jsontree_setup(&js, (struct jsontree_value *)&PwmTree, json_putchar); + json_parse(&js, pParseBuffer); + + os_printf("rsp1:%u\n",PostCmdNeeRsp); + if(PostCmdNeeRsp == 0) + PostCmdNeeRsp = 1; + else + response_send(ptrespconn, true); + } else { + response_send(ptrespconn, false); + } + } + else if (os_strcmp(pURL_Frame->pFilename, "reset") == 0) { + response_send(ptrespconn, true); + extern struct esp_platform_saved_param esp_param; + esp_param.activeflag = 0; + system_param_save_with_protect(ESP_PARAM_START_SEC, &esp_param, sizeof(esp_param)); + + system_restore(); + system_restart(); + } + +#endif + else { + response_send(ptrespconn, false); + } + } + else if(os_strcmp(pURL_Frame->pSelect, "upgrade") == 0 && + os_strcmp(pURL_Frame->pCommand, "command") == 0){ + if (os_strcmp(pURL_Frame->pFilename, "start") == 0){ + response_send(ptrespconn, true); + os_printf("local upgrade start\n"); + upgrade_lock = 1; + system_upgrade_init(); + system_upgrade_flag_set(UPGRADE_FLAG_START); + os_timer_disarm(&upgrade_check_timer); + os_timer_setfn(&upgrade_check_timer, (os_timer_func_t *)upgrade_check_func, NULL); + os_timer_arm(&upgrade_check_timer, 120000, 0); + } else if (os_strcmp(pURL_Frame->pFilename, "reset") == 0) { + + response_send(ptrespconn, true); + os_printf("local upgrade restart\n"); + system_upgrade_reboot(); + } else { + response_send(ptrespconn, false); + } + }else { + response_send(ptrespconn, false); + } + break; + } + + if (precvbuffer != NULL){ + os_free(precvbuffer); + precvbuffer = NULL; + } + os_free(pURL_Frame); + pURL_Frame = NULL; + _temp_exit: + ; + } + else if(upgrade_lock == 1){ + local_upgrade_download(ptrespconn,pusrdata, length); + if (precvbuffer != NULL){ + os_free(precvbuffer); + precvbuffer = NULL; + } + os_free(pURL_Frame); + pURL_Frame = NULL; + } +} + +/****************************************************************************** + * FunctionName : webserver_recon + * Description : the connection has been err, reconnection + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL ICACHE_FLASH_ATTR +void webserver_recon(void *arg, sint8 err) +{ + struct espconn *pesp_conn = arg; + + os_printf("webserver's %d.%d.%d.%d:%d err %d reconnect\n", pesp_conn->proto.tcp->remote_ip[0], + pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], + pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port, err); +} + +/****************************************************************************** + * FunctionName : webserver_recon + * Description : the connection has been err, reconnection + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL ICACHE_FLASH_ATTR +void webserver_discon(void *arg) +{ + struct espconn *pesp_conn = arg; + + os_printf("webserver's %d.%d.%d.%d:%d disconnect\n", pesp_conn->proto.tcp->remote_ip[0], + pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], + pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port); +} + +/****************************************************************************** + * FunctionName : user_accept_listen + * Description : server listened a connection successfully + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +webserver_listen(void *arg) +{ + struct espconn *pesp_conn = arg; + + espconn_regist_recvcb(pesp_conn, webserver_recv); + espconn_regist_reconcb(pesp_conn, webserver_recon); + espconn_regist_disconcb(pesp_conn, webserver_discon); +} + +/****************************************************************************** + * FunctionName : user_webserver_init + * Description : parameter initialize as a server + * Parameters : port -- server port + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +user_webserver_init(uint32 port) +{ + LOCAL struct espconn esp_conn; + LOCAL esp_tcp esptcp; + + esp_conn.type = ESPCONN_TCP; + esp_conn.state = ESPCONN_NONE; + esp_conn.proto.tcp = &esptcp; + esp_conn.proto.tcp->local_port = port; + espconn_regist_connectcb(&esp_conn, webserver_listen); + +#ifdef SERVER_SSL_ENABLE + espconn_secure_set_default_certificate(default_certificate, default_certificate_len); + espconn_secure_set_default_private_key(default_private_key, default_private_key_len); + espconn_secure_accept(&esp_conn); +#else + espconn_accept(&esp_conn); +#endif +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/!!!readme!!!.txt b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/!!!readme!!!.txt new file mode 100644 index 0000000000..d91f947d7b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/!!!readme!!!.txt @@ -0,0 +1,42 @@ +Notice: AT added some functions so it's larger than before, if you want to compile it, please compile it as 1024KB or larger flash in compilation STEP 5. + +1¡¢compile options + +(1) COMPILE + Possible value: gcc + Default value: + If not set, use xt-xcc by default. + +(2) BOOT + Possible value: none/old/new + none: no need boot + old: use boot_v1.1 + new: use boot_v1.2+ + Default value: none + +(3) APP + Possible value: 0/1/2 + 0: original mode, generate eagle.app.v6.flash.bin and eagle.app.v6.irom0text.bin + 1: generate user1 + 2: generate user2 + Default value: 0 + +(3) SPI_SPEED + Possible value: 20/26.7/40/80 + Default value: 40 + +(4) SPI_MODE + Possible value: QIO/QOUT/DIO/DOUT + Default value: QIO + +(4) SPI_SIZE + Possible value: 0/2/3/4/5/6 + Default value: 0 + +For example: + make COMPILE=gcc BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=0 + +2¡¢You can also use gen_misc to make and generate specific bin you needed. + Linux: ./gen_misc.sh + Windows: gen_misc.bat + Follow the tips and steps. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/Makefile new file mode 100644 index 0000000000..bdfc1697f7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/Makefile @@ -0,0 +1,154 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user +ifdef AT_OPEN_SRC +SUBDIRS += \ + at +endif +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +ifdef AT_OPEN_SRC +COMPONENTS_eagle.app.v6 += \ + at/libat.a +endif + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lupgrade \ + -lssl \ + -lwps \ + -lsmartconfig \ + -lairkiss \ + $(DEP_LIBS_eagle.app.v6) + +ifndef AT_OPEN_SRC +LINKFLAGS_eagle.app.v6 += \ + -lat +endif + +LINKFLAGS_eagle.app.v6 += \ + -Wl,--end-group +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH +ifdef AT_OPEN_SRC +CONFIGURATION_DEFINES += \ + -DAT_OPEN_SRC +endif + +ifeq ($(APP),0) +else +CONFIGURATION_DEFINES += \ + -DAT_UPGRADE_SUPPORT +endif + +ifeq ($(SPI_SIZE_MAP),5) +CONFIGURATION_DEFINES += -DFLASH_MAP=$(SPI_SIZE_MAP) +endif + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.sh new file mode 100644 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/include/user_config.h new file mode 100644 index 0000000000..60ebcbf119 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/include/user_config.h @@ -0,0 +1,36 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define AT_CUSTOM_UPGRADE + +#ifdef AT_CUSTOM_UPGRADE + #ifndef AT_UPGRADE_SUPPORT + #error "upgrade is not supported when eagle.flash.bin+eagle.irom0text.bin!!!" + #endif +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/at_upgrade.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/at_upgrade.c new file mode 100644 index 0000000000..7a14fed98b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/at_upgrade.c @@ -0,0 +1,304 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "c_types.h" +#include "user_interface.h" +#include "espconn.h" +#include "mem.h" +#include "osapi.h" +#include "upgrade.h" + +#ifdef AT_UPGRADE_SUPPORT +#ifdef AT_CUSTOM_UPGRADE + +#define UPGRADE_FRAME "{\"path\": \"/v1/messages/\", \"method\": \"POST\", \"meta\": {\"Authorization\": \"token %s\"},\ +\"get\":{\"action\":\"%s\"},\"body\":{\"pre_rom_version\":\"%s\",\"rom_version\":\"%s\"}}\n" + +#define pheadbuffer "Connection: keep-alive\r\n\ +Cache-Control: no-cache\r\n\ +User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 \r\n\ +Accept: */*\r\n\ +Accept-Encoding: gzip,deflate\r\n\ +Accept-Language: zh-CN,eb-US;q=0.8\r\n\r\n" + +/**/ + + +struct espconn *pespconn = NULL; +struct upgrade_server_info *upServer = NULL; + +static os_timer_t at_delay_check; +static struct espconn *pTcpServer = NULL; +static ip_addr_t host_ip; +/****************************************************************************** + * FunctionName : user_esp_platform_upgrade_cb + * Description : Processing the downloaded data from the server + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_rsp(void *arg) +{ + struct upgrade_server_info *server = arg; + + + if(server->upgrade_flag == true) + { + os_printf("device_upgrade_success\r\n"); + at_response_ok(); + system_upgrade_reboot(); + } + else + { + os_printf("device_upgrade_failed\r\n"); + at_response_error(); + } + + os_free(server->url); + server->url = NULL; + os_free(server); + server = NULL; +} +/** + * @brief Tcp client disconnect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_discon_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t idTemp = 0; + + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + if(pespconn != NULL) + { + os_free(pespconn); + } + + os_printf("disconnect\r\n"); + + if(system_upgrade_start(upServer) == false) + { + at_response_error(); + } + else + { + at_port_print("+CIPUPDATE:4\r\n"); + } +} + +/** + * @brief Udp server receive data callback function. + * @param arg: contain the ip link information + * @retval None + */ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_recv(void *arg, char *pusrdata, unsigned short len) +{ + struct espconn *pespconn = (struct espconn *)arg; + char temp[32] = {0}; + uint8_t user_bin[12] = {0}; + uint8_t i = 0; + + os_timer_disarm(&at_delay_check); + at_port_print("+CIPUPDATE:3\r\n"); + + upServer = (struct upgrade_server_info *)os_zalloc(sizeof(struct upgrade_server_info)); + + upServer->upgrade_version[5] = '\0'; + + upServer->pespconn = pespconn; + + os_memcpy(upServer->ip, pespconn->proto.tcp->remote_ip, 4); + + upServer->port = pespconn->proto.tcp->remote_port; + + upServer->check_cb = at_upDate_rsp; + upServer->check_times = 60000; + + if(upServer->url == NULL) + { + upServer->url = (uint8 *) os_zalloc(1024); + } + + if(system_upgrade_userbin_check() == UPGRADE_FW_BIN1) + { + os_memcpy(user_bin, "user2.bin", 10); + } + else if(system_upgrade_userbin_check() == UPGRADE_FW_BIN2) + { + os_memcpy(user_bin, "user1.bin", 10); + } + + os_sprintf(upServer->url, + "GET /%s HTTP/1.1\r\nHost: "IPSTR"\r\n"pheadbuffer"", + user_bin, IP2STR(upServer->ip)); +} + +LOCAL void ICACHE_FLASH_ATTR +at_upDate_wait(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + if(pespconn != NULL) + { + espconn_disconnect(pespconn); + } + else + { + at_response_error(); + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_sent_cb + * Description : Data has been sent successfully and acknowledged by the remote host. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_sent_cb(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + os_timer_setfn(&at_delay_check, (os_timer_func_t *)at_upDate_wait, pespconn); + os_timer_arm(&at_delay_check, 5000, 0); + os_printf("at_upDate_sent_cb\r\n"); +} + +/** + * @brief Tcp client connect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_connect_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t user_bin[9] = {0}; + char *temp = NULL; + + at_port_print("+CIPUPDATE:2\r\n"); + + + espconn_regist_disconcb(pespconn, at_upDate_discon_cb); + espconn_regist_recvcb(pespconn, at_upDate_recv);//////// + espconn_regist_sentcb(pespconn, at_upDate_sent_cb); + + temp = (uint8 *) os_zalloc(512); + + os_sprintf(temp,"GET /v1/device/rom/?is_format_simple=true HTTP/1.0\r\nHost: "IPSTR"\r\n"pheadbuffer"", + IP2STR(pespconn->proto.tcp->remote_ip)); + + espconn_sent(pespconn, temp, os_strlen(temp)); + os_free(temp); +} + +/** + * @brief Tcp client connect repeat callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_recon_cb(void *arg, sint8 errType) +{ + struct espconn *pespconn = (struct espconn *)arg; + + at_response_error(); + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + os_free(pespconn); + os_printf("disconnect\r\n"); + + if(upServer != NULL) + { + os_free(upServer); + upServer = NULL; + } + at_response_error(); + +} + +/****************************************************************************** + * FunctionName : upServer_dns_found + * Description : dns found callback + * Parameters : name -- pointer to the name that was looked up. + * ipaddr -- pointer to an ip_addr_t containing the IP address of + * the hostname, or NULL if the name could not be found (or on any + * other error). + * callback_arg -- a user-specified callback argument passed to + * dns_gethostbyname + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +upServer_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pespconn = (struct espconn *) arg; +// char temp[32]; + + if(ipaddr == NULL) + { + at_response_error(); + return; + } + at_port_print("+CIPUPDATE:1\r\n"); + + + if(host_ip.addr == 0 && ipaddr->addr != 0) + { + if(pespconn->type == ESPCONN_TCP) + { + os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); + } + } +} + +void ICACHE_FLASH_ATTR +at_exeCmdCiupdate(uint8_t id) +{ + pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); + pespconn->type = ESPCONN_TCP; + pespconn->state = ESPCONN_NONE; + pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + pespconn->proto.tcp->local_port = espconn_port(); + pespconn->proto.tcp->remote_port = 80; + + host_ip.addr = ipaddr_addr("192.168.10.9"); + at_port_print("+CIPUPDATE:1\r\n"); + os_memcpy(pespconn->proto.tcp->remote_ip, &host_ip.addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); +} +#endif +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/user_main.c new file mode 100644 index 0000000000..228bbe82de --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at/user/user_main.c @@ -0,0 +1,187 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "at_custom.h" +#include "user_interface.h" + +// test :AT+TEST=1,"abc"<,3> +void ICACHE_FLASH_ATTR +at_setupCmdTest(uint8_t id, char *pPara) +{ + int result = 0, err = 0, flag = 0; + uint8 buffer[32] = {0}; + pPara++; // skip '=' + + //get the first parameter + // digit + flag = at_get_next_int_dec(&pPara, &result, &err); + + // flag must be ture because there are more parameter + if (flag == FALSE) { + at_response_error(); + return; + } + + if (*pPara++ != ',') { // skip ',' + at_response_error(); + return; + } + + os_sprintf(buffer, "the first parameter:%d\r\n", result); + at_port_print(buffer); + + //get the second parameter + // string + at_data_str_copy(buffer, &pPara, 10); + at_port_print("the second parameter:"); + at_port_print(buffer); + at_port_print("\r\n"); + + if (*pPara == ',') { + pPara++; // skip ',' + result = 0; + //there is the third parameter + // digit + flag = at_get_next_int_dec(&pPara, &result, &err); + // we donot care of flag + os_sprintf(buffer, "the third parameter:%d\r\n", result); + at_port_print(buffer); + } + + if (*pPara != '\r') { + at_response_error(); + return; + } + + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_testCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_testCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_queryCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_queryCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_exeCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_exeCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +extern void at_exeCmdCiupdate(uint8_t id); +at_funcationType at_custom_cmd[] = { + {"+TEST", 5, at_testCmdTest, at_queryCmdTest, at_setupCmdTest, at_exeCmdTest}, +#ifdef AT_UPGRADE_SUPPORT + {"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdCiupdate} +#endif +}; + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABBBCDDD + * A : rf cal + * B : at parameters + * C : rf init data + * D : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ + system_phy_freq_trace_enable(at_get_rf_auto_trace_from_flash()); +} + +void ICACHE_FLASH_ATTR +user_init(void) +{ + char buf[64] = {0}; + at_customLinkMax = 5; + at_init(); + os_sprintf(buf,"compile time:%s %s",__DATE__,__TIME__); + at_set_custom_info(buf); + at_port_print("\r\nready\r\n"); + at_cmd_array_regist(&at_custom_cmd[0], sizeof(at_custom_cmd)/sizeof(at_custom_cmd[0])); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/!!!readme!!!.txt b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/!!!readme!!!.txt new file mode 100644 index 0000000000..d91f947d7b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/!!!readme!!!.txt @@ -0,0 +1,42 @@ +Notice: AT added some functions so it's larger than before, if you want to compile it, please compile it as 1024KB or larger flash in compilation STEP 5. + +1¡¢compile options + +(1) COMPILE + Possible value: gcc + Default value: + If not set, use xt-xcc by default. + +(2) BOOT + Possible value: none/old/new + none: no need boot + old: use boot_v1.1 + new: use boot_v1.2+ + Default value: none + +(3) APP + Possible value: 0/1/2 + 0: original mode, generate eagle.app.v6.flash.bin and eagle.app.v6.irom0text.bin + 1: generate user1 + 2: generate user2 + Default value: 0 + +(3) SPI_SPEED + Possible value: 20/26.7/40/80 + Default value: 40 + +(4) SPI_MODE + Possible value: QIO/QOUT/DIO/DOUT + Default value: QIO + +(4) SPI_SIZE + Possible value: 0/2/3/4/5/6 + Default value: 0 + +For example: + make COMPILE=gcc BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=0 + +2¡¢You can also use gen_misc to make and generate specific bin you needed. + Linux: ./gen_misc.sh + Windows: gen_misc.bat + Follow the tips and steps. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/Makefile new file mode 100644 index 0000000000..aeae9917a1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/Makefile @@ -0,0 +1,150 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user +ifdef AT_OPEN_SRC +SUBDIRS += \ + at +endif +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +ifdef AT_OPEN_SRC +COMPONENTS_eagle.app.v6 += \ + at/libat.a +endif + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lupgrade \ + -lssl \ + -lwps \ + -lsmartconfig \ + -lairkiss \ + $(DEP_LIBS_eagle.app.v6) + +ifndef AT_OPEN_SRC +LINKFLAGS_eagle.app.v6 += \ + -lat +endif + +LINKFLAGS_eagle.app.v6 += \ + -Wl,--end-group +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH +ifdef AT_OPEN_SRC +CONFIGURATION_DEFINES += \ + -DAT_OPEN_SRC +endif + +ifeq ($(APP),0) +else +CONFIGURATION_DEFINES += \ + -DAT_UPGRADE_SUPPORT +endif + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.sh new file mode 100644 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/include/user_config.h new file mode 100644 index 0000000000..60ebcbf119 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/include/user_config.h @@ -0,0 +1,36 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define AT_CUSTOM_UPGRADE + +#ifdef AT_CUSTOM_UPGRADE + #ifndef AT_UPGRADE_SUPPORT + #error "upgrade is not supported when eagle.flash.bin+eagle.irom0text.bin!!!" + #endif +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/at_upgrade.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/at_upgrade.c new file mode 100644 index 0000000000..7a14fed98b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/at_upgrade.c @@ -0,0 +1,304 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "c_types.h" +#include "user_interface.h" +#include "espconn.h" +#include "mem.h" +#include "osapi.h" +#include "upgrade.h" + +#ifdef AT_UPGRADE_SUPPORT +#ifdef AT_CUSTOM_UPGRADE + +#define UPGRADE_FRAME "{\"path\": \"/v1/messages/\", \"method\": \"POST\", \"meta\": {\"Authorization\": \"token %s\"},\ +\"get\":{\"action\":\"%s\"},\"body\":{\"pre_rom_version\":\"%s\",\"rom_version\":\"%s\"}}\n" + +#define pheadbuffer "Connection: keep-alive\r\n\ +Cache-Control: no-cache\r\n\ +User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 \r\n\ +Accept: */*\r\n\ +Accept-Encoding: gzip,deflate\r\n\ +Accept-Language: zh-CN,eb-US;q=0.8\r\n\r\n" + +/**/ + + +struct espconn *pespconn = NULL; +struct upgrade_server_info *upServer = NULL; + +static os_timer_t at_delay_check; +static struct espconn *pTcpServer = NULL; +static ip_addr_t host_ip; +/****************************************************************************** + * FunctionName : user_esp_platform_upgrade_cb + * Description : Processing the downloaded data from the server + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_rsp(void *arg) +{ + struct upgrade_server_info *server = arg; + + + if(server->upgrade_flag == true) + { + os_printf("device_upgrade_success\r\n"); + at_response_ok(); + system_upgrade_reboot(); + } + else + { + os_printf("device_upgrade_failed\r\n"); + at_response_error(); + } + + os_free(server->url); + server->url = NULL; + os_free(server); + server = NULL; +} +/** + * @brief Tcp client disconnect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_discon_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t idTemp = 0; + + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + if(pespconn != NULL) + { + os_free(pespconn); + } + + os_printf("disconnect\r\n"); + + if(system_upgrade_start(upServer) == false) + { + at_response_error(); + } + else + { + at_port_print("+CIPUPDATE:4\r\n"); + } +} + +/** + * @brief Udp server receive data callback function. + * @param arg: contain the ip link information + * @retval None + */ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_recv(void *arg, char *pusrdata, unsigned short len) +{ + struct espconn *pespconn = (struct espconn *)arg; + char temp[32] = {0}; + uint8_t user_bin[12] = {0}; + uint8_t i = 0; + + os_timer_disarm(&at_delay_check); + at_port_print("+CIPUPDATE:3\r\n"); + + upServer = (struct upgrade_server_info *)os_zalloc(sizeof(struct upgrade_server_info)); + + upServer->upgrade_version[5] = '\0'; + + upServer->pespconn = pespconn; + + os_memcpy(upServer->ip, pespconn->proto.tcp->remote_ip, 4); + + upServer->port = pespconn->proto.tcp->remote_port; + + upServer->check_cb = at_upDate_rsp; + upServer->check_times = 60000; + + if(upServer->url == NULL) + { + upServer->url = (uint8 *) os_zalloc(1024); + } + + if(system_upgrade_userbin_check() == UPGRADE_FW_BIN1) + { + os_memcpy(user_bin, "user2.bin", 10); + } + else if(system_upgrade_userbin_check() == UPGRADE_FW_BIN2) + { + os_memcpy(user_bin, "user1.bin", 10); + } + + os_sprintf(upServer->url, + "GET /%s HTTP/1.1\r\nHost: "IPSTR"\r\n"pheadbuffer"", + user_bin, IP2STR(upServer->ip)); +} + +LOCAL void ICACHE_FLASH_ATTR +at_upDate_wait(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + if(pespconn != NULL) + { + espconn_disconnect(pespconn); + } + else + { + at_response_error(); + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_sent_cb + * Description : Data has been sent successfully and acknowledged by the remote host. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_sent_cb(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + os_timer_setfn(&at_delay_check, (os_timer_func_t *)at_upDate_wait, pespconn); + os_timer_arm(&at_delay_check, 5000, 0); + os_printf("at_upDate_sent_cb\r\n"); +} + +/** + * @brief Tcp client connect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_connect_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t user_bin[9] = {0}; + char *temp = NULL; + + at_port_print("+CIPUPDATE:2\r\n"); + + + espconn_regist_disconcb(pespconn, at_upDate_discon_cb); + espconn_regist_recvcb(pespconn, at_upDate_recv);//////// + espconn_regist_sentcb(pespconn, at_upDate_sent_cb); + + temp = (uint8 *) os_zalloc(512); + + os_sprintf(temp,"GET /v1/device/rom/?is_format_simple=true HTTP/1.0\r\nHost: "IPSTR"\r\n"pheadbuffer"", + IP2STR(pespconn->proto.tcp->remote_ip)); + + espconn_sent(pespconn, temp, os_strlen(temp)); + os_free(temp); +} + +/** + * @brief Tcp client connect repeat callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_recon_cb(void *arg, sint8 errType) +{ + struct espconn *pespconn = (struct espconn *)arg; + + at_response_error(); + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + os_free(pespconn); + os_printf("disconnect\r\n"); + + if(upServer != NULL) + { + os_free(upServer); + upServer = NULL; + } + at_response_error(); + +} + +/****************************************************************************** + * FunctionName : upServer_dns_found + * Description : dns found callback + * Parameters : name -- pointer to the name that was looked up. + * ipaddr -- pointer to an ip_addr_t containing the IP address of + * the hostname, or NULL if the name could not be found (or on any + * other error). + * callback_arg -- a user-specified callback argument passed to + * dns_gethostbyname + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +upServer_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pespconn = (struct espconn *) arg; +// char temp[32]; + + if(ipaddr == NULL) + { + at_response_error(); + return; + } + at_port_print("+CIPUPDATE:1\r\n"); + + + if(host_ip.addr == 0 && ipaddr->addr != 0) + { + if(pespconn->type == ESPCONN_TCP) + { + os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); + } + } +} + +void ICACHE_FLASH_ATTR +at_exeCmdCiupdate(uint8_t id) +{ + pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); + pespconn->type = ESPCONN_TCP; + pespconn->state = ESPCONN_NONE; + pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + pespconn->proto.tcp->local_port = espconn_port(); + pespconn->proto.tcp->remote_port = 80; + + host_ip.addr = ipaddr_addr("192.168.10.9"); + at_port_print("+CIPUPDATE:1\r\n"); + os_memcpy(pespconn->proto.tcp->remote_ip, &host_ip.addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); +} +#endif +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/user_main.c new file mode 100755 index 0000000000..9304879e5f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_espconn/user/user_main.c @@ -0,0 +1,215 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "at_custom.h" +#include "user_interface.h" +#include "mem.h" +#include "espconn.h" + + +static struct espconn *at_espconn_demo_espconn_ptr = NULL; + +#define AT_ESPCONN_DEMO_BUFFER_SIZE (2920) +static uint8 at_espconn_demo_buffer[AT_ESPCONN_DEMO_BUFFER_SIZE]; +static uint32 at_espconn_demo_data_len = 0; +static bool at_espconn_demo_flag = FALSE; + +static void ICACHE_FLASH_ATTR +at_espconn_demo_recon_cb(void *arg, sint8 errType) +{ + struct espconn *espconn_ptr = (struct espconn *)arg; + + os_printf("at demo espconn reconnect\r\n"); + at_espconn_demo_flag = FALSE; + espconn_connect(espconn_ptr); +} + + +// notify at module that espconn has received data +static void ICACHE_FLASH_ATTR +at_espconn_demo_recv(void *arg, char *pusrdata, unsigned short len) +{ + at_fake_uart_rx(pusrdata,len); +} + +static void ICACHE_FLASH_ATTR +at_espconn_demo_send_cb(void *arg) +{ + at_espconn_demo_flag = TRUE; + if(at_espconn_demo_data_len) { + espconn_send(at_espconn_demo_espconn_ptr,at_espconn_demo_buffer,at_espconn_demo_data_len); + at_espconn_demo_data_len = 0; + } +} +static void ICACHE_FLASH_ATTR +at_espconn_demo_discon_cb(void *arg) +{ + struct espconn *espconn_ptr = (struct espconn *)arg; + + os_printf("at demo espconn disconnected\r\n"); + at_espconn_demo_flag = FALSE; + espconn_connect(espconn_ptr); +} + +static void ICACHE_FLASH_ATTR +at_espconn_demo_connect_cb(void *arg) +{ + os_printf("at demo espconn connected\r\n"); + espconn_set_opt((struct espconn*)arg,ESPCONN_COPY); + at_espconn_demo_flag = TRUE; + at_espconn_demo_data_len = 0; +} + +static void ICACHE_FLASH_ATTR at_espconn_demo_response(const uint8*data,uint32 length) +{ + if((data == NULL) || (length == 0)) { + return; + } + + if(at_espconn_demo_flag) { + espconn_send(at_espconn_demo_espconn_ptr,(uint8*)data,length); + at_espconn_demo_flag = FALSE; + } else { + if(length <= (AT_ESPCONN_DEMO_BUFFER_SIZE - at_espconn_demo_data_len)) { + os_memcpy(at_espconn_demo_buffer + at_espconn_demo_data_len,data,length); + at_espconn_demo_data_len += length; + } else { + os_printf("at espconn buffer full\r\n"); + } + } +} + + +static void ICACHE_FLASH_ATTR at_espconn_demo_init(void) +{ + uint32 ip = 0; + at_espconn_demo_espconn_ptr = (struct espconn *)os_zalloc(sizeof(struct espconn)); + at_espconn_demo_espconn_ptr->type = ESPCONN_TCP; + at_espconn_demo_espconn_ptr->state = ESPCONN_NONE; + at_espconn_demo_espconn_ptr->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + at_espconn_demo_espconn_ptr->proto.tcp->local_port = espconn_port(); + at_espconn_demo_espconn_ptr->proto.tcp->remote_port = 8999; + + ip = ipaddr_addr("192.168.1.120"); + os_memcpy(at_espconn_demo_espconn_ptr->proto.tcp->remote_ip,&ip,sizeof(ip)); + espconn_regist_connectcb(at_espconn_demo_espconn_ptr, at_espconn_demo_connect_cb); + espconn_regist_reconcb(at_espconn_demo_espconn_ptr, at_espconn_demo_recon_cb); + espconn_regist_disconcb(at_espconn_demo_espconn_ptr, at_espconn_demo_discon_cb); + espconn_regist_recvcb(at_espconn_demo_espconn_ptr, at_espconn_demo_recv); + espconn_regist_sentcb(at_espconn_demo_espconn_ptr, at_espconn_demo_send_cb); + + espconn_connect(at_espconn_demo_espconn_ptr); + + at_fake_uart_enable(TRUE,at_espconn_demo_response); +} + +static void ICACHE_FLASH_ATTR +at_exeCmdTest(uint8_t id) +{ + at_response_ok(); + at_espconn_demo_init(); +} + +extern void at_exeCmdCiupdate(uint8_t id); +at_funcationType at_custom_cmd[] = { + {"+TEST", 5, NULL, NULL, NULL, at_exeCmdTest}, +#ifdef AT_UPGRADE_SUPPORT + {"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdCiupdate} +#endif +}; + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ + system_phy_freq_trace_enable(at_get_rf_auto_trace_from_flash()); +} + +void ICACHE_FLASH_ATTR +user_init(void) +{ + char buf[64] = {0}; + at_customLinkMax = 5; + at_init(); + os_sprintf(buf,"compile time:%s %s",__DATE__,__TIME__); + at_set_custom_info(buf); + at_port_print("\r\nready\r\n"); + at_cmd_array_regist(&at_custom_cmd[0], sizeof(at_custom_cmd)/sizeof(at_custom_cmd[0])); + at_port_print("\r\n***==================================***"); + at_port_print("\r\n*** Welcome to at espconn demo!!! ***"); + at_port_print("\r\n*** Please create a TCP Server on PC,***"); + at_port_print("\r\n*** then enter command AT+TEST. ***"); + at_port_print("\r\n***==================================***\r\n"); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/Makefile new file mode 100644 index 0000000000..c4d9b2dedf --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/Makefile @@ -0,0 +1,157 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user \ + driver +ifdef AT_OPEN_SRC +SUBDIRS += \ + at +endif +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a \ + driver/libdriver.a + +ifdef AT_OPEN_SRC +COMPONENTS_eagle.app.v6 += \ + at/libat.a +endif + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lupgrade \ + -lssl \ + -lwps \ + -lsmartconfig \ + -lairkiss \ + $(DEP_LIBS_eagle.app.v6) + +ifndef AT_OPEN_SRC +LINKFLAGS_eagle.app.v6 += \ + -lat +endif + +LINKFLAGS_eagle.app.v6 += \ + -Wl,--end-group +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH \ + -DAT_OVER_SDIO_SUPPORT +ifdef AT_OPEN_SRC +CONFIGURATION_DEFINES += \ + -DAT_OPEN_SRC +endif + +ifeq ($(APP),0) +else +CONFIGURATION_DEFINES += \ + -DAT_UPGRADE_SUPPORT +endif + +ifeq ($(SPI_SIZE_MAP),5) +CONFIGURATION_DEFINES += -DFLASH_MAP=$(SPI_SIZE_MAP) +endif + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/Makefile new file mode 100644 index 0000000000..38fd29fcd6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libdriver.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/sdio_slv.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/sdio_slv.c new file mode 100644 index 0000000000..b0763da7bd --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/driver/sdio_slv.c @@ -0,0 +1,493 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "driver/slc_register.h" +#include "driver/sdio_slv.h" +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" +//#include "gpio.h" +#include "user_interface.h" +#include "mem.h" + +#define SDIO_TOKEN_SIZE 0//4 +#define RX_BUFFER_SIZE 2048 +#define RX_BUFFER_NUM 5 + +#define TX_BUFFER_SIZE 2048 +#define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA) +#define TRIG_TOHOST_INT() SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\ + CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0) +struct sdio_queue +{ + uint32 blocksize:12; + uint32 datalen:12; + uint32 unused:5; + uint32 sub_sof:1; + uint32 eof:1; + uint32 owner:1; + + uint32 buf_ptr; + uint32 next_link_ptr; +}; + +struct sdio_slave_status_element +{ + uint32 wr_busy:1; + uint32 rd_empty :1; + uint32 comm_cnt :3; + uint32 intr_no :3; + uint32 rx_length:16; + uint32 res:8; +}; + +union sdio_slave_status +{ + struct sdio_slave_status_element elm_value; + uint32 word_value; +}; + +//uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024]; +uint8 tx_buffer[TX_BUFFER_SIZE]; + +uint32 data_len = 0; + +struct sdio_list { + uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE]; + uint8* tail; + struct sdio_list* next; +}; + +static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL; +struct sdio_list* pHead_ToSend; +struct sdio_list* pTail_ToSend; +struct sdio_list* pHead_Sended; +struct sdio_list* pTail_Sended; + + + +os_event_t * sdioQueue; +struct sdio_queue rx_que,tx_que; + +static bool has_read = 0; + +static void sdio_slave_isr(void *para); +static void tx_buff_handle_done(void); +static void rx_buff_read_done(void); +static void tx_buff_write_done(void); + +static void sdio_try_to_load(void); +static void sdio_read_done_process(void); +#ifdef SDIO_DEBUG +extern uint32 sum_len; +#endif +void sdio_slave_init(void) +{ + uint32 regval = 0; + union sdio_slave_status sdio_sta; + ETS_SDIO_INTR_DISABLE(); + /// + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U,FUNC_SDCLK); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U,FUNC_SDDATA0); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U,FUNC_SDDATA1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U,FUNC_SDDATA2); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U,FUNC_SDDATA3); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U,FUNC_SDCMD); + + + ////reset orginal link + SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST); + CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST); + + os_printf("RX&TX link reset!\n"); + + //set sdio mode + SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE); + //clear to host interrupt io signal for preventing from random initial signal. + WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff); + //enable 2 events to trigger the to host intr io + SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA); + ////initialize rx queue information + + has_read = TRUE; + pHead_ToSend = NULL; + + int loop = RX_BUFFER_NUM; + struct sdio_list* p = NULL; + while(loop--) { + if(pHead_Sended == NULL) { + pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list)); + p = pHead_Sended; + } else { + p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list)); + p = p->next; + } + //os_printf("p:0x%08x\r\n",p); + p->tail = p->buffer + SDIO_TOKEN_SIZE; + p->next = NULL; + } + pTail_Sended = p; + + rx_que.blocksize = RX_BUFFER_SIZE; + rx_que.datalen=0; + rx_que.eof=1; + rx_que.owner=1; + rx_que.sub_sof=0; + rx_que.unused=0; + rx_que.buf_ptr=(uint32)pHead_Sended->buffer; + rx_que.next_link_ptr=0; + + + ////initialize tx queue information + tx_que.blocksize=TX_BUFFER_SIZE; + tx_que.datalen=0; + tx_que.eof=0; + tx_que.owner=1; + tx_que.sub_sof=0; + tx_que.unused=0; + tx_que.buf_ptr=(uint32)tx_buffer; + tx_que.next_link_ptr=0; + + ///////link tx&rx queue information address to sdio hardware + CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK); + regval= ((uint32)&rx_que); + SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK); + CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK); + regval= ((uint32)&tx_que); + SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK); + +#if (SDIO_TOKEN_SIZE == 0) + SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE); +#endif + + /////config sdio_status reg + sdio_sta.elm_value.comm_cnt=7; + sdio_sta.elm_value.intr_no=INIT_STAGE; + sdio_sta.elm_value.wr_busy=0; + sdio_sta.elm_value.rd_empty=1; + sdio_sta.elm_value.rx_length=0; + sdio_sta.elm_value.res=0; + SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); + + + /////attach isr func to sdio interrupt + ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL); + /////enable sdio operation intr + WRITE_PERI_REG(SLC_INT_ENA, SLC_INTEREST_EVENT); + /////clear sdio initial random active intr signal + WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff); + /////enable sdio intr in cpu + ETS_SDIO_INTR_ENABLE(); +} + +static void sdio_slave_isr(void *para) +{ + uint32 slc_intr_status,postval; + static uint8 state =0; + uint16 rx_len,i; + uint32* pword; + union sdio_slave_status sdio_sta; + + slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); + + if (slc_intr_status == 0) + { + /* No interested interrupts pending */ + return; + } + //clear all intrs + WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status); + //os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status); + //process every intr + + //TO HOST DONE + if (slc_intr_status & SLC_RX_EOF_INT_ENA) + { + //following code must be called after a data pack has been read + rx_buff_read_done(); + sdio_read_done_process(); + } + + //FROM HOST DONE + if (slc_intr_status & SLC_TX_EOF_INT_ENA) + { + //call the following function after host cpu data transmission finished + tx_buff_write_done(); + if(sdio_recv_data_callback_ptr) { + if (sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen) == tx_que.datalen) { + tx_buff_handle_done(); + TRIG_TOHOST_INT(); + } + } else { + tx_buff_handle_done(); + TRIG_TOHOST_INT(); + } + } +#if 0 + //TO HOST underflow + if(slc_intr_status & SLC_RX_UDF_INT_ENA) + { + } + + //FROM HOST overflow + if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA) + { + } + + slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); + if(slc_intr_status) + { + WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status); + } +#endif +} + +static void rx_buff_read_done(void) +{ + union sdio_slave_status sdio_sta; + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.comm_cnt++; + sdio_sta.elm_value.rd_empty=1; + sdio_sta.elm_value.rx_length=0; + sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //os_printf("rx_buff_read_done\r\n"); +} + +static void tx_buff_write_done(void) +{ + union sdio_slave_status sdio_sta; + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.comm_cnt++; + sdio_sta.elm_value.wr_busy=1; + sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE); + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register +} + +static void tx_buff_handle_done(void) +{ + union sdio_slave_status sdio_sta; + + /////config tx queue information + tx_que.blocksize=TX_BUFFER_SIZE; + tx_que.datalen=0; + tx_que.eof=0; + tx_que.owner=1; + + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.wr_busy=0; + sdio_sta.elm_value.intr_no |= TX_AVAILIBLE; + + SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); //tx buffer is ready for being written + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //*******************************************************************// + +} +static int32 rx_buff_load_done(uint16 rx_len) +{ + union sdio_slave_status sdio_sta; + + if(rx_len == 0) { + return 0; + } + if(rx_len > rx_que.blocksize) + { + rx_len = rx_que.blocksize; + } + + //os_memcpy(rx_que.buf_ptr,data,rx_len); + /////config rx queue information + rx_que.blocksize=RX_BUFFER_SIZE; + rx_que.datalen=rx_len + SDIO_TOKEN_SIZE; + rx_que.eof=1; + rx_que.owner=1; +#ifdef SDIO_DEBUG + sum_len += rx_que.datalen; +#endif + //ETS_SDIO_INTR_DISABLE(); + //available_buffer_amount--; + + /////modify sdio status reg + sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2); + sdio_sta.elm_value.rd_empty=0; + sdio_sta.elm_value.intr_no |= RX_AVAILIBLE; + sdio_sta.elm_value.rx_length=rx_len; + + SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); //rx buffer is ready for being read + WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register + //ETS_SDIO_INTR_ENABLE(); + return rx_len; +} + +int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len) +{ + int32 data_len = 0; + struct sdio_list* temp_list; + if (pHead_Sended == NULL) { + //os_printf("no buf\r\n"); + return 0; + } + int32 left_len = 0; + while(len) + { + ETS_SDIO_INTR_DISABLE(); + if(pHead_Sended == NULL) + { + //os_printf("buf full\r\n"); + ETS_SDIO_INTR_ENABLE(); + break; + } + temp_list = pHead_Sended; + pHead_Sended = pHead_Sended->next; + ETS_SDIO_INTR_ENABLE(); + left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(temp_list->tail - temp_list->buffer); + if(len < left_len) + { + os_memcpy(temp_list->tail,data,len); + temp_list->tail += len; + + data_len += len; + len = 0; + ETS_SDIO_INTR_DISABLE(); + temp_list->next = pHead_Sended; + pHead_Sended = temp_list; + //ETS_SDIO_INTR_ENABLE(); + } + else + { + os_memcpy(temp_list->tail,data,left_len); + temp_list->tail += left_len; + len -= left_len; + data += left_len; + data_len += left_len; + ETS_SDIO_INTR_DISABLE(); + if(pHead_ToSend == NULL) { + pTail_ToSend = temp_list; + pHead_ToSend = pTail_ToSend; + sdio_try_to_load(); + } else { + pTail_ToSend->next = temp_list; + pTail_ToSend = pTail_ToSend->next; + } + pTail_ToSend->next = NULL; + //ETS_SDIO_INTR_ENABLE(); + } + } + //ETS_SDIO_INTR_DISABLE(); + if(pHead_ToSend == NULL) { + pTail_ToSend = pHead_Sended; + pHead_ToSend = pTail_ToSend; + + pHead_Sended = pHead_Sended->next; + pTail_ToSend->next = NULL; + sdio_try_to_load(); + } + ETS_SDIO_INTR_ENABLE(); + return data_len; +} + +static void sdio_try_to_load(void) +{ + if((has_read == TRUE) && (pHead_ToSend != NULL)) + { + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + //pHead_ToSend = pHead_ToSend->next; + has_read = FALSE; + //os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS)); + TRIG_TOHOST_INT(); + } +} + +static void sdio_read_done_process(void) +{ + has_read = TRUE; + + pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE; + if(pHead_Sended) { + pTail_Sended->next = pHead_ToSend; + pTail_Sended = pTail_Sended->next; + }else { + pTail_Sended = pHead_ToSend; + pHead_Sended = pTail_Sended; + } + pHead_ToSend = pHead_ToSend->next; + pTail_Sended->next = NULL; + //os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail); + if(pHead_ToSend) { + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + has_read = FALSE; + //os_printf("intr trig\r\n"); + //TRIG_TOHOST_INT(); + } else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) { + pHead_ToSend = pHead_Sended; + pTail_ToSend = pHead_ToSend; + pHead_Sended = pHead_Sended->next; + pTail_ToSend->next = NULL; + + rx_que.buf_ptr = (uint32)pHead_ToSend->buffer; + rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE); + has_read = FALSE; + //os_printf("intr trig\r\n"); + //TRIG_TOHOST_INT(); + } + + if (has_read == FALSE) { + TRIG_TOHOST_INT(); + } +} + +bool sdio_register_recv_cb(sdio_recv_data_callback_t cb) +{ + sdio_recv_data_callback_ptr = cb; + + return TRUE; +} + +void ICACHE_FLASH_ATTR at_custom_uart_rx_buffer_fetch_cb(void) +{ + if(sdio_recv_data_callback_ptr && tx_que.datalen) { + if (sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen) == tx_que.datalen) { + tx_buff_handle_done(); + TRIG_TOHOST_INT(); + } + } +} + + +#ifdef SDIO_DEBUG +void ICACHE_FLASH_ATTR at_spi_check_cb(void *arg) +{ + //TRIG_TOHOST_INT(); + os_printf("sum_len:%d\r\n",sum_len); + //sdio_load_data("esp8266\r\n",os_strlen("esp8266\r\n")); + + sum_len = 0; +} +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.bat new file mode 100644 index 0000000000..fb9c5d0e55 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.bat @@ -0,0 +1,27 @@ +@echo off +set BACKPATH=%PATH% +set PATH=%BACKPATH%;%CD%\..\tools +@echo on + +del /F ..\bin\eagle.app.v6.flash.bin ..\bin\eagle.app.v6.irom0text.bin ..\bin\eagle.app.v6.dump ..\bin\eagle.app.v6.S + +cd .output\eagle\debug\image + +xt-objdump -x -s eagle.app.v6.out > ..\..\..\..\..\bin\eagle.app.v6.dump +xt-objdump -S eagle.app.v6.out > ..\..\..\..\..\bin\eagle.app.v6.S + +xt-objcopy --only-section .text -O binary eagle.app.v6.out eagle.app.v6.text.bin +xt-objcopy --only-section .data -O binary eagle.app.v6.out eagle.app.v6.data.bin +xt-objcopy --only-section .rodata -O binary eagle.app.v6.out eagle.app.v6.rodata.bin +xt-objcopy --only-section .irom0.text -O binary eagle.app.v6.out eagle.app.v6.irom0text.bin + +gen_appbin.py eagle.app.v6.out v6 + +xcopy /y eagle.app.v6.irom0text.bin ..\..\..\..\..\bin\ +xcopy /y eagle.app.v6.flash.bin ..\..\..\..\..\bin\ + +cd ..\..\..\..\ + +@echo off +set PATH=%BACKPATH% +@echo on diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.sh new file mode 100644 index 0000000000..174aad56fa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +make clean + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/sdio_slv.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/sdio_slv.h new file mode 100644 index 0000000000..bdf0a7e2e3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/sdio_slv.h @@ -0,0 +1,43 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SDIO_SLAVE_H__ +#define __SDIO_SLAVE_H__ +#include "slc_register.h" +#include "c_types.h" +#include "user_interface.h" + +//#define SDIO_DEBUG + +#define RX_AVAILIBLE 2 +#define TX_AVAILIBLE 1 +#define INIT_STAGE 0 + +void sdio_slave_init(void); + +int32 sdio_load_data(const uint8* data,uint32 len); +typedef uint32 (*sdio_recv_data_callback_t)(uint8* data,uint32 len); + +bool sdio_register_recv_cb(sdio_recv_data_callback_t cb); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/slc_register.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/slc_register.h new file mode 100644 index 0000000000..bd8fd8ed93 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/driver/slc_register.h @@ -0,0 +1,299 @@ +//Generated at 2012-10-23 19:55:03 +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef SLC_REGISTER_H_ +#define SLC_REGISTER_H_ + +#define REG_SLC_BASE 0x60000B00 +//version value:32'h091700 + +#define SLC_CONF0 (REG_SLC_BASE + 0x0) +#ifndef ESP_MAC_5 +#define SLC_MODE 0x00000003 +#define SLC_MODE_S 12 +#endif +#define SLC_DATA_BURST_EN (BIT(9)) +#define SLC_DSCR_BURST_EN (BIT(8)) +#define SLC_RX_NO_RESTART_CLR (BIT(7)) +#define SLC_RX_AUTO_WRBACK (BIT(6)) +#define SLC_RX_LOOP_TEST (BIT(5)) +#define SLC_TX_LOOP_TEST (BIT(4)) +#define SLC_AHBM_RST (BIT(3)) +#define SLC_AHBM_FIFO_RST (BIT(2)) +#define SLC_RXLINK_RST (BIT(1)) +#define SLC_TXLINK_RST (BIT(0)) + +#define SLC_INT_RAW (REG_SLC_BASE + 0x4) +#define SLC_TX_DSCR_EMPTY_INT_RAW (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_RAW (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_RAW (BIT(19)) +#define SLC_TOHOST_INT_RAW (BIT(18)) +#define SLC_RX_EOF_INT_RAW (BIT(17)) +#define SLC_RX_DONE_INT_RAW (BIT(16)) +#define SLC_TX_EOF_INT_RAW (BIT(15)) +#define SLC_TX_DONE_INT_RAW (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_RAW (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_RAW (BIT(12)) +#define SLC_TX_OVF_INT_RAW (BIT(11)) +#define SLC_RX_UDF_INT_RAW (BIT(10)) +#define SLC_TX_START_INT_RAW (BIT(9)) +#define SLC_RX_START_INT_RAW (BIT(8)) +#define SLC_FRHOST_BIT7_INT_RAW (BIT(7)) +#define SLC_FRHOST_BIT6_INT_RAW (BIT(6)) +#define SLC_FRHOST_BIT5_INT_RAW (BIT(5)) +#define SLC_FRHOST_BIT4_INT_RAW (BIT(4)) +#define SLC_FRHOST_BIT3_INT_RAW (BIT(3)) +#define SLC_FRHOST_BIT2_INT_RAW (BIT(2)) +#define SLC_FRHOST_BIT1_INT_RAW (BIT(1)) +#define SLC_FRHOST_BIT0_INT_RAW (BIT(0)) + +#define SLC_INT_STATUS (REG_SLC_BASE + 0x8) +#define SLC_TX_DSCR_EMPTY_INT_ST (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_ST (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_ST (BIT(19)) +#define SLC_TOHOST_INT_ST (BIT(18)) +#define SLC_RX_EOF_INT_ST (BIT(17)) +#define SLC_RX_DONE_INT_ST (BIT(16)) +#define SLC_TX_EOF_INT_ST (BIT(15)) +#define SLC_TX_DONE_INT_ST (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_ST (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_ST (BIT(12)) +#define SLC_TX_OVF_INT_ST (BIT(11)) +#define SLC_RX_UDF_INT_ST (BIT(10)) +#define SLC_TX_START_INT_ST (BIT(9)) +#define SLC_RX_START_INT_ST (BIT(8)) +#define SLC_FRHOST_BIT7_INT_ST (BIT(7)) +#define SLC_FRHOST_BIT6_INT_ST (BIT(6)) +#define SLC_FRHOST_BIT5_INT_ST (BIT(5)) +#define SLC_FRHOST_BIT4_INT_ST (BIT(4)) +#define SLC_FRHOST_BIT3_INT_ST (BIT(3)) +#define SLC_FRHOST_BIT2_INT_ST (BIT(2)) +#define SLC_FRHOST_BIT1_INT_ST (BIT(1)) +#define SLC_FRHOST_BIT0_INT_ST (BIT(0)) + +#define SLC_INT_ENA (REG_SLC_BASE + 0xC) +#define SLC_TX_DSCR_EMPTY_INT_ENA (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_ENA (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_ENA (BIT(19)) +#define SLC_TOHOST_INT_ENA (BIT(18)) +#define SLC_RX_EOF_INT_ENA (BIT(17)) +#define SLC_RX_DONE_INT_ENA (BIT(16)) +#define SLC_TX_EOF_INT_ENA (BIT(15)) +#define SLC_TX_DONE_INT_ENA (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_ENA (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_ENA (BIT(12)) +#define SLC_TX_OVF_INT_ENA (BIT(11)) +#define SLC_RX_UDF_INT_ENA (BIT(10)) +#define SLC_TX_START_INT_ENA (BIT(9)) +#define SLC_RX_START_INT_ENA (BIT(8)) +#define SLC_FRHOST_BIT7_INT_ENA (BIT(7)) +#define SLC_FRHOST_BIT6_INT_ENA (BIT(6)) +#define SLC_FRHOST_BIT5_INT_ENA (BIT(5)) +#define SLC_FRHOST_BIT4_INT_ENA (BIT(4)) +#define SLC_FRHOST_BIT3_INT_ENA (BIT(3)) +#define SLC_FRHOST_BIT2_INT_ENA (BIT(2)) +#define SLC_FRHOST_BIT1_INT_ENA (BIT(1)) +#define SLC_FRHOST_BIT0_INT_ENA (BIT(0)) + +#define SLC_FRHOST_BIT_INT_ENA_ALL 0xff + +#define SLC_INT_CLR (REG_SLC_BASE + 0x10) +#define SLC_TX_DSCR_EMPTY_INT_CLR (BIT(21)) +#define SLC_RX_DSCR_ERR_INT_CLR (BIT(20)) +#define SLC_TX_DSCR_ERR_INT_CLR (BIT(19)) +#define SLC_TOHOST_INT_CLR (BIT(18)) +#define SLC_RX_EOF_INT_CLR (BIT(17)) +#define SLC_RX_DONE_INT_CLR (BIT(16)) +#define SLC_TX_EOF_INT_CLR (BIT(15)) +#define SLC_TX_DONE_INT_CLR (BIT(14)) +#define SLC_TOKEN1_1TO0_INT_CLR (BIT(13)) +#define SLC_TOKEN0_1TO0_INT_CLR (BIT(12)) +#define SLC_TX_OVF_INT_CLR (BIT(11)) +#define SLC_RX_UDF_INT_CLR (BIT(10)) +#define SLC_TX_START_INT_CLR (BIT(9)) +#define SLC_RX_START_INT_CLR (BIT(8)) +#define SLC_FRHOST_BIT7_INT_CLR (BIT(7)) +#define SLC_FRHOST_BIT6_INT_CLR (BIT(6)) +#define SLC_FRHOST_BIT5_INT_CLR (BIT(5)) +#define SLC_FRHOST_BIT4_INT_CLR (BIT(4)) +#define SLC_FRHOST_BIT3_INT_CLR (BIT(3)) +#define SLC_FRHOST_BIT2_INT_CLR (BIT(2)) +#define SLC_FRHOST_BIT1_INT_CLR (BIT(1)) +#define SLC_FRHOST_BIT0_INT_CLR (BIT(0)) + +#define SLC_RX_STATUS (REG_SLC_BASE + 0x14) +#define SLC_RX_EMPTY (BIT(1)) +#define SLC_RX_FULL (BIT(0)) + +#define SLC_RX_FIFO_PUSH (REG_SLC_BASE + 0x18) +#define SLC_RXFIFO_PUSH (BIT(16)) +#define SLC_RXFIFO_WDATA 0x000001FF +#define SLC_RXFIFO_WDATA_S 0 + +#define SLC_TX_STATUS (REG_SLC_BASE + 0x1C) +#define SLC_TX_EMPTY (BIT(1)) +#define SLC_TX_FULL (BIT(0)) + +#define SLC_TX_FIFO_POP (REG_SLC_BASE + 0x20) +#define SLC_TXFIFO_POP (BIT(16)) +#define SLC_TXFIFO_RDATA 0x000007FF +#define SLC_TXFIFO_RDATA_S 0 + +#define SLC_RX_LINK (REG_SLC_BASE + 0x24) +#define SLC_RXLINK_PARK (BIT(31)) +#define SLC_RXLINK_RESTART (BIT(30)) +#define SLC_RXLINK_START (BIT(29)) +#define SLC_RXLINK_STOP (BIT(28)) +#define SLC_RXLINK_DESCADDR_MASK 0x000FFFFF +#define SLC_RXLINK_ADDR_S 0 + +#define SLC_TX_LINK (REG_SLC_BASE + 0x28) +#define SLC_TXLINK_PARK (BIT(31)) +#define SLC_TXLINK_RESTART (BIT(30)) +#define SLC_TXLINK_START (BIT(29)) +#define SLC_TXLINK_STOP (BIT(28)) +#define SLC_TXLINK_DESCADDR_MASK 0x000FFFFF +#define SLC_TXLINK_ADDR_S 0 + +#define SLC_INTVEC_TOHOST (REG_SLC_BASE + 0x2C) +#define SLC_TOHOST_INTVEC 0x000000FF +#define SLC_TOHOST_INTVEC_S 0 + +#define SLC_TOKEN0 (REG_SLC_BASE + 0x30) +#define SLC_TOKEN0_MASK 0x00000FFF +#define SLC_TOKEN0_S 16 +#define SLC_TOKEN0_LOCAL_INC_MORE (BIT(14)) +#define SLC_TOKEN0_LOCAL_INC (BIT(13)) +#define SLC_TOKEN0_LOCAL_WR (BIT(12)) +#define SLC_TOKEN0_LOCAL_WDATA_MASK 0x00000FFF +#define SLC_TOKEN0_LOCAL_WDATA_S 0 + +#define SLC_TOKEN1 (REG_SLC_BASE + 0x34) +#define SLC_TOKEN1_MASK 0x00000FFF +#define SLC_TOKEN1_S 16 +#define SLC_TOKEN1_LOCAL_INC_MORE (BIT(14)) +#define SLC_TOKEN1_LOCAL_INC (BIT(13)) +#define SLC_TOKEN1_LOCAL_WR (BIT(12)) +#define SLC_TOKEN1_LOCAL_WDATA 0x00000FFF +#define SLC_TOKEN1_LOCAL_WDATA_S 0 + +#define SLC_CONF1 (REG_SLC_BASE + 0x38) +#define SLC_STATE0 (REG_SLC_BASE + 0x3C) +#define SLC_STATE1 (REG_SLC_BASE + 0x40) + +#define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44) +#ifndef ESP_MAC_5 +#define SLC_TX_PUSH_IDLE_NUM 0x0000FFFF +#define SLC_TX_PUSH_IDLE_NUM_S 16 +#define SLC_TX_DUMMY_MODE (BIT(12)) +#endif +#define SLC_FIFO_MAP_ENA 0x0000000F +#define SLC_FIFO_MAP_ENA_S 8 +#define SLC_TXEOF_ENA 0x0000003F +#define SLC_TXEOF_ENA_S 0 + +#define SLC_RX_EOF_DES_ADDR (REG_SLC_BASE + 0x48) +#define SLC_TX_EOF_DES_ADDR (REG_SLC_BASE + 0x4C) +#define SLC_FROM_HOST_LAST_DESC SLC_TX_EOF_DES_ADDR +#define SLC_TO_HOST_LAST_DESC SLC_RX_EOF_DES_ADDR + +#define SLC_RX_EOF_BFR_DES_ADDR (REG_SLC_BASE + 0x50) +#define SLC_AHB_TEST (REG_SLC_BASE + 0x54) +#define SLC_AHB_TESTADDR 0x00000003 +#define SLC_AHB_TESTADDR_S 4 +#define SLC_AHB_TESTMODE 0x00000007 +#define SLC_AHB_TESTMODE_S 0 + +#define SLC_SDIO_ST (REG_SLC_BASE + 0x58) +#define SLC_BUS_ST 0x00000007 +#define SLC_BUS_ST_S 12 +#define SLC_SDIO_WAKEUP (BIT(8)) +#define SLC_FUNC_ST 0x0000000F +#define SLC_FUNC_ST_S 4 +#define SLC_CMD_ST 0x00000007 +#define SLC_CMD_ST_S 0 + +#define SLC_RX_DSCR_CONF (REG_SLC_BASE + 0x5C) +#ifdef ESP_MAC_5 +#define SLC_INFOR_NO_REPLACE (BIT(9)) +#define SLC_TOKEN_NO_REPLACE (BIT(8)) +#define SLC_POP_IDLE_CNT 0x000000FF +#else +#define SLC_RX_FILL_EN (BIT(20)) +#define SLC_RX_EOF_MODE (BIT(19)) +#define SLC_RX_FILL_MODE (BIT(18)) +#define SLC_INFOR_NO_REPLACE (BIT(17)) +#define SLC_TOKEN_NO_REPLACE (BIT(16)) // +#define SLC_POP_IDLE_CNT 0x0000FFFF +#endif +#define SLC_POP_IDLE_CNT_S 0 + +#define SLC_TXLINK_DSCR (REG_SLC_BASE + 0x60) +#define SLC_TXLINK_DSCR_BF0 (REG_SLC_BASE + 0x64) +#define SLC_TXLINK_DSCR_BF1 (REG_SLC_BASE + 0x68) +#define SLC_RXLINK_DSCR (REG_SLC_BASE + 0x6C) +#define SLC_RXLINK_DSCR_BF0 (REG_SLC_BASE + 0x70) +#define SLC_RXLINK_DSCR_BF1 (REG_SLC_BASE + 0x74) +#define SLC_DATE (REG_SLC_BASE + 0x78) +#define SLC_ID (REG_SLC_BASE + 0x7C) + +#define SLC_HOST_CONF_W0 (REG_SLC_BASE + 0x80 + 0x14) +#define SLC_HOST_CONF_W1 (REG_SLC_BASE + 0x80 + 0x18) +#define SLC_HOST_CONF_W2 (REG_SLC_BASE + 0x80 + 0x20) +#define SLC_HOST_CONF_W3 (REG_SLC_BASE + 0x80 + 0x24) +#define SLC_HOST_CONF_W4 (REG_SLC_BASE + 0x80 + 0x28) + +#define SLC_HOST_INTR_ST (REG_SLC_BASE + 0x80 + 0x1c) +#define SLC_HOST_INTR_CLR (REG_SLC_BASE + 0x80 + 0x30) +#define SLC_HOST_INTR_SOF_BIT (BIT(12)) + +#define SLC_HOST_INTR_ENA (REG_SLC_BASE + 0x80 + 0x34) +#define SLC_RX_NEW_PACKET_INT_ENA (BIT23) +#define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT0) +#define SLC_HOST_CONF_W5 (REG_SLC_BASE + 0x80 + 0x3C) +#define SLC_HOST_INTR_RAW (REG_SLC_BASE + 0x80 + 0x8) +#define SLC_HOST_INTR_ENA_BIT (BIT(23)) +//[15:12]: 0x3ff9xxxx -- 0b01 from_host +// 0x3ffaxxxx -- 0b10 general +// 0x3ffbxxxx -- 0b11 to_host +#define SLC_DATA_ADDR_CLEAR_MASK (~(0xf<<12)) +#define SLC_FROM_HOST_ADDR_MASK (0x1<<12) +#define SLC_TO_HOST_ADDR_MASK (0x3<<12) + +#define SLC_SET_FROM_HOST_ADDR_MASK(v) do { \ + (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ + (v) |= SLC_FROM_HOST_ADDR_MASK; \ +} while(0); + +#define SLC_SET_TO_HOST_ADDR_MASK(v) do { \ + (v) &= SLC_DATA_ADDR_CLEAR_MASK; \ + (v) |= SLC_TO_HOST_ADDR_MASK; \ +} while(0); + + +#define SLC_TX_DESC_DEBUG_REG 0x3ff0002c //[15:0] set to 0xcccc + + +#endif // SLC_REGISTER_H_INCLUDED diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/user_config.h new file mode 100644 index 0000000000..60ebcbf119 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/user_config.h @@ -0,0 +1,36 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define AT_CUSTOM_UPGRADE + +#ifdef AT_CUSTOM_UPGRADE + #ifndef AT_UPGRADE_SUPPORT + #error "upgrade is not supported when eagle.flash.bin+eagle.irom0text.bin!!!" + #endif +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/version.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/version.h new file mode 100644 index 0000000000..e38099af6a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/include/version.h @@ -0,0 +1,23 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/at_upgrade.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/at_upgrade.c new file mode 100644 index 0000000000..4408025e53 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/at_upgrade.c @@ -0,0 +1,304 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "c_types.h" +#include "user_interface.h" +#include "espconn.h" +#include "mem.h" +#include "osapi.h" +#include "upgrade.h" + +#ifdef AT_UPGRADE_SUPPORT +#ifdef AT_CUSTOM_UPGRADE + +#define UPGRADE_FRAME "{\"path\": \"/v1/messages/\", \"method\": \"POST\", \"meta\": {\"Authorization\": \"token %s\"},\ +\"get\":{\"action\":\"%s\"},\"body\":{\"pre_rom_version\":\"%s\",\"rom_version\":\"%s\"}}\n" + +#define pheadbuffer "Connection: keep-alive\r\n\ +Cache-Control: no-cache\r\n\ +User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 \r\n\ +Accept: */*\r\n\ +Accept-Encoding: gzip,deflate\r\n\ +Accept-Language: zh-CN,eb-US;q=0.8\r\n\r\n" + +/**/ + + +struct espconn *pespconn = NULL; +struct upgrade_server_info *upServer = NULL; + +static os_timer_t at_delay_check; +static struct espconn *pTcpServer = NULL; +static ip_addr_t host_ip; +/****************************************************************************** + * FunctionName : user_esp_platform_upgrade_cb + * Description : Processing the downloaded data from the server + * Parameters : pespconn -- the espconn used to connetion with the host + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_rsp(void *arg) +{ + struct upgrade_server_info *server = arg; + + + if(server->upgrade_flag == true) + { + os_printf("device_upgrade_success\r\n"); + at_response_ok(); + system_upgrade_reboot(); + } + else + { + os_printf("device_upgrade_failed\r\n"); + at_response_error(); + } + + os_free(server->url); + server->url = NULL; + os_free(server); + server = NULL; +} +/** + * @brief Tcp client disconnect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_discon_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t idTemp = 0; + + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + if(pespconn != NULL) + { + os_free(pespconn); + } + + os_printf("disconnect\r\n"); + + if(system_upgrade_start(upServer) == false) + { + at_response_error(); + } + else + { + at_port_print("+CIPUPDATE:4\r\n"); + } +} + +/** + * @brief Udp server receive data callback function. + * @param arg: contain the ip link information + * @retval None + */ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_recv(void *arg, char *pusrdata, unsigned short len) +{ + struct espconn *pespconn = (struct espconn *)arg; + char temp[32] = {0}; + uint8_t user_bin[12] = {0}; + uint8_t i = 0; + + os_timer_disarm(&at_delay_check); + at_port_print("+CIPUPDATE:3\r\n"); + + upServer = (struct upgrade_server_info *)os_zalloc(sizeof(struct upgrade_server_info)); + + upServer->upgrade_version[5] = '\0'; + + upServer->pespconn = pespconn; + + os_memcpy(upServer->ip, pespconn->proto.tcp->remote_ip, 4); + + upServer->port = pespconn->proto.tcp->remote_port; + + upServer->check_cb = at_upDate_rsp; + upServer->check_times = 60000; + + if(upServer->url == NULL) + { + upServer->url = (uint8 *) os_zalloc(1024); + } + + if(system_upgrade_userbin_check() == UPGRADE_FW_BIN1) + { + os_memcpy(user_bin, "user2.bin", 10); + } + else if(system_upgrade_userbin_check() == UPGRADE_FW_BIN2) + { + os_memcpy(user_bin, "user1.bin", 10); + } + + os_sprintf(upServer->url, + "GET /%s HTTP/1.1\r\nHost: "IPSTR"\r\n"pheadbuffer"", + user_bin, IP2STR(upServer->ip)); +} + +LOCAL void ICACHE_FLASH_ATTR +at_upDate_wait(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + if(pespconn != NULL) + { + espconn_disconnect(pespconn); + } + else + { + at_response_error(); + } +} + +/****************************************************************************** + * FunctionName : user_esp_platform_sent_cb + * Description : Data has been sent successfully and acknowledged by the remote host. + * Parameters : arg -- Additional argument to pass to the callback function + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +at_upDate_sent_cb(void *arg) +{ + struct espconn *pespconn = arg; + os_timer_disarm(&at_delay_check); + os_timer_setfn(&at_delay_check, (os_timer_func_t *)at_upDate_wait, pespconn); + os_timer_arm(&at_delay_check, 5000, 0); + os_printf("at_upDate_sent_cb\r\n"); +} + +/** + * @brief Tcp client connect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_connect_cb(void *arg) +{ + struct espconn *pespconn = (struct espconn *)arg; + uint8_t user_bin[9] = {0}; + char *temp = NULL; + + at_port_print("+CIPUPDATE:2\r\n"); + + + espconn_regist_disconcb(pespconn, at_upDate_discon_cb); + espconn_regist_recvcb(pespconn, at_upDate_recv);//////// + espconn_regist_sentcb(pespconn, at_upDate_sent_cb); + + temp = (uint8 *) os_zalloc(512); + + os_sprintf(temp,"GET /v1/device/rom/?is_format_simple=true HTTP/1.0\r\nHost: "IPSTR"\r\n"pheadbuffer"", + IP2STR(pespconn->proto.tcp->remote_ip)); + + espconn_sent(pespconn, temp, os_strlen(temp)); + os_free(temp); +} + +/** + * @brief Tcp client connect repeat callback function. + * @param arg: contain the ip link information + * @retval None + */ +static void ICACHE_FLASH_ATTR +at_upDate_recon_cb(void *arg, sint8 errType) +{ + struct espconn *pespconn = (struct espconn *)arg; + + at_response_error(); + if(pespconn->proto.tcp != NULL) + { + os_free(pespconn->proto.tcp); + } + os_free(pespconn); + os_printf("disconnect\r\n"); + + if(upServer != NULL) + { + os_free(upServer); + upServer = NULL; + } + at_response_error(); + +} + +/****************************************************************************** + * FunctionName : upServer_dns_found + * Description : dns found callback + * Parameters : name -- pointer to the name that was looked up. + * ipaddr -- pointer to an ip_addr_t containing the IP address of + * the hostname, or NULL if the name could not be found (or on any + * other error). + * callback_arg -- a user-specified callback argument passed to + * dns_gethostbyname + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +upServer_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pespconn = (struct espconn *) arg; +// char temp[32]; + + if(ipaddr == NULL) + { + at_response_error(); + return; + } + at_port_print("+CIPUPDATE:1\r\n"); + + + if(host_ip.addr == 0 && ipaddr->addr != 0) + { + if(pespconn->type == ESPCONN_TCP) + { + os_memcpy(pespconn->proto.tcp->remote_ip, &ipaddr->addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); + } + } +} + +void ICACHE_FLASH_ATTR +at_exeCmdCiupdate(uint8_t id) +{ + pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); + pespconn->type = ESPCONN_TCP; + pespconn->state = ESPCONN_NONE; + pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + pespconn->proto.tcp->local_port = espconn_port(); + pespconn->proto.tcp->remote_port = 80; + + host_ip.addr = ipaddr_addr("192.168.0.107"); + at_port_print("+CIPUPDATE:1\r\n"); + os_memcpy(pespconn->proto.tcp->remote_ip, &host_ip.addr, 4); + espconn_regist_connectcb(pespconn, at_upDate_connect_cb); + espconn_regist_reconcb(pespconn, at_upDate_recon_cb); + espconn_connect(pespconn); +} +#endif +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/user_main.c new file mode 100755 index 0000000000..a3fd6c94c1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/at_sdio/user/user_main.c @@ -0,0 +1,230 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "at_custom.h" +#include "user_interface.h" + +#include "driver/sdio_slv.h" + +#ifdef SDIO_DEBUG +static os_timer_t at_spi_check; +uint32 sum_len = 0; +extern void ICACHE_FLASH_ATTR at_spi_check_cb(void *arg); +#endif + +uint32 at_fake_uart_rx(uint8* data,uint32 length); +typedef void (*at_fake_uart_tx_func_type)(const uint8*data,uint32 length); +bool at_fake_uart_enable(bool enable,at_fake_uart_tx_func_type at_fake_uart_tx_func); + +typedef void (*at_custom_uart_rx_buffer_fetch_cb_type)(void); +void at_register_uart_rx_buffer_fetch_cb(at_custom_uart_rx_buffer_fetch_cb_type rx_buffer_fetch_cb); +// test :AT+TEST=1,"abc"<,3> +void ICACHE_FLASH_ATTR +at_setupCmdTest(uint8_t id, char *pPara) +{ + int result = 0, err = 0, flag = 0; + uint8 buffer[32] = {0}; + pPara++; // skip '=' + + //get the first parameter + // digit + flag = at_get_next_int_dec(&pPara, &result, &err); + + // flag must be ture because there are more parameter + if (flag == FALSE) { + at_response_error(); + return; + } + + if (*pPara++ != ',') { // skip ',' + at_response_error(); + return; + } + + os_sprintf(buffer, "the first parameter:%d\r\n", result); + at_port_print(buffer); + + //get the second parameter + // string + at_data_str_copy(buffer, &pPara, 10); + at_port_print("the second parameter:"); + at_port_print(buffer); + at_port_print("\r\n"); + + if (*pPara == ',') { + pPara++; // skip ',' + result = 0; + //there is the third parameter + // digit + flag = at_get_next_int_dec(&pPara, &result, &err); + // we donot care of flag + os_sprintf(buffer, "the third parameter:%d\r\n", result); + at_port_print(buffer); + } + + if (*pPara != '\r') { + at_response_error(); + return; + } + + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_testCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_testCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_queryCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_queryCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +void ICACHE_FLASH_ATTR +at_exeCmdTest(uint8_t id) +{ + uint8 buffer[32] = {0}; + + os_sprintf(buffer, "%s\r\n", "at_exeCmdTest"); + at_port_print(buffer); + at_response_ok(); +} + +extern void at_exeCmdCiupdate(uint8_t id); +at_funcationType at_custom_cmd[] = { + {"+TEST", 5, at_testCmdTest, at_queryCmdTest, at_setupCmdTest, at_exeCmdTest}, +#ifdef AT_UPGRADE_SUPPORT + {"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdCiupdate} +#endif +}; + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABBBCDDD + * A : rf cal + * B : at parameters + * C : rf init data + * D : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ + system_phy_freq_trace_enable(at_get_rf_auto_trace_from_flash()); +} + +void ICACHE_FLASH_ATTR at_sdio_response(const uint8*data,uint32 length) +{ + if((data == NULL) || (length == 0)) { + return; + } + + sdio_load_data(data,length); +} + +uint32 sdio_recv_data_callback(uint8* data,uint32 len) +{ + return at_fake_uart_rx(data,len); +} + +extern void at_custom_uart_rx_buffer_fetch_cb(void); + +void ICACHE_FLASH_ATTR user_init(void) +{ + char buf[64] = {0}; + at_customLinkMax = 5; + sdio_slave_init(); + sdio_register_recv_cb(sdio_recv_data_callback); + at_init(); + at_register_uart_rx_buffer_fetch_cb(at_custom_uart_rx_buffer_fetch_cb); + os_sprintf(buf,"compile time:%s %s",__DATE__,__TIME__); + at_set_custom_info(buf); + at_fake_uart_enable(TRUE,at_sdio_response); + + at_cmd_array_regist(&at_custom_cmd[0], sizeof(at_custom_cmd)/sizeof(at_custom_cmd[0])); + + espconn_tcp_set_wnd(4); + at_port_print("\r\nready\r\n"); + +#ifdef SDIO_DEBUG + os_timer_disarm(&at_spi_check); + os_timer_setfn(&at_spi_check, (os_timer_func_t *)at_spi_check_cb, NULL); + os_timer_arm(&at_spi_check, 1000, 1); + os_printf("\r\ntimer start\r\n"); +#endif +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/Makefile new file mode 100644 index 0000000000..a21fcad725 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/Makefile @@ -0,0 +1,131 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user \ + mqtt \ + modules + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a \ + mqtt/libmqtt.a \ + modules/libmodules.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lupgrade\ + -lssl \ + -lpwm \ + -ldriver \ + -lsmartconfig \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH \ + -DGLOBAL_DEBUG_ON + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include -I $(PDIR)include/mqtt -I $(PDIR)include/modules +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/README.md b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/README.md new file mode 100644 index 0000000000..de9a1f2f8c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/README.md @@ -0,0 +1,77 @@ + +# Simple MQTT Client Demo + +This example implement: +- MQTT Publish the Message +- MQTT Subscribe the Topic +- MQTT works with SSL/TLS +- MQTT works with one-way anthentication +- MQTT works with two-way anthentication + +# How to make the Demo work + +### Step 1: Start the MQTT broker + +you could choose [mosquitto](https://mosquitto.org) or [EMQTT](https://github.com/emqtt/emqttd) as your MQTT broker + +### Step 2: Configurate your demo + +All you need to configurate are in mqtt_config.h, please according to the comment to modify: +- CFG_HOLDER +- MQTT_HOST +- MQTT_PORT +- MQTT_CLIENT_ID +- MQTT_USER +- MQTT_PASS +- STA_SSID +- STA_PASS +- DEFAULT_SECURITY +- CA_CERT_FLASH_ADDRESS +- CLIENT_CERT_FLASH_ADDRESS + +### Step 3(optional): Generate your certificate for SSL/TLS + +if you configurate DEFAULT_SECURITY to ONE_WAY_ANTHENTICATION or TWO_WAY_ANTHENTICATION, please according to [tools/README.txt](../../tools/README.md) to generate your certificate + +### Step 4: Build your demo + +``` +$./gen_misc.sh +``` + +compile options: 1 1 2 0 5, or others if you are familar to it. + +### Step 5: Flash your demo + +Any way is OK,such as: +``` +$~/esp/esp-idf/components/esptool_py/esptool/esptool.py --port /dev/ttyUSB0 --baud 921600 write_flash 0x00000 ~/ESP8266_NONOS_SDK/bin/boot_v1.6.bin 0x1000 ../bin/upgrade/user1.2048.new.5.bin 0x1fe000 ~/ESP8266_NONOS_SDK/bin/blank.bin 0x1fc000 ~/ESP8266_NONOS_SDK/bin/esp_init_data_default.bin +``` + +### Step 6(optional): Flash your certificate + +Any way is OK, but your flashing address is same as the Step 2,such as: + +``` +$~/esp/esp-idf/components/esptool_py/esptool/esptool.py --port /dev/ttyUSB0 --baud 921600 write_flash 0x77000 ~/ESP8266_NONOS_SDK/tools/bin/esp_ca_cert.bin +$~/esp/esp-idf/components/esptool_py/esptool/esptool.py --port /dev/ttyUSB0 --baud 921600 write_flash 0x78000 ~/MQTTESP8266/tools/bin/esp_cert_private_key.bin +``` +### Run the demo and Result Shows + +when the demo starts up: +- it would subscribe the topic `/mqtt/topic/0` , `/mqtt/topic/1` , `/mqtt/topic/2` +- it would publish the topic `/mqtt/topic/0` , `/mqtt/topic/1` , `/mqtt/topic/2` +- MQTT broker would receive subscribe and publish + +### Troubleshooting + +**why the demo connect the WiFi failed?** +- try to modify CFG_HOLDER + +**why the handshake failed?** + +- try to uncomment espconn_secure_set_size and modify memory allocate +- make sure your MQTT broker SSL/TLS certificate configurate valid + + + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.bat new file mode 100644 index 0000000000..8856e66e33 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.sh new file mode 100755 index 0000000000..173023af2b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" +make clean +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart.h new file mode 100644 index 0000000000..353135c584 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart.h @@ -0,0 +1,125 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef UART_APP_H +#define UART_APP_H + +#include "uart_register.h" +#include "eagle_soc.h" +#include "c_types.h" + +#define RX_BUFF_SIZE 256 +#define TX_BUFF_SIZE 100 +#define UART0 0 +#define UART1 1 + +typedef enum { + FIVE_BITS = 0x0, + SIX_BITS = 0x1, + SEVEN_BITS = 0x2, + EIGHT_BITS = 0x3 +} UartBitsNum4Char; + +typedef enum { + ONE_STOP_BIT = 0, + ONE_HALF_STOP_BIT = BIT2, + TWO_STOP_BIT = BIT2 +} UartStopBitsNum; + +typedef enum { + NONE_BITS = 0, + ODD_BITS = 0, + EVEN_BITS = BIT4 +} UartParityMode; + +typedef enum { + STICK_PARITY_DIS = 0, + STICK_PARITY_EN = BIT3 | BIT5 +} UartExistParity; + +typedef enum { + BIT_RATE_9600 = 9600, + BIT_RATE_19200 = 19200, + BIT_RATE_38400 = 38400, + BIT_RATE_57600 = 57600, + BIT_RATE_74880 = 74880, + BIT_RATE_115200 = 115200, + BIT_RATE_230400 = 230400, + BIT_RATE_256000 = 256000, + BIT_RATE_460800 = 460800, + BIT_RATE_921600 = 921600 +} UartBautRate; + +typedef enum { + NONE_CTRL, + HARDWARE_CTRL, + XON_XOFF_CTRL +} UartFlowCtrl; + +typedef enum { + EMPTY, + UNDER_WRITE, + WRITE_OVER +} RcvMsgBuffState; + +typedef struct { + uint32 RcvBuffSize; + uint8 *pRcvMsgBuff; + uint8 *pWritePos; + uint8 *pReadPos; + uint8 TrigLvl; //JLU: may need to pad + RcvMsgBuffState BuffState; +} RcvMsgBuff; + +typedef struct { + uint32 TrxBuffSize; + uint8 *pTrxBuff; +} TrxMsgBuff; + +typedef enum { + BAUD_RATE_DET, + WAIT_SYNC_FRM, + SRCH_MSG_HEAD, + RCV_MSG_BODY, + RCV_ESC_CHAR, +} RcvMsgState; + +typedef struct { + UartBautRate baut_rate; + UartBitsNum4Char data_bits; + UartExistParity exist_parity; + UartParityMode parity; // chip size in byte + UartStopBitsNum stop_bits; + UartFlowCtrl flow_ctrl; + RcvMsgBuff rcv_buff; + TrxMsgBuff trx_buff; + RcvMsgState rcv_state; + int received; + int buff_uart_no; //indicate which uart use tx/rx buffer +} UartDevice; + +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +void uart0_sendStr(const char *str); +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart_register.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart_register.h new file mode 100644 index 0000000000..fa27ac6d6d --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/driver/uart_register.h @@ -0,0 +1,147 @@ +//Generated at 2012-07-03 18:44:06 +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef UART_REGISTER_H_INCLUDED +#define UART_REGISTER_H_INCLUDED +#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) +//version value:32'h062000 + +#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) +#define UART_RXFIFO_RD_BYTE 0x000000FF +#define UART_RXFIFO_RD_BYTE_S 0 + +#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) +#define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) +#define UART_BRK_DET_INT_RAW (BIT(7)) +#define UART_CTS_CHG_INT_RAW (BIT(6)) +#define UART_DSR_CHG_INT_RAW (BIT(5)) +#define UART_RXFIFO_OVF_INT_RAW (BIT(4)) +#define UART_FRM_ERR_INT_RAW (BIT(3)) +#define UART_PARITY_ERR_INT_RAW (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) +#define UART_RXFIFO_FULL_INT_RAW (BIT(0)) + +#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) +#define UART_RXFIFO_TOUT_INT_ST (BIT(8)) +#define UART_BRK_DET_INT_ST (BIT(7)) +#define UART_CTS_CHG_INT_ST (BIT(6)) +#define UART_DSR_CHG_INT_ST (BIT(5)) +#define UART_RXFIFO_OVF_INT_ST (BIT(4)) +#define UART_FRM_ERR_INT_ST (BIT(3)) +#define UART_PARITY_ERR_INT_ST (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) +#define UART_RXFIFO_FULL_INT_ST (BIT(0)) + +#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) +#define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) +#define UART_BRK_DET_INT_ENA (BIT(7)) +#define UART_CTS_CHG_INT_ENA (BIT(6)) +#define UART_DSR_CHG_INT_ENA (BIT(5)) +#define UART_RXFIFO_OVF_INT_ENA (BIT(4)) +#define UART_FRM_ERR_INT_ENA (BIT(3)) +#define UART_PARITY_ERR_INT_ENA (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) +#define UART_RXFIFO_FULL_INT_ENA (BIT(0)) + +#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) +#define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) +#define UART_BRK_DET_INT_CLR (BIT(7)) +#define UART_CTS_CHG_INT_CLR (BIT(6)) +#define UART_DSR_CHG_INT_CLR (BIT(5)) +#define UART_RXFIFO_OVF_INT_CLR (BIT(4)) +#define UART_FRM_ERR_INT_CLR (BIT(3)) +#define UART_PARITY_ERR_INT_CLR (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) +#define UART_RXFIFO_FULL_INT_CLR (BIT(0)) + +#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) +#define UART_CLKDIV_CNT 0x000FFFFF +#define UART_CLKDIV_S 0 + +#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) +#define UART_GLITCH_FILT 0x000000FF +#define UART_GLITCH_FILT_S 8 +#define UART_AUTOBAUD_EN (BIT(0)) + +#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) +#define UART_TXD (BIT(31)) +#define UART_RTSN (BIT(30)) +#define UART_DTRN (BIT(29)) +#define UART_TXFIFO_CNT 0x000000FF +#define UART_TXFIFO_CNT_S 16 +#define UART_RXD (BIT(15)) +#define UART_CTSN (BIT(14)) +#define UART_DSRN (BIT(13)) +#define UART_RXFIFO_CNT 0x000000FF +#define UART_RXFIFO_CNT_S 0 + +#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) +#define UART_TXFIFO_RST (BIT(18)) +#define UART_RXFIFO_RST (BIT(17)) +#define UART_IRDA_EN (BIT(16)) +#define UART_TX_FLOW_EN (BIT(15)) +#define UART_LOOPBACK (BIT(14)) +#define UART_IRDA_RX_INV (BIT(13)) +#define UART_IRDA_TX_INV (BIT(12)) +#define UART_IRDA_WCTL (BIT(11)) +#define UART_IRDA_TX_EN (BIT(10)) +#define UART_IRDA_DPLX (BIT(9)) +#define UART_TXD_BRK (BIT(8)) +#define UART_SW_DTR (BIT(7)) +#define UART_SW_RTS (BIT(6)) +#define UART_STOP_BIT_NUM 0x00000003 +#define UART_STOP_BIT_NUM_S 4 +#define UART_BIT_NUM 0x00000003 +#define UART_BIT_NUM_S 2 +#define UART_PARITY_EN (BIT(1)) +#define UART_PARITY (BIT(0)) + +#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) +#define UART_RX_TOUT_EN (BIT(31)) +#define UART_RX_TOUT_THRHD 0x0000007F +#define UART_RX_TOUT_THRHD_S 24 +#define UART_RX_FLOW_EN (BIT(23)) +#define UART_RX_FLOW_THRHD 0x0000007F +#define UART_RX_FLOW_THRHD_S 16 +#define UART_TXFIFO_EMPTY_THRHD 0x0000007F +#define UART_TXFIFO_EMPTY_THRHD_S 8 +#define UART_RXFIFO_FULL_THRHD 0x0000007F +#define UART_RXFIFO_FULL_THRHD_S 0 + +#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) +#define UART_LOWPULSE_MIN_CNT 0x000FFFFF +#define UART_LOWPULSE_MIN_CNT_S 0 + +#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) +#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF +#define UART_HIGHPULSE_MIN_CNT_S 0 + +#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) +#define UART_PULSE_NUM_CNT 0x0003FF +#define UART_PULSE_NUM_CNT_S 0 + +#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) +#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) +#endif // UART_REGISTER_H_INCLUDED diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/config.h new file mode 100644 index 0000000000..ac84ff2900 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/config.h @@ -0,0 +1,61 @@ +/* config.h +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef USER_CONFIG_H_ +#define USER_CONFIG_H_ +#include "os_type.h" +#include "user_config.h" +typedef struct{ + uint32_t cfg_holder; + uint8_t device_id[32]; + + uint8_t sta_ssid[64]; + uint8_t sta_pwd[64]; + uint32_t sta_type; + + uint8_t mqtt_host[64]; + uint32_t mqtt_port; + uint8_t mqtt_user[32]; + uint8_t mqtt_pass[32]; + uint32_t mqtt_keepalive; + uint8_t security; +} SYSCFG; + +typedef struct { + uint8 flag; + uint8 pad[3]; +} SAVE_FLAG; + +void ICACHE_FLASH_ATTR CFG_Save(); +void ICACHE_FLASH_ATTR CFG_Load(); + +extern SYSCFG sysCfg; + +#endif /* USER_CONFIG_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/wifi.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/wifi.h new file mode 100644 index 0000000000..64fa4ac2f1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/modules/wifi.h @@ -0,0 +1,15 @@ +/* + * wifi.h + * + * Created on: Dec 30, 2014 + * Author: Minh + */ + +#ifndef USER_WIFI_H_ +#define USER_WIFI_H_ +#include "os_type.h" +typedef void (*WifiCallback)(uint8_t); +void ICACHE_FLASH_ATTR WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb); + + +#endif /* USER_WIFI_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/debug.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/debug.h new file mode 100644 index 0000000000..3879573bb6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/debug.h @@ -0,0 +1,23 @@ +/* + * debug.h + * + * Created on: Dec 4, 2014 + * Author: Minh + */ + +#ifndef USER_DEBUG_H_ +#define USER_DEBUG_H_ + +#if defined(GLOBAL_DEBUG_ON) +#define MQTT_DEBUG_ON +#endif +#if defined(MQTT_DEBUG_ON) +#define INFO( format, ... ) os_printf( format, ## __VA_ARGS__ ) +#else +#define INFO( format, ... ) +#endif +// #ifndef INFO +// #define INFO os_printf +// #endif + +#endif /* USER_DEBUG_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt.h new file mode 100644 index 0000000000..862c481ed2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt.h @@ -0,0 +1,148 @@ +/* mqtt.h +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef USER_AT_MQTT_H_ +#define USER_AT_MQTT_H_ +#include "mqtt_config.h" +#include "mqtt_msg.h" +#include "user_interface.h" + +#include "queue.h" +typedef struct mqtt_event_data_t +{ + uint8_t type; + const char* topic; + const char* data; + uint16_t topic_length; + uint16_t data_length; + uint16_t data_offset; +} mqtt_event_data_t; + +typedef struct mqtt_state_t +{ + uint16_t port; + int auto_reconnect; + mqtt_connect_info_t* connect_info; + uint8_t* in_buffer; + uint8_t* out_buffer; + int in_buffer_length; + int out_buffer_length; + uint16_t message_length; + uint16_t message_length_read; + mqtt_message_t* outbound_message; + mqtt_connection_t mqtt_connection; + uint16_t pending_msg_id; + int pending_msg_type; + int pending_publish_qos; +} mqtt_state_t; + +typedef enum { + WIFI_INIT, + WIFI_CONNECTING, + WIFI_CONNECTING_ERROR, + WIFI_CONNECTED, + DNS_RESOLVE, + TCP_DISCONNECTING, + TCP_DISCONNECTED, + TCP_RECONNECT_DISCONNECTING, + TCP_RECONNECT_REQ, + TCP_RECONNECT, + TCP_CONNECTING, + TCP_CONNECTING_ERROR, + TCP_CONNECTED, + MQTT_CONNECT_SEND, + MQTT_CONNECT_SENDING, + MQTT_SUBSCIBE_SEND, + MQTT_SUBSCIBE_SENDING, + MQTT_DATA, + MQTT_KEEPALIVE_SEND, + MQTT_PUBLISH_RECV, + MQTT_PUBLISHING, + MQTT_DELETING, + MQTT_DELETED, +} tConnState; + +typedef void (*MqttCallback)(uint32_t *args); +typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh); + +typedef struct { + struct espconn *pCon; + uint8_t security; + uint8_t* host; + uint32_t port; + ip_addr_t ip; + mqtt_state_t mqtt_state; + mqtt_connect_info_t connect_info; + MqttCallback connectedCb; + MqttCallback disconnectedCb; + MqttCallback publishedCb; + MqttCallback timeoutCb; + MqttDataCallback dataCb; + ETSTimer mqttTimer; + uint32_t keepAliveTick; + uint32_t reconnectTick; + uint32_t sendTimeout; + tConnState connState; + QUEUE msgQueue; + void* user_data; +} MQTT_Client; + +#define SEC_NONSSL 0 +#define SEC_SSL 1 + +#define MQTT_FLAG_CONNECTED 1 +#define MQTT_FLAG_READY 2 +#define MQTT_FLAG_EXIT 4 + +#define MQTT_EVENT_TYPE_NONE 0 +#define MQTT_EVENT_TYPE_CONNECTED 1 +#define MQTT_EVENT_TYPE_DISCONNECTED 2 +#define MQTT_EVENT_TYPE_SUBSCRIBED 3 +#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4 +#define MQTT_EVENT_TYPE_PUBLISH 5 +#define MQTT_EVENT_TYPE_PUBLISHED 6 +#define MQTT_EVENT_TYPE_EXITED 7 +#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8 + +void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security); +void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession); +void ICACHE_FLASH_ATTR MQTT_DeleteClient(MQTT_Client *mqttClient); +void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); +void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb); +void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb); +void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb); +void ICACHE_FLASH_ATTR MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb); +void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb); +BOOL ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos); +BOOL ICACHE_FLASH_ATTR MQTT_UnSubscribe(MQTT_Client *client, char* topic); +void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient); +void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient); +BOOL ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain); + +#endif /* USER_AT_MQTT_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt_msg.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt_msg.h new file mode 100644 index 0000000000..1e6bf0efaf --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/mqtt_msg.h @@ -0,0 +1,130 @@ +/* + * File: mqtt_msg.h + * Author: Minh Tuan + * + * Created on July 12, 2014, 1:05 PM + */ + +#ifndef MQTT_MSG_H +#define MQTT_MSG_H +#include "mqtt_config.h" +#include "c_types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ +/* 7 6 5 4 3 2 1 0*/ +/*| --- Message Type---- | DUP Flag | QoS Level | Retain | +/* Remaining Length */ + + +enum mqtt_message_type +{ + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +typedef struct mqtt_message +{ + uint8_t* data; + uint16_t length; + +} mqtt_message_t; + +typedef struct mqtt_connection +{ + mqtt_message_t message; + + uint16_t message_id; + uint8_t* buffer; + uint16_t buffer_length; + +} mqtt_connection_t; + +typedef struct mqtt_connect_info +{ + char* client_id; + char* username; + char* password; + char* will_topic; + char* will_message; + int keepalive; + int will_qos; + int will_retain; + int clean_session; + +} mqtt_connect_info_t; + + +static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } +static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } +static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } +static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } + +void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); +int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length); +const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length); +const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length); +uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length); + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); + + +#ifdef __cplusplus +} +#endif + +#endif /* MQTT_MSG_H */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/proto.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/proto.h new file mode 100644 index 0000000000..4c452b5654 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/proto.h @@ -0,0 +1,32 @@ +/* + * File: proto.h + * Author: ThuHien + * + * Created on November 23, 2012, 8:57 AM + */ + +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include +#include "typedef.h" +#include "ringbuf.h" + +typedef void(PROTO_PARSE_CALLBACK)(); + +typedef struct{ + U8 *buf; + U16 bufSize; + U16 dataLen; + U8 isEsc; + U8 isBegin; + PROTO_PARSE_CALLBACK* callback; +}PROTO_PARSER; + +I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize); +I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len); +I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize); +I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len); +I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value); +I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen); +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/queue.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/queue.h new file mode 100644 index 0000000000..5f277a6015 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/queue.h @@ -0,0 +1,44 @@ +/* str_queue.h -- +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef USER_QUEUE_H_ +#define USER_QUEUE_H_ +#include "os_type.h" +#include "ringbuf.h" +typedef struct { + uint8_t *buf; + RINGBUF rb; +} QUEUE; + +void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize); +int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len); +int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); +BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue); +#endif /* USER_QUEUE_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/ringbuf.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/ringbuf.h new file mode 100644 index 0000000000..6c6d6e68b6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/ringbuf.h @@ -0,0 +1,19 @@ +#ifndef _RING_BUF_H_ +#define _RING_BUF_H_ + +#include +#include +#include "typedef.h" + +typedef struct{ + U8* p_o; /**< Original pointer */ + U8* volatile p_r; /**< Read pointer */ + U8* volatile p_w; /**< Write pointer */ + volatile I32 fill_cnt; /**< Number of filled slots */ + I32 size; /**< Buffer size */ +}RINGBUF; + +I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size); +I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c); +I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/typedef.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/typedef.h new file mode 100644 index 0000000000..a4c69d6d01 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/typedef.h @@ -0,0 +1,17 @@ +/** +* \file +* Standard Types definition +*/ + +#ifndef _TYPE_DEF_H_ +#define _TYPE_DEF_H_ + +typedef char I8; +typedef unsigned char U8; +typedef short I16; +typedef unsigned short U16; +typedef long I32; +typedef unsigned long U32; +typedef unsigned long long U64; + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/utils.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/utils.h new file mode 100644 index 0000000000..175befff4e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include "c_types.h" + +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s); +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip); +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt_config.h new file mode 100644 index 0000000000..708be87a6b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/mqtt_config.h @@ -0,0 +1,46 @@ +#ifndef __MQTT_CONFIG_H__ +#define __MQTT_CONFIG_H__ + +typedef enum{ + NO_TLS = 0, // 0: disable SSL/TLS, there must be no certificate verify between MQTT server and ESP8266 + TLS_WITHOUT_AUTHENTICATION = 1, // 1: enable SSL/TLS, but there is no a certificate verify + ONE_WAY_ANTHENTICATION = 2, // 2: enable SSL/TLS, ESP8266 would verify the SSL server certificate at the same time + TWO_WAY_ANTHENTICATION = 3, // 3: enable SSL/TLS, ESP8266 would verify the SSL server certificate and SSL server would verify ESP8266 certificate +}TLS_LEVEL; + + +/*IMPORTANT: the following configuration maybe need modified*/ +/***********************************************************************************************************************/ +#define CFG_HOLDER 0x00FF55A4 /* Change this value to load default configurations */ + +/*DEFAULT CONFIGURATIONS*/ + +#define MQTT_HOST "192.168.1.100" // the IP address or domain name of your MQTT server or MQTT broker ,such as "mqtt.yourdomain.com" +#define MQTT_PORT 1883 // the listening port of your MQTT server or MQTT broker +#define MQTT_CLIENT_ID "Device_ID" // the ID of yourself, any string is OK,client would use this ID register itself to MQTT server +#define MQTT_USER "Device_Name" // your MQTT login name, if MQTT server allow anonymous login,any string is OK, otherwise, please input valid login name which you had registered +#define MQTT_PASS "Device_Passwd" // you MQTT login password, same as above +#define STA_SSID "AP_SSID" // your AP/router SSID to config your device networking +#define STA_PASS "AP_Passwd" // your AP/router password + +#define DEFAULT_SECURITY NO_TLS // very important: you must config DEFAULT_SECURITY for SSL/TLS + +#define CA_CERT_FLASH_ADDRESS 0x77 // CA certificate address in flash to read, 0x77 means address 0x77000 +#define CLIENT_CERT_FLASH_ADDRESS 0x78 // client certificate and private key address in flash to read, 0x78 means address 0x78000 +/***********************************************************************************************************************/ + + +/*Please Keep the following configuration if you have no very deep understanding of ESP SSL/TLS*/ +#define CFG_LOCATION 0x79 /* Please don't change or if you know what you doing */ +#define MQTT_BUF_SIZE 1024 +#define MQTT_KEEPALIVE 120 /*second*/ +#define MQTT_RECONNECT_TIMEOUT 5 /*second*/ +#define MQTT_SSL_ENABLE //* Please don't change or if you know what you doing */ + +#define STA_TYPE AUTH_WPA2_PSK +#define QUEUE_BUFFER_SIZE 2048 + +#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ +//PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ + +#endif // __MQTT_CONFIG_H__ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/user_config.h new file mode 100644 index 0000000000..231a11838b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/include/user_config.h @@ -0,0 +1,7 @@ +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#define USE_OPTIMIZE_PRINTF + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/Makefile new file mode 100644 index 0000000000..62e0b43845 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libmodules.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/config.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/config.c new file mode 100644 index 0000000000..fd2c60f8a1 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/config.c @@ -0,0 +1,110 @@ +/* +/* config.c +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ +#include "ets_sys.h" +#include "os_type.h" +#include "mem.h" +#include "osapi.h" +#include "user_interface.h" + +#include "mqtt.h" +#include "config.h" +#include "user_config.h" +#include "debug.h" + +SYSCFG sysCfg; +SAVE_FLAG saveFlag; + +void ICACHE_FLASH_ATTR +CFG_Save() +{ + spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE, + (uint32 *)&saveFlag, sizeof(SAVE_FLAG)); + + if (saveFlag.flag == 0) { + spi_flash_erase_sector(CFG_LOCATION + 1); + spi_flash_write((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, + (uint32 *)&sysCfg, sizeof(SYSCFG)); + saveFlag.flag = 1; + spi_flash_erase_sector(CFG_LOCATION + 3); + spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE, + (uint32 *)&saveFlag, sizeof(SAVE_FLAG)); + } else { + spi_flash_erase_sector(CFG_LOCATION + 0); + spi_flash_write((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE, + (uint32 *)&sysCfg, sizeof(SYSCFG)); + saveFlag.flag = 0; + spi_flash_erase_sector(CFG_LOCATION + 3); + spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE, + (uint32 *)&saveFlag, sizeof(SAVE_FLAG)); + } +} + +void ICACHE_FLASH_ATTR +CFG_Load() +{ + + INFO("\r\nload ...\r\n"); + spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE, + (uint32 *)&saveFlag, sizeof(SAVE_FLAG)); + if (saveFlag.flag == 0) { + spi_flash_read((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE, + (uint32 *)&sysCfg, sizeof(SYSCFG)); + } else { + spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, + (uint32 *)&sysCfg, sizeof(SYSCFG)); + } + if(sysCfg.cfg_holder != CFG_HOLDER){ + os_memset(&sysCfg, 0x00, sizeof sysCfg); + + + sysCfg.cfg_holder = CFG_HOLDER; + + os_sprintf(sysCfg.device_id, MQTT_CLIENT_ID, system_get_chip_id()); + sysCfg.device_id[sizeof(sysCfg.device_id) - 1] = '\0'; + os_strncpy(sysCfg.sta_ssid, STA_SSID, sizeof(sysCfg.sta_ssid) - 1); + os_strncpy(sysCfg.sta_pwd, STA_PASS, sizeof(sysCfg.sta_pwd) - 1); + sysCfg.sta_type = STA_TYPE; + + os_strncpy(sysCfg.mqtt_host, MQTT_HOST, sizeof(sysCfg.mqtt_host) - 1); + sysCfg.mqtt_port = MQTT_PORT; + os_strncpy(sysCfg.mqtt_user, MQTT_USER, sizeof(sysCfg.mqtt_user) - 1); + os_strncpy(sysCfg.mqtt_pass, MQTT_PASS, sizeof(sysCfg.mqtt_pass) - 1); + + sysCfg.security = DEFAULT_SECURITY; /* default non ssl */ + + sysCfg.mqtt_keepalive = MQTT_KEEPALIVE; + + INFO(" default configuration\r\n"); + + CFG_Save(); + } + +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/wifi.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/wifi.c new file mode 100644 index 0000000000..c7c45fd02e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/modules/wifi.c @@ -0,0 +1,100 @@ +/* + * wifi.c + * + * Created on: Dec 30, 2014 + * Author: Minh + */ +#include "wifi.h" +#include "user_interface.h" +#include "osapi.h" +#include "espconn.h" +#include "os_type.h" +#include "mem.h" +#include "mqtt_msg.h" +#include "debug.h" +#include "user_config.h" +#include "config.h" + +static ETSTimer WiFiLinker; +WifiCallback wifiCb = NULL; +static uint8_t wifiStatus = STATION_IDLE, lastWifiStatus = STATION_IDLE; +static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg) +{ + struct ip_info ipConfig; + + os_timer_disarm(&WiFiLinker); + wifi_get_ip_info(STATION_IF, &ipConfig); + wifiStatus = wifi_station_get_connect_status(); + if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0) + { + + os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); + os_timer_arm(&WiFiLinker, 2000, 0); + + + } + else + { + if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD) + { + + INFO("STATION_WRONG_PASSWORD\r\n"); + wifi_station_connect(); + + + } + else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND) + { + + INFO("STATION_NO_AP_FOUND\r\n"); + wifi_station_connect(); + + + } + else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL) + { + + INFO("STATION_CONNECT_FAIL\r\n"); + wifi_station_connect(); + + } + else + { + INFO("STATION_IDLE\r\n"); + } + + os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); + os_timer_arm(&WiFiLinker, 500, 0); + } + if(wifiStatus != lastWifiStatus){ + lastWifiStatus = wifiStatus; + if(wifiCb) + wifiCb(wifiStatus); + } +} + +void ICACHE_FLASH_ATTR WIFI_Connect(uint8_t* ssid, uint8_t* pass, WifiCallback cb) +{ + struct station_config stationConf; + + INFO("WIFI_INIT\r\n"); + wifi_set_opmode_current(STATION_MODE); + + //wifi_station_set_auto_connect(FALSE); + wifiCb = cb; + + os_memset(&stationConf, 0, sizeof(struct station_config)); + + os_sprintf(stationConf.ssid, "%s", ssid); + os_sprintf(stationConf.password, "%s", pass); + + wifi_station_set_config_current(&stationConf); + + os_timer_disarm(&WiFiLinker); + os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); + os_timer_arm(&WiFiLinker, 1000, 0); + + //wifi_station_set_auto_connect(TRUE); + wifi_station_connect(); +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/Makefile new file mode 100644 index 0000000000..db53f43865 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libmqtt.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/debug.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/debug.h new file mode 100644 index 0000000000..3879573bb6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/debug.h @@ -0,0 +1,23 @@ +/* + * debug.h + * + * Created on: Dec 4, 2014 + * Author: Minh + */ + +#ifndef USER_DEBUG_H_ +#define USER_DEBUG_H_ + +#if defined(GLOBAL_DEBUG_ON) +#define MQTT_DEBUG_ON +#endif +#if defined(MQTT_DEBUG_ON) +#define INFO( format, ... ) os_printf( format, ## __VA_ARGS__ ) +#else +#define INFO( format, ... ) +#endif +// #ifndef INFO +// #define INFO os_printf +// #endif + +#endif /* USER_DEBUG_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt.h new file mode 100644 index 0000000000..862c481ed2 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt.h @@ -0,0 +1,148 @@ +/* mqtt.h +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef USER_AT_MQTT_H_ +#define USER_AT_MQTT_H_ +#include "mqtt_config.h" +#include "mqtt_msg.h" +#include "user_interface.h" + +#include "queue.h" +typedef struct mqtt_event_data_t +{ + uint8_t type; + const char* topic; + const char* data; + uint16_t topic_length; + uint16_t data_length; + uint16_t data_offset; +} mqtt_event_data_t; + +typedef struct mqtt_state_t +{ + uint16_t port; + int auto_reconnect; + mqtt_connect_info_t* connect_info; + uint8_t* in_buffer; + uint8_t* out_buffer; + int in_buffer_length; + int out_buffer_length; + uint16_t message_length; + uint16_t message_length_read; + mqtt_message_t* outbound_message; + mqtt_connection_t mqtt_connection; + uint16_t pending_msg_id; + int pending_msg_type; + int pending_publish_qos; +} mqtt_state_t; + +typedef enum { + WIFI_INIT, + WIFI_CONNECTING, + WIFI_CONNECTING_ERROR, + WIFI_CONNECTED, + DNS_RESOLVE, + TCP_DISCONNECTING, + TCP_DISCONNECTED, + TCP_RECONNECT_DISCONNECTING, + TCP_RECONNECT_REQ, + TCP_RECONNECT, + TCP_CONNECTING, + TCP_CONNECTING_ERROR, + TCP_CONNECTED, + MQTT_CONNECT_SEND, + MQTT_CONNECT_SENDING, + MQTT_SUBSCIBE_SEND, + MQTT_SUBSCIBE_SENDING, + MQTT_DATA, + MQTT_KEEPALIVE_SEND, + MQTT_PUBLISH_RECV, + MQTT_PUBLISHING, + MQTT_DELETING, + MQTT_DELETED, +} tConnState; + +typedef void (*MqttCallback)(uint32_t *args); +typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh); + +typedef struct { + struct espconn *pCon; + uint8_t security; + uint8_t* host; + uint32_t port; + ip_addr_t ip; + mqtt_state_t mqtt_state; + mqtt_connect_info_t connect_info; + MqttCallback connectedCb; + MqttCallback disconnectedCb; + MqttCallback publishedCb; + MqttCallback timeoutCb; + MqttDataCallback dataCb; + ETSTimer mqttTimer; + uint32_t keepAliveTick; + uint32_t reconnectTick; + uint32_t sendTimeout; + tConnState connState; + QUEUE msgQueue; + void* user_data; +} MQTT_Client; + +#define SEC_NONSSL 0 +#define SEC_SSL 1 + +#define MQTT_FLAG_CONNECTED 1 +#define MQTT_FLAG_READY 2 +#define MQTT_FLAG_EXIT 4 + +#define MQTT_EVENT_TYPE_NONE 0 +#define MQTT_EVENT_TYPE_CONNECTED 1 +#define MQTT_EVENT_TYPE_DISCONNECTED 2 +#define MQTT_EVENT_TYPE_SUBSCRIBED 3 +#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4 +#define MQTT_EVENT_TYPE_PUBLISH 5 +#define MQTT_EVENT_TYPE_PUBLISHED 6 +#define MQTT_EVENT_TYPE_EXITED 7 +#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8 + +void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security); +void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession); +void ICACHE_FLASH_ATTR MQTT_DeleteClient(MQTT_Client *mqttClient); +void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); +void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb); +void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb); +void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb); +void ICACHE_FLASH_ATTR MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb); +void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb); +BOOL ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos); +BOOL ICACHE_FLASH_ATTR MQTT_UnSubscribe(MQTT_Client *client, char* topic); +void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient); +void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient); +BOOL ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain); + +#endif /* USER_AT_MQTT_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt_msg.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt_msg.h new file mode 100644 index 0000000000..1e6bf0efaf --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/mqtt_msg.h @@ -0,0 +1,130 @@ +/* + * File: mqtt_msg.h + * Author: Minh Tuan + * + * Created on July 12, 2014, 1:05 PM + */ + +#ifndef MQTT_MSG_H +#define MQTT_MSG_H +#include "mqtt_config.h" +#include "c_types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ +/* 7 6 5 4 3 2 1 0*/ +/*| --- Message Type---- | DUP Flag | QoS Level | Retain | +/* Remaining Length */ + + +enum mqtt_message_type +{ + MQTT_MSG_TYPE_CONNECT = 1, + MQTT_MSG_TYPE_CONNACK = 2, + MQTT_MSG_TYPE_PUBLISH = 3, + MQTT_MSG_TYPE_PUBACK = 4, + MQTT_MSG_TYPE_PUBREC = 5, + MQTT_MSG_TYPE_PUBREL = 6, + MQTT_MSG_TYPE_PUBCOMP = 7, + MQTT_MSG_TYPE_SUBSCRIBE = 8, + MQTT_MSG_TYPE_SUBACK = 9, + MQTT_MSG_TYPE_UNSUBSCRIBE = 10, + MQTT_MSG_TYPE_UNSUBACK = 11, + MQTT_MSG_TYPE_PINGREQ = 12, + MQTT_MSG_TYPE_PINGRESP = 13, + MQTT_MSG_TYPE_DISCONNECT = 14 +}; + +typedef struct mqtt_message +{ + uint8_t* data; + uint16_t length; + +} mqtt_message_t; + +typedef struct mqtt_connection +{ + mqtt_message_t message; + + uint16_t message_id; + uint8_t* buffer; + uint16_t buffer_length; + +} mqtt_connection_t; + +typedef struct mqtt_connect_info +{ + char* client_id; + char* username; + char* password; + char* will_topic; + char* will_message; + int keepalive; + int will_qos; + int will_retain; + int clean_session; + +} mqtt_connect_info_t; + + +static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } +static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } +static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } +static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } + +void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); +int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length); +const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length); +const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length); +uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length); + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); + + +#ifdef __cplusplus +} +#endif + +#endif /* MQTT_MSG_H */ + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/proto.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/proto.h new file mode 100644 index 0000000000..4c452b5654 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/proto.h @@ -0,0 +1,32 @@ +/* + * File: proto.h + * Author: ThuHien + * + * Created on November 23, 2012, 8:57 AM + */ + +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include +#include "typedef.h" +#include "ringbuf.h" + +typedef void(PROTO_PARSE_CALLBACK)(); + +typedef struct{ + U8 *buf; + U16 bufSize; + U16 dataLen; + U8 isEsc; + U8 isBegin; + PROTO_PARSE_CALLBACK* callback; +}PROTO_PARSER; + +I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize); +I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len); +I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize); +I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len); +I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value); +I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen); +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/queue.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/queue.h new file mode 100644 index 0000000000..5f277a6015 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/queue.h @@ -0,0 +1,44 @@ +/* str_queue.h -- +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef USER_QUEUE_H_ +#define USER_QUEUE_H_ +#include "os_type.h" +#include "ringbuf.h" +typedef struct { + uint8_t *buf; + RINGBUF rb; +} QUEUE; + +void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize); +int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len); +int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); +BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue); +#endif /* USER_QUEUE_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/ringbuf.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/ringbuf.h new file mode 100644 index 0000000000..6c6d6e68b6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/ringbuf.h @@ -0,0 +1,19 @@ +#ifndef _RING_BUF_H_ +#define _RING_BUF_H_ + +#include +#include +#include "typedef.h" + +typedef struct{ + U8* p_o; /**< Original pointer */ + U8* volatile p_r; /**< Read pointer */ + U8* volatile p_w; /**< Write pointer */ + volatile I32 fill_cnt; /**< Number of filled slots */ + I32 size; /**< Buffer size */ +}RINGBUF; + +I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size); +I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c); +I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/typedef.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/typedef.h new file mode 100644 index 0000000000..a4c69d6d01 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/typedef.h @@ -0,0 +1,17 @@ +/** +* \file +* Standard Types definition +*/ + +#ifndef _TYPE_DEF_H_ +#define _TYPE_DEF_H_ + +typedef char I8; +typedef unsigned char U8; +typedef short I16; +typedef unsigned short U16; +typedef long I32; +typedef unsigned long U32; +typedef unsigned long long U64; + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/utils.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/utils.h new file mode 100644 index 0000000000..175befff4e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/include/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include "c_types.h" + +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s); +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip); +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str); +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt.c new file mode 100644 index 0000000000..3a030d2366 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt.c @@ -0,0 +1,894 @@ +/* mqtt.c +* Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "user_interface.h" +#include "osapi.h" +#include "espconn.h" +#include "os_type.h" +#include "mem.h" +#include "mqtt_msg.h" +#include "debug.h" +#include "user_config.h" +#include "mqtt.h" +#include "queue.h" + +#define MQTT_TASK_PRIO 2 +#define MQTT_TASK_QUEUE_SIZE 1 +#define MQTT_SEND_TIMOUT 5 + +#ifndef QUEUE_BUFFER_SIZE +#define QUEUE_BUFFER_SIZE 2048 +#endif + +unsigned char *default_certificate; +unsigned int default_certificate_len = 0; +unsigned char *default_private_key; +unsigned int default_private_key_len = 0; + +os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE]; + +LOCAL void ICACHE_FLASH_ATTR +mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) +{ + struct espconn *pConn = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pConn->reverse; + + + if (ipaddr == NULL) + { + INFO("DNS: Found, but got no ip, try to reconnect\r\n"); + client->connState = TCP_RECONNECT_REQ; + return; + } + + INFO("DNS: found ip %d.%d.%d.%d\n", + *((uint8 *) &ipaddr->addr), + *((uint8 *) &ipaddr->addr + 1), + *((uint8 *) &ipaddr->addr + 2), + *((uint8 *) &ipaddr->addr + 3)); + + if (client->ip.addr == 0 && ipaddr->addr != 0) + { + os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); + if (client->security) { +#ifdef MQTT_SSL_ENABLE + if(DEFAULT_SECURITY >= ONE_WAY_ANTHENTICATION ) { + espconn_secure_ca_enable(ESPCONN_CLIENT,CA_CERT_FLASH_ADDRESS); + } + if(DEFAULT_SECURITY >= TWO_WAY_ANTHENTICATION) { + espconn_secure_cert_req_enable(ESPCONN_CLIENT,CLIENT_CERT_FLASH_ADDRESS); + } + + espconn_secure_connect(client->pCon); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + espconn_connect(client->pCon); + } + + client->connState = TCP_CONNECTING; + INFO("TCP: connecting...\r\n"); + } + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + + + +LOCAL void ICACHE_FLASH_ATTR +deliver_publish(MQTT_Client* client, uint8_t* message, int length) +{ + mqtt_event_data_t event_data; + + event_data.topic_length = length; + event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length); + event_data.data_length = length; + event_data.data = mqtt_get_publish_data(message, &event_data.data_length); + + if (client->dataCb) + client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length); + +} + +void ICACHE_FLASH_ATTR +mqtt_send_keepalive(MQTT_Client *client) +{ + INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); + client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); + client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); + client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + + client->sendTimeout = MQTT_SEND_TIMOUT; + INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); + err_t result = ESPCONN_OK; + if (client->security) { +#ifdef MQTT_SSL_ENABLE + result = espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + result = espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + } + + client->mqtt_state.outbound_message = NULL; + if(ESPCONN_OK == result) { + client->keepAliveTick = 0; + client->connState = MQTT_DATA; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + } + else { + client->connState = TCP_RECONNECT_DISCONNECTING; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + } +} + +/** + * @brief Delete tcp client and free all memory + * @param mqttClient: The mqtt client which contain TCP client + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_delete(MQTT_Client *mqttClient) +{ + if (mqttClient->pCon != NULL) { + INFO("Free memory\r\n"); + espconn_delete(mqttClient->pCon); + if (mqttClient->pCon->proto.tcp) + os_free(mqttClient->pCon->proto.tcp); + os_free(mqttClient->pCon); + mqttClient->pCon = NULL; + } +} + +/** + * @brief Delete MQTT client and free all memory + * @param mqttClient: The mqtt client + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_client_delete(MQTT_Client *mqttClient) +{ + mqtt_tcpclient_delete(mqttClient); + if (mqttClient->host != NULL) { + os_free(mqttClient->host); + mqttClient->host = NULL; + } + + if (mqttClient->user_data != NULL) { + os_free(mqttClient->user_data); + mqttClient->user_data = NULL; + } + + if(mqttClient->connect_info.client_id != NULL) { + os_free(mqttClient->connect_info.client_id); + mqttClient->connect_info.client_id = NULL; + } + + if(mqttClient->connect_info.username != NULL) { + os_free(mqttClient->connect_info.username); + mqttClient->connect_info.username = NULL; + } + + if(mqttClient->connect_info.password != NULL) { + os_free(mqttClient->connect_info.password); + mqttClient->connect_info.password = NULL; + } + + if(mqttClient->connect_info.will_topic != NULL) { + os_free(mqttClient->connect_info.will_topic); + mqttClient->connect_info.will_topic = NULL; + } + + if(mqttClient->connect_info.will_message != NULL) { + os_free(mqttClient->connect_info.will_message); + mqttClient->connect_info.will_message = NULL; + } + + if(mqttClient->mqtt_state.in_buffer != NULL) { + os_free(mqttClient->mqtt_state.in_buffer); + mqttClient->mqtt_state.in_buffer = NULL; + } + + if(mqttClient->mqtt_state.out_buffer != NULL) { + os_free(mqttClient->mqtt_state.out_buffer); + mqttClient->mqtt_state.out_buffer = NULL; + } +} + + +/** + * @brief Client received callback function. + * @param arg: contain the ip link information + * @param pdata: received data + * @param len: the lenght of received data + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len) +{ + uint8_t msg_type; + uint8_t msg_qos; + uint16_t msg_id; + + struct espconn *pCon = (struct espconn*)arg; + MQTT_Client *client = (MQTT_Client *)pCon->reverse; + + client->keepAliveTick = 0; +READPACKET: + INFO("TCP: data received %d bytes\r\n", len); + if (len < MQTT_BUF_SIZE && len > 0) { + os_memcpy(client->mqtt_state.in_buffer, pdata, len); + + msg_type = mqtt_get_type(client->mqtt_state.in_buffer); + msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); + msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); + switch (client->connState) { + case MQTT_CONNECT_SENDING: + if (msg_type == MQTT_MSG_TYPE_CONNACK) { + if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT) { + INFO("MQTT: Invalid packet\r\n"); + if (client->security) { +#ifdef MQTT_SSL_ENABLE + espconn_secure_disconnect(client->pCon); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + espconn_disconnect(client->pCon); + } + } else { + INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port); + client->connState = MQTT_DATA; + if (client->connectedCb) + client->connectedCb((uint32_t*)client); + } + + } + break; + case MQTT_DATA: + case MQTT_KEEPALIVE_SEND: + client->mqtt_state.message_length_read = len; + client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); + + + switch (msg_type) + { + + case MQTT_MSG_TYPE_SUBACK: + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) + INFO("MQTT: Subscribe successful\r\n"); + break; + case MQTT_MSG_TYPE_UNSUBACK: + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) + INFO("MQTT: UnSubscribe successful\r\n"); + break; + case MQTT_MSG_TYPE_PUBLISH: + if (msg_qos == 1) + client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); + else if (msg_qos == 2) + client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); + if (msg_qos == 1 || msg_qos == 2) { + INFO("MQTT: Queue response QoS: %d\r\n", msg_qos); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + } + } + + deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); + break; + case MQTT_MSG_TYPE_PUBACK: + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { + INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n"); + } + + break; + case MQTT_MSG_TYPE_PUBREC: + client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + } + break; + case MQTT_MSG_TYPE_PUBREL: + client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + } + break; + case MQTT_MSG_TYPE_PUBCOMP: + if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { + INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n"); + } + break; + case MQTT_MSG_TYPE_PINGREQ: + client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection); + if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + } + break; + case MQTT_MSG_TYPE_PINGRESP: + // Ignore + break; + } + // NOTE: this is done down here and not in the switch case above + // because the PSOCK_READBUF_LEN() won't work inside a switch + // statement due to the way protothreads resume. + if (msg_type == MQTT_MSG_TYPE_PUBLISH) + { + len = client->mqtt_state.message_length_read; + + if (client->mqtt_state.message_length < client->mqtt_state.message_length_read) + { + //client->connState = MQTT_PUBLISH_RECV; + //Not Implement yet + len -= client->mqtt_state.message_length; + pdata += client->mqtt_state.message_length; + + INFO("Get another published message\r\n"); + goto READPACKET; + } + + } + break; + } + } else { + INFO("ERROR: Message too long\r\n"); + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** + * @brief Client send over callback function. + * @param arg: contain the ip link information + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_sent_cb(void *arg) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + INFO("TCP: Sent\r\n"); + client->sendTimeout = 0; + client->keepAliveTick =0; + + if ((client->connState == MQTT_DATA || client->connState == MQTT_KEEPALIVE_SEND) + && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) { + if (client->publishedCb) + client->publishedCb((uint32_t*)client); + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +void ICACHE_FLASH_ATTR mqtt_timer(void *arg) +{ + MQTT_Client* client = (MQTT_Client*)arg; + + if (client->connState == MQTT_DATA) { + client->keepAliveTick ++; + if (client->keepAliveTick > client->mqtt_state.connect_info->keepalive) { + client->connState = MQTT_KEEPALIVE_SEND; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + } + + } else if (client->connState == TCP_RECONNECT_REQ) { + client->reconnectTick ++; + if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { + client->reconnectTick = 0; + client->connState = TCP_RECONNECT; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + if (client->timeoutCb) + client->timeoutCb((uint32_t*)client); + } + } + if (client->sendTimeout > 0) + client->sendTimeout --; +} + +void ICACHE_FLASH_ATTR +mqtt_tcpclient_discon_cb(void *arg) +{ + + struct espconn *pespconn = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pespconn->reverse; + INFO("TCP: Disconnected callback\r\n"); + if(TCP_DISCONNECTING == client->connState) { + client->connState = TCP_DISCONNECTED; + } + else if(MQTT_DELETING == client->connState) { + client->connState = MQTT_DELETED; + } + else { + client->connState = TCP_RECONNECT_REQ; + } + if (client->disconnectedCb) + client->disconnectedCb((uint32_t*)client); + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + + + +/** + * @brief Tcp client connect success callback function. + * @param arg: contain the ip link information + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_connect_cb(void *arg) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + + espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); + espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// + espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// + INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); + + mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); + client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); + client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); + client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + + + client->sendTimeout = MQTT_SEND_TIMOUT; + INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); + if (client->security) { +#ifdef MQTT_SSL_ENABLE + espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); + } + + client->mqtt_state.outbound_message = NULL; + client->connState = MQTT_CONNECT_SENDING; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); +} + +/** + * @brief Tcp client connect repeat callback function. + * @param arg: contain the ip link information + * @retval None + */ +void ICACHE_FLASH_ATTR +mqtt_tcpclient_recon_cb(void *arg, sint8 errType) +{ + struct espconn *pCon = (struct espconn *)arg; + MQTT_Client* client = (MQTT_Client *)pCon->reverse; + + INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port); + + client->connState = TCP_RECONNECT_REQ; + + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + +} + +/** + * @brief MQTT publish function. + * @param client: MQTT_Client reference + * @param topic: string topic will publish to + * @param data: buffer data send point to + * @param data_length: length of data + * @param qos: qos + * @param retain: retain + * @retval TRUE if success queue + */ +BOOL ICACHE_FLASH_ATTR +MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain) +{ + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, + topic, data, data_length, + qos, retain, + &client->mqtt_state.pending_msg_id); + if (client->mqtt_state.outbound_message->length == 0) { + INFO("MQTT: Queuing publish failed\r\n"); + return FALSE; + } + INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + INFO("MQTT: Serious buffer error\r\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +/** + * @brief MQTT subscibe function. + * @param client: MQTT_Client reference + * @param topic: string topic will subscribe + * @param qos: qos + * @retval TRUE if success queue + */ +BOOL ICACHE_FLASH_ATTR +MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos) +{ + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + + client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, + topic, qos, + &client->mqtt_state.pending_msg_id); + INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id); + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + INFO("MQTT: Serious buffer error\r\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +/** + * @brief MQTT un-subscibe function. + * @param client: MQTT_Client reference + * @param topic: String topic will un-subscribe + * @retval TRUE if success queue + */ +BOOL ICACHE_FLASH_ATTR +MQTT_UnSubscribe(MQTT_Client *client, char* topic) +{ + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection, + topic, + &client->mqtt_state.pending_msg_id); + INFO("MQTT: queue un-subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id); + while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { + INFO("MQTT: Queue full\r\n"); + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + INFO("MQTT: Serious buffer error\r\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +/** + * @brief MQTT ping function. + * @param client: MQTT_Client reference + * @retval TRUE if success queue + */ +BOOL ICACHE_FLASH_ATTR +MQTT_Ping(MQTT_Client *client) +{ + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); + if(client->mqtt_state.outbound_message->length == 0){ + INFO("MQTT: Queuing publish failed\r\n"); + return FALSE; + } + INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); + while(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ + INFO("MQTT: Queue full\r\n"); + if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { + INFO("MQTT: Serious buffer error\r\n"); + return FALSE; + } + } + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); + return TRUE; +} + +void ICACHE_FLASH_ATTR +MQTT_Task(os_event_t *e) +{ + MQTT_Client* client = (MQTT_Client*)e->par; + uint8_t dataBuffer[MQTT_BUF_SIZE]; + uint16_t dataLen; + if (e->par == 0) + return; + switch (client->connState) { + + case TCP_RECONNECT_REQ: + break; + case TCP_RECONNECT: + mqtt_tcpclient_delete(client); + MQTT_Connect(client); + INFO("TCP: Reconnect to: %s:%d\r\n", client->host, client->port); + client->connState = TCP_CONNECTING; + break; + case MQTT_DELETING: + case TCP_DISCONNECTING: + case TCP_RECONNECT_DISCONNECTING: + if (client->security) { +#ifdef MQTT_SSL_ENABLE + espconn_secure_disconnect(client->pCon); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + espconn_disconnect(client->pCon); + } + break; + case TCP_DISCONNECTED: + INFO("MQTT: Disconnected\r\n"); + mqtt_tcpclient_delete(client); + break; + case MQTT_DELETED: + INFO("MQTT: Deleted client\r\n"); + mqtt_client_delete(client); + break; + case MQTT_KEEPALIVE_SEND: + mqtt_send_keepalive(client); + break; + case MQTT_DATA: + if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) { + break; + } + if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0) { + client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer); + client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen); + + + client->sendTimeout = MQTT_SEND_TIMOUT; + INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); + if (client->security) { +#ifdef MQTT_SSL_ENABLE + espconn_secure_send(client->pCon, dataBuffer, dataLen); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else { + espconn_send(client->pCon, dataBuffer, dataLen); + } + + client->mqtt_state.outbound_message = NULL; + break; + } + break; + } +} + +/** + * @brief MQTT initialization connection function + * @param client: MQTT_Client reference + * @param host: Domain or IP string + * @param port: Port to connect + * @param security: 1 for ssl, 0 for none + * @retval None + */ +void ICACHE_FLASH_ATTR +MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security) +{ + uint32_t temp; + INFO("MQTT_InitConnection\r\n"); + os_memset(mqttClient, 0, sizeof(MQTT_Client)); + temp = os_strlen(host); + mqttClient->host = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->host, host); + mqttClient->host[temp] = 0; + mqttClient->port = port; + mqttClient->security = security; + +} + +/** + * @brief MQTT initialization mqtt client function + * @param client: MQTT_Client reference + * @param clientid: MQTT client id + * @param client_user:MQTT client user + * @param client_pass:MQTT client password + * @param client_pass:MQTT keep alive timer, in second + * @retval None + */ +void ICACHE_FLASH_ATTR +MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) +{ + uint32_t temp; + INFO("MQTT_InitClient\r\n"); + + os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); + + temp = os_strlen(client_id); + mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->connect_info.client_id, client_id); + mqttClient->connect_info.client_id[temp] = 0; + + if (client_user) + { + temp = os_strlen(client_user); + mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->connect_info.username, client_user); + mqttClient->connect_info.username[temp] = 0; + } + + if (client_pass) + { + temp = os_strlen(client_pass); + mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->connect_info.password, client_pass); + mqttClient->connect_info.password[temp] = 0; + } + + + mqttClient->connect_info.keepalive = keepAliveTime; + mqttClient->connect_info.clean_session = cleanSession; + + mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); + mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; + mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); + mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; + mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; + + mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); + + QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); + + system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); +} +void ICACHE_FLASH_ATTR +MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) +{ + uint32_t temp; + temp = os_strlen(will_topic); + mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->connect_info.will_topic, will_topic); + mqttClient->connect_info.will_topic[temp] = 0; + + temp = os_strlen(will_msg); + mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1); + os_strcpy(mqttClient->connect_info.will_message, will_msg); + mqttClient->connect_info.will_message[temp] = 0; + + + mqttClient->connect_info.will_qos = will_qos; + mqttClient->connect_info.will_retain = will_retain; +} +/** + * @brief Begin connect to MQTT broker + * @param client: MQTT_Client reference + * @retval None + */ +void ICACHE_FLASH_ATTR +MQTT_Connect(MQTT_Client *mqttClient) +{ + //espconn_secure_set_size(0x01,6*1024); // try to modify memory size 6*1024 if ssl/tls handshake failed + if (mqttClient->pCon) { + // Clean up the old connection forcefully - using MQTT_Disconnect + // does not actually release the old connection until the + // disconnection callback is invoked. + mqtt_tcpclient_delete(mqttClient); + } + mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); + mqttClient->pCon->type = ESPCONN_TCP; + mqttClient->pCon->state = ESPCONN_NONE; + mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); + mqttClient->pCon->proto.tcp->local_port = espconn_port(); + mqttClient->pCon->proto.tcp->remote_port = mqttClient->port; + mqttClient->pCon->reverse = mqttClient; + espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb); + espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb); + + mqttClient->keepAliveTick = 0; + mqttClient->reconnectTick = 0; + + + os_timer_disarm(&mqttClient->mqttTimer); + os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient); + os_timer_arm(&mqttClient->mqttTimer, 1000, 1); + + os_printf("your ESP SSL/TLS configuration is %d.[0:NO_TLS\t1:TLS_WITHOUT_AUTHENTICATION\t2ONE_WAY_ANTHENTICATION\t3TWO_WAY_ANTHENTICATION]\n"); + if (UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) { + INFO("TCP: Connect to ip %s:%d\r\n", mqttClient->host, mqttClient->port); + if (mqttClient->security) + { +#ifdef MQTT_SSL_ENABLE + if(DEFAULT_SECURITY >= ONE_WAY_ANTHENTICATION ) { + espconn_secure_ca_enable(ESPCONN_CLIENT,CA_CERT_FLASH_ADDRESS); + } + if(DEFAULT_SECURITY >= TWO_WAY_ANTHENTICATION) { + espconn_secure_cert_req_enable(ESPCONN_CLIENT,CLIENT_CERT_FLASH_ADDRESS); + } + espconn_secure_connect(mqttClient->pCon); +#else + INFO("TCP: Do not support SSL\r\n"); +#endif + } + else + { + espconn_connect(mqttClient->pCon); + } + } + else { + INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port); + espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found); + } + mqttClient->connState = TCP_CONNECTING; +} + +void ICACHE_FLASH_ATTR +MQTT_Disconnect(MQTT_Client *mqttClient) +{ + mqttClient->connState = TCP_DISCONNECTING; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); + os_timer_disarm(&mqttClient->mqttTimer); +} + +void ICACHE_FLASH_ATTR +MQTT_DeleteClient(MQTT_Client *mqttClient) +{ + mqttClient->connState = MQTT_DELETING; + system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); + os_timer_disarm(&mqttClient->mqttTimer); +} + +void ICACHE_FLASH_ATTR +MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb) +{ + mqttClient->connectedCb = connectedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb) +{ + mqttClient->disconnectedCb = disconnectedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb) +{ + mqttClient->dataCb = dataCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb) +{ + mqttClient->publishedCb = publishedCb; +} + +void ICACHE_FLASH_ATTR +MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb) +{ + mqttClient->timeoutCb = timeoutCb; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt_msg.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt_msg.c new file mode 100644 index 0000000000..b6c78e5010 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/mqtt_msg.c @@ -0,0 +1,473 @@ +/* +* Copyright (c) 2014, Stephen Robinson +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include +#include "mqtt_msg.h" +#include "user_config.h" +#define MQTT_MAX_FIXED_HEADER_SIZE 3 + +enum mqtt_connect_flag +{ + MQTT_CONNECT_FLAG_USERNAME = 1 << 7, + MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, + MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, + MQTT_CONNECT_FLAG_WILL = 1 << 2, + MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 +}; + +struct __attribute((__packed__)) mqtt_connect_variable_header +{ + uint8_t lengthMsb; + uint8_t lengthLsb; +#if defined(PROTOCOL_NAMEv31) + uint8_t magic[6]; +#elif defined(PROTOCOL_NAMEv311) + uint8_t magic[4]; +#else +#error "Please define protocol name" +#endif + uint8_t version; + uint8_t flags; + uint8_t keepaliveMsb; + uint8_t keepaliveLsb; +}; + +static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len) +{ + if(connection->message.length + len + 2 > connection->buffer_length) + return -1; + + connection->buffer[connection->message.length++] = len >> 8; + connection->buffer[connection->message.length++] = len & 0xff; + memcpy(connection->buffer + connection->message.length, string, len); + connection->message.length += len; + + return len + 2; +} + +static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id) +{ + // If message_id is zero then we should assign one, otherwise + // we'll use the one supplied by the caller + while(message_id == 0) + message_id = ++connection->message_id; + + if(connection->message.length + 2 > connection->buffer_length) + return 0; + + connection->buffer[connection->message.length++] = message_id >> 8; + connection->buffer[connection->message.length++] = message_id & 0xff; + + return message_id; +} + +static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection) +{ + connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; + return MQTT_MAX_FIXED_HEADER_SIZE; +} + +static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection) +{ + connection->message.data = connection->buffer; + connection->message.length = 0; + return &connection->message; +} + +static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) +{ + int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; + + if(remaining_length > 127) + { + connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + connection->buffer[1] = 0x80 | (remaining_length % 128); + connection->buffer[2] = remaining_length / 128; + connection->message.length = remaining_length + 3; + connection->message.data = connection->buffer; + } + else + { + connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); + connection->buffer[2] = remaining_length; + connection->message.length = remaining_length + 2; + connection->message.data = connection->buffer + 1; + } + + return &connection->message; +} + +void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) +{ + memset(connection, 0, sizeof(mqtt_connection_t)); + connection->buffer = buffer; + connection->buffer_length = buffer_length; +} + +int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length) +{ + int i; + int totlen = 0; + + for(i = 1; i < length; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + return totlen; +} + +const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) +{ + int i; + int totlen = 0; + int topiclen; + + for(i = 1; i < *length; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i -1)); + if((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + if(i + 2 >= *length) + return NULL; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if(i + topiclen > *length) + return NULL; + + *length = topiclen; + return (const char*)(buffer + i); +} + +const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) +{ + int i; + int totlen = 0; + int topiclen; + int blength = *length; + *length = 0; + + for(i = 1; i < blength; ++i) + { + totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); + if((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + totlen += i; + + if(i + 2 >= blength) + return NULL; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if(i + topiclen >= blength) + return NULL; + + i += topiclen; + + if(mqtt_get_qos(buffer) > 0) + { + if(i + 2 >= blength) + return NULL; + i += 2; + } + + if(totlen < i) + return NULL; + + if(totlen <= blength) + *length = totlen - i; + else + *length = blength - i; + return (const char*)(buffer + i); +} + +uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length) +{ + if(length < 1) + return 0; + + switch(mqtt_get_type(buffer)) + { + case MQTT_MSG_TYPE_PUBLISH: + { + int i; + int topiclen; + + for(i = 1; i < length; ++i) + { + if((buffer[i] & 0x80) == 0) + { + ++i; + break; + } + } + + if(i + 2 >= length) + return 0; + topiclen = buffer[i++] << 8; + topiclen |= buffer[i++]; + + if(i + topiclen >= length) + return 0; + i += topiclen; + + if(mqtt_get_qos(buffer) > 0) + { + if(i + 2 >= length) + return 0; + //i += 2; + } else { + return 0; + } + + return (buffer[i] << 8) | buffer[i + 1]; + } + case MQTT_MSG_TYPE_PUBACK: + case MQTT_MSG_TYPE_PUBREC: + case MQTT_MSG_TYPE_PUBREL: + case MQTT_MSG_TYPE_PUBCOMP: + case MQTT_MSG_TYPE_SUBACK: + case MQTT_MSG_TYPE_UNSUBACK: + case MQTT_MSG_TYPE_SUBSCRIBE: + { + // This requires the remaining length to be encoded in 1 byte, + // which it should be. + if(length >= 4 && (buffer[1] & 0x80) == 0) + return (buffer[2] << 8) | buffer[3]; + else + return 0; + } + + default: + return 0; + } +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) +{ + struct mqtt_connect_variable_header* variable_header; + + init_message(connection); + + if(connection->message.length + sizeof(*variable_header) > connection->buffer_length) + return fail_message(connection); + variable_header = (void*)(connection->buffer + connection->message.length); + connection->message.length += sizeof(*variable_header); + + variable_header->lengthMsb = 0; +#if defined(PROTOCOL_NAMEv31) + variable_header->lengthLsb = 6; + memcpy(variable_header->magic, "MQIsdp", 6); + variable_header->version = 3; +#elif defined(PROTOCOL_NAMEv311) + variable_header->lengthLsb = 4; + memcpy(variable_header->magic, "MQTT", 4); + variable_header->version = 4; +#else +#error "Please define protocol name" +#endif + + variable_header->flags = 0; + variable_header->keepaliveMsb = info->keepalive >> 8; + variable_header->keepaliveLsb = info->keepalive & 0xff; + + if(info->clean_session) + variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; + + if(info->client_id != NULL && info->client_id[0] != '\0') + { + if(append_string(connection, info->client_id, strlen(info->client_id)) < 0) + return fail_message(connection); + } + else + return fail_message(connection); + + if(info->will_topic != NULL && info->will_topic[0] != '\0') + { + if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) + return fail_message(connection); + + if(append_string(connection, info->will_message, strlen(info->will_message)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_WILL; + if(info->will_retain) + variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; + variable_header->flags |= (info->will_qos & 3) << 3; + } + + if(info->username != NULL && info->username[0] != '\0') + { + if(append_string(connection, info->username, strlen(info->username)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; + } + + if(info->password != NULL && info->password[0] != '\0') + { + if(append_string(connection, info->password, strlen(info->password)) < 0) + return fail_message(connection); + + variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; + } + + return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) +{ + init_message(connection); + + if(topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if(append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + if(qos > 0) + { + if((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + } + else + *message_id = 0; + + if(connection->message.length + data_length > connection->buffer_length) + return fail_message(connection); + memcpy(connection->buffer + connection->message.length, data, data_length); + connection->message.length += data_length; + + return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if(append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if(append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if(append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) +{ + init_message(connection); + if(append_message_id(connection, message_id) == 0) + return fail_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) +{ + init_message(connection); + + if(topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + + if(append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + if(connection->message.length + 1 > connection->buffer_length) + return fail_message(connection); + connection->buffer[connection->message.length++] = qos; + + return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) +{ + init_message(connection); + + if(topic == NULL || topic[0] == '\0') + return fail_message(connection); + + if((*message_id = append_message_id(connection, 0)) == 0) + return fail_message(connection); + + if(append_string(connection, topic, strlen(topic)) < 0) + return fail_message(connection); + + return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); +} + +mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection) +{ + init_message(connection); + return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/proto.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/proto.c new file mode 100644 index 0000000000..d3e229234b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/proto.c @@ -0,0 +1,129 @@ +#include "proto.h" +#include "ringbuf.h" +I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize) +{ + parser->buf = buf; + parser->bufSize = bufSize; + parser->dataLen = 0; + parser->callback = completeCallback; + parser->isEsc = 0; + return 0; +} + +I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value) +{ + switch(value){ + case 0x7D: + parser->isEsc = 1; + break; + + case 0x7E: + parser->dataLen = 0; + parser->isEsc = 0; + parser->isBegin = 1; + break; + + case 0x7F: + if (parser->callback != NULL) + parser->callback(); + parser->isBegin = 0; + return 0; + break; + + default: + if(parser->isBegin == 0) break; + + if(parser->isEsc){ + value ^= 0x20; + parser->isEsc = 0; + } + + if(parser->dataLen < parser->bufSize) + parser->buf[parser->dataLen++] = value; + + break; + } + return -1; +} + +I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len) +{ + while(len--) + PROTO_ParseByte(parser, *buf++); + + return 0; +} +I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen) +{ + U8 c; + + PROTO_PARSER proto; + PROTO_Init(&proto, NULL, bufOut, maxBufLen); + while(RINGBUF_Get(rb, &c) == 0){ + if(PROTO_ParseByte(&proto, c) == 0){ + *len = proto.dataLen; + return 0; + } + } + return -1; +} +I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize) +{ + U16 i = 2; + U16 len = *(U16*) packet; + + if (bufSize < 1) return -1; + + *buf++ = 0x7E; + bufSize--; + + while (len--) { + switch (*packet) { + case 0x7D: + case 0x7E: + case 0x7F: + if (bufSize < 2) return -1; + *buf++ = 0x7D; + *buf++ = *packet++ ^ 0x20; + i += 2; + bufSize -= 2; + break; + default: + if (bufSize < 1) return -1; + *buf++ = *packet++; + i++; + bufSize--; + break; + } + } + + if (bufSize < 1) return -1; + *buf++ = 0x7F; + + return i; +} + +I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len) +{ + U16 i = 2; + if(RINGBUF_Put(rb, 0x7E) == -1) return -1; + while (len--) { + switch (*packet) { + case 0x7D: + case 0x7E: + case 0x7F: + if(RINGBUF_Put(rb, 0x7D) == -1) return -1; + if(RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1; + i += 2; + break; + default: + if(RINGBUF_Put(rb, *packet++) == -1) return -1; + i++; + break; + } + } + if(RINGBUF_Put(rb, 0x7F) == -1) return -1; + + return i; +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/queue.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/queue.c new file mode 100644 index 0000000000..b6add16943 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/queue.c @@ -0,0 +1,57 @@ +/* str_queue.c +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ +#include "queue.h" + +#include "user_interface.h" +#include "osapi.h" +#include "os_type.h" +#include "mem.h" +#include "proto.h" +void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize) +{ + queue->buf = (uint8_t*)os_zalloc(bufferSize); + RINGBUF_Init(&queue->rb, queue->buf, bufferSize); +} +int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len) +{ + return PROTO_AddRb(&queue->rb, buffer, len); +} +int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen) +{ + + return PROTO_ParseRb(&queue->rb, buffer, len, maxLen); +} + +BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue) +{ + if(queue->rb.fill_cnt<=0) + return TRUE; + return FALSE; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/ringbuf.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/ringbuf.c new file mode 100644 index 0000000000..5ac3d07da6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/ringbuf.c @@ -0,0 +1,67 @@ +/** +* \file +* Ring Buffer library +*/ + +#include "ringbuf.h" + + +/** +* \brief init a RINGBUF object +* \param r pointer to a RINGBUF object +* \param buf pointer to a byte array +* \param size size of buf +* \return 0 if successfull, otherwise failed +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size) +{ + if(r == NULL || buf == NULL || size < 2) return -1; + + r->p_o = r->p_r = r->p_w = buf; + r->fill_cnt = 0; + r->size = size; + + return 0; +} +/** +* \brief put a character into ring buffer +* \param r pointer to a ringbuf object +* \param c character to be put +* \return 0 if successfull, otherwise failed +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c) +{ + if(r->fill_cnt>=r->size)return -1; // ring buffer is full, this should be atomic operation + + + r->fill_cnt++; // increase filled slots count, this should be atomic operation + + + *r->p_w++ = c; // put character into buffer + + if(r->p_w >= r->p_o + r->size) // rollback if write pointer go pass + r->p_w = r->p_o; // the physical boundary + + return 0; +} +/** +* \brief get a character from ring buffer +* \param r pointer to a ringbuf object +* \param c read character +* \return 0 if successfull, otherwise failed +*/ +I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c) +{ + if(r->fill_cnt<=0)return -1; // ring buffer is empty, this should be atomic operation + + + r->fill_cnt--; // decrease filled slots count + + + *c = *r->p_r++; // get the character out + + if(r->p_r >= r->p_o + r->size) // rollback if write pointer go pass + r->p_r = r->p_o; // the physical boundary + + return 0; +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/utils.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/utils.c new file mode 100644 index 0000000000..3ed7e508d7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/mqtt/utils.c @@ -0,0 +1,149 @@ +/* +* Copyright (c) 2014, Tuan PM +* Email: tuanpm@live.com +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*/ +#include +#include +#include +#include +#include +#include "utils.h" + + +uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str) +{ + uint8_t segs = 0; /* Segment count. */ + uint8_t chcnt = 0; /* Character count within segment. */ + uint8_t accum = 0; /* Accumulator for segment. */ + /* Catch NULL pointer. */ + if (str == 0) + return 0; + /* Process every character in string. */ + + while (*str != '\0') { + /* Segment changeover. */ + + if (*str == '.') { + /* Must have some digits in segment. */ + if (chcnt == 0) + return 0; + /* Limit number of segments. */ + if (++segs == 4) + return 0; + /* Reset segment values and restart loop. */ + chcnt = accum = 0; + str++; + continue; + } + + /* Check numeric. */ + if ((*str < '0') || (*str > '9')) + return 0; + + /* Accumulate and check segment. */ + + if ((accum = accum * 10 + *str - '0') > 255) + return 0; + /* Advance other segment specific stuff and continue loop. */ + + chcnt++; + str++; + } + + /* Check enough segments and enough characters in last segment. */ + + if (segs != 3) + return 0; + if (chcnt == 0) + return 0; + /* Address okay. */ + + return 1; +} +uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip) +{ + + /* The count of the number of bytes processed. */ + int i; + /* A pointer to the next digit to process. */ + const char * start; + + start = str; + for (i = 0; i < 4; i++) { + /* The digit being processed. */ + char c; + /* The value of this byte. */ + int n = 0; + while (1) { + c = * start; + start++; + if (c >= '0' && c <= '9') { + n *= 10; + n += c - '0'; + } + /* We insist on stopping at "." if we are still parsing + the first, second, or third numbers. If we have reached + the end of the numbers, we will allow any character. */ + else if ((i < 3 && c == '.') || i == 3) { + break; + } + else { + return 0; + } + } + if (n >= 256) { + return 0; + } + ((uint8_t*)ip)[i] = n; + } + return 1; + +} +uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s) +{ + uint32_t value = 0, digit; + int8_t c; + + while((c = *s++)){ + if('0' <= c && c <= '9') + digit = c - '0'; + else if('A' <= c && c <= 'F') + digit = c - 'A' + 10; + else if('a' <= c && c<= 'f') + digit = c - 'a' + 10; + else break; + + value = (value << 4) | digit; + } + + return value; +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/Makefile new file mode 100644 index 0000000000..dd3837c790 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/user_main.c new file mode 100644 index 0000000000..8fbe8cd2ea --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/esp_mqtt_proj/user/user_main.c @@ -0,0 +1,192 @@ +/* main.c -- MQTT client example +* +* Copyright (c) 2014-2015, Tuan PM +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of Redis nor the names of its contributors may be used +* to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ets_sys.h" +#include "driver/uart.h" +#include "osapi.h" +#include "mqtt.h" +#include "wifi.h" +#include "config.h" +#include "debug.h" +#include "gpio.h" +#include "user_interface.h" +#include "mem.h" +#include "sntp.h" + +MQTT_Client mqttClient; +typedef unsigned long u32_t; +static ETSTimer sntp_timer; + +void sntpfn() +{ + u32_t ts = 0; + ts = sntp_get_current_timestamp(); + os_printf("current time : %s\n", sntp_get_real_time(ts)); + if (ts == 0) { + //os_printf("did not get a valid time from sntp server\n"); + } else { + os_timer_disarm(&sntp_timer); + MQTT_Connect(&mqttClient); + } +} + +void wifiConnectCb(uint8_t status) +{ + if(status == STATION_GOT_IP){ + sntp_setservername(0, "pool.ntp.org"); // set sntp server after got ip address + sntp_init(); + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntpfn, NULL); + os_timer_arm(&sntp_timer, 1000, 1);//1s + } else { + MQTT_Disconnect(&mqttClient); + } +} + +void mqttConnectedCb(uint32_t *args) +{ + MQTT_Client* client = (MQTT_Client*)args; + INFO("MQTT: Connected\r\n"); + MQTT_Subscribe(client, "/mqtt/topic/0", 0); + MQTT_Subscribe(client, "/mqtt/topic/1", 1); + MQTT_Subscribe(client, "/mqtt/topic/2", 2); + + MQTT_Publish(client, "/mqtt/topic/0", "hello0", 6, 0, 0); + MQTT_Publish(client, "/mqtt/topic/1", "hello1", 6, 1, 0); + MQTT_Publish(client, "/mqtt/topic/2", "hello2", 6, 2, 0); + +} + +void mqttDisconnectedCb(uint32_t *args) +{ + MQTT_Client* client = (MQTT_Client*)args; + INFO("MQTT: Disconnected\r\n"); +} + +void mqttPublishedCb(uint32_t *args) +{ + MQTT_Client* client = (MQTT_Client*)args; + INFO("MQTT: Published\r\n"); +} + +void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) +{ + char *topicBuf = (char*)os_zalloc(topic_len+1), + *dataBuf = (char*)os_zalloc(data_len+1); + + MQTT_Client* client = (MQTT_Client*)args; + + os_memcpy(topicBuf, topic, topic_len); + topicBuf[topic_len] = 0; + + os_memcpy(dataBuf, data, data_len); + dataBuf[data_len] = 0; + + INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf); + os_free(topicBuf); + os_free(dataBuf); +} + + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector + *******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + + +void user_init(void) +{ + uart_init(BIT_RATE_115200, BIT_RATE_115200); + os_delay_us(60000); + + CFG_Load(); + + MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security); + //MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0); + + MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1); + //MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1); + + MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0); + MQTT_OnConnected(&mqttClient, mqttConnectedCb); + MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); + MQTT_OnPublished(&mqttClient, mqttPublishedCb); + MQTT_OnData(&mqttClient, mqttDataCb); + + WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb); + + INFO("\r\nSystem started ...\r\n"); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/Makefile new file mode 100644 index 0000000000..b01d653c5b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/Makefile @@ -0,0 +1,121 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ldriver \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.sh new file mode 100755 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/spi_test.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/spi_test.h new file mode 100644 index 0000000000..e241ab3a9a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/spi_test.h @@ -0,0 +1,52 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2015 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __SPI_TEST_H__ +#define __SPI_TEST_H__ + + +//***************************************************************************** +// +// Make sure all of the definitions in this header have a C binding. +// +//***************************************************************************** + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief test spi module function. + * + * @param [in] None. + * + * @return void. + */ +void spi_interface_test(void); + +#ifdef __cplusplus +} +#endif + +#endif // __SPI_TEST_H__ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/user_config.h new file mode 100644 index 0000000000..3edc1ee019 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/include/user_config.h @@ -0,0 +1,29 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/spi_test.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/spi_test.c new file mode 100644 index 0000000000..a1db0c55ec --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/spi_test.c @@ -0,0 +1,268 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2015 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "driver/spi_interface.h" +#include "eagle_soc.h" +#include "osapi.h" + + +// Show the spi registers. +#define SHOWSPIREG(i) __ShowRegValue(__func__, __LINE__); + +/** + * @brief Print debug information. + * + */ +void __ShowRegValue(const char * func, uint32_t line) +{ + + int i; + uint32_t regAddr = 0x60000140; // SPI--0x60000240, HSPI--0x60000140; + os_printf("\r\n FUNC[%s],line[%d]\r\n", func, line); + os_printf(" SPI_ADDR [0x%08x]\r\n", READ_PERI_REG(SPI_ADDR(SpiNum_HSPI))); + os_printf(" SPI_CMD [0x%08x]\r\n", READ_PERI_REG(SPI_CMD(SpiNum_HSPI))); + os_printf(" SPI_CTRL [0x%08x]\r\n", READ_PERI_REG(SPI_CTRL(SpiNum_HSPI))); + os_printf(" SPI_CTRL2 [0x%08x]\r\n", READ_PERI_REG(SPI_CTRL2(SpiNum_HSPI))); + os_printf(" SPI_CLOCK [0x%08x]\r\n", READ_PERI_REG(SPI_CLOCK(SpiNum_HSPI))); + os_printf(" SPI_RD_STATUS [0x%08x]\r\n", READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI))); + os_printf(" SPI_WR_STATUS [0x%08x]\r\n", READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI))); + os_printf(" SPI_USER [0x%08x]\r\n", READ_PERI_REG(SPI_USER(SpiNum_HSPI))); + os_printf(" SPI_USER1 [0x%08x]\r\n", READ_PERI_REG(SPI_USER1(SpiNum_HSPI))); + os_printf(" SPI_USER2 [0x%08x]\r\n", READ_PERI_REG(SPI_USER2(SpiNum_HSPI))); + os_printf(" SPI_PIN [0x%08x]\r\n", READ_PERI_REG(SPI_PIN(SpiNum_HSPI))); + os_printf(" SPI_SLAVE [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE(SpiNum_HSPI))); + os_printf(" SPI_SLAVE1 [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE1(SpiNum_HSPI))); + os_printf(" SPI_SLAVE2 [0x%08x]\r\n", READ_PERI_REG(SPI_SLAVE2(SpiNum_HSPI))); + + for (i = 0; i < 16; ++i) { + os_printf(" ADDR[0x%08x],Value[0x%08x]\r\n", regAddr, READ_PERI_REG(regAddr)); + regAddr += 4; + } + +} + + +// SPI interrupt callback function. +void spi_slave_isr_sta(void *para) +{ + uint32 regvalue; + uint32 statusW, statusR, counter; + if (READ_PERI_REG(0x3ff00020)&BIT4) { + //following 3 lines is to clear isr signal + CLEAR_PERI_REG_MASK(SPI_SLAVE(SpiNum_SPI), 0x3ff); + } else if (READ_PERI_REG(0x3ff00020)&BIT7) { //bit7 is for hspi isr, + regvalue = READ_PERI_REG(SPI_SLAVE(SpiNum_HSPI)); + os_printf("spi_slave_isr_sta SPI_SLAVE[0x%08x]\n\r", regvalue); + SPIIntClear(SpiNum_HSPI); + SET_PERI_REG_MASK(SPI_SLAVE(SpiNum_HSPI), SPI_SYNC_RESET); + SPIIntClear(SpiNum_HSPI); + + SPIIntEnable(SpiNum_HSPI, SpiIntSrc_WrStaDone + | SpiIntSrc_RdStaDone + | SpiIntSrc_WrBufDone + | SpiIntSrc_RdBufDone); + + if (regvalue & SPI_SLV_WR_BUF_DONE) { + // User can get data from the W0~W7 + os_printf("spi_slave_isr_sta : SPI_SLV_WR_BUF_DONE\n\r"); + } else if (regvalue & SPI_SLV_RD_BUF_DONE) { + // TO DO + os_printf("spi_slave_isr_sta : SPI_SLV_RD_BUF_DONE\n\r"); + } + if (regvalue & SPI_SLV_RD_STA_DONE) { + statusR = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI)); + statusW = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI)); + os_printf("spi_slave_isr_sta : SPI_SLV_RD_STA_DONE[R=0x%08x,W=0x%08x]\n\r", statusR, statusW); + } + + if (regvalue & SPI_SLV_WR_STA_DONE) { + statusR = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI)); + statusW = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI)); + os_printf("spi_slave_isr_sta : SPI_SLV_WR_STA_DONE[R=0x%08x,W=0x%08x]\n\r", statusR, statusW); + } + if ((regvalue & SPI_TRANS_DONE) && ((regvalue & 0xf) == 0)) { + os_printf("spi_slave_isr_sta : SPI_TRANS_DONE\n\r"); + + } + SHOWSPIREG(SpiNum_HSPI); + } +} + +// Test spi master interfaces. +void ICACHE_FLASH_ATTR spi_master_test() +{ + SpiAttr hSpiAttr; + hSpiAttr.bitOrder = SpiBitOrder_MSBFirst; + hSpiAttr.speed = SpiSpeed_10MHz; + hSpiAttr.mode = SpiMode_Master; + hSpiAttr.subMode = SpiSubMode_0; + + // Init HSPI GPIO + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode + + SPIInit(SpiNum_HSPI, &hSpiAttr); + uint32_t value = 0xD3D4D5D6; + uint32_t sendData[8] ={ 0 }; + SpiData spiData; + + os_printf("\r\n ============= spi init master ============= \r\n"); + +// Test 8266 slave.Communication format: 1byte command + 1bytes address + x bytes Data. + os_printf("\r\n Master send 32 bytes data to slave(8266)\r\n"); + os_memset(sendData, 0, sizeof(sendData)); + sendData[0] = 0x55565758; + sendData[1] = 0x595a5b5c; + sendData[2] = 0x5d5e5f60; + sendData[3] = 0x61626364; + sendData[4] = 0x65666768; + sendData[5] = 0x696a6b6c; + sendData[6] = 0x6d6e6f70; + sendData[7] = 0x71727374; + spiData.cmd = MASTER_WRITE_DATA_TO_SLAVE_CMD; + spiData.cmdLen = 1; + spiData.addr = &value; + spiData.addrLen = 4; + spiData.data = sendData; + spiData.dataLen = 32; + SPIMasterSendData(SpiNum_HSPI, &spiData); + + + os_printf("\r\n Master receive 24 bytes data from slave(8266)\r\n"); + spiData.cmd = MASTER_READ_DATA_FROM_SLAVE_CMD; + spiData.cmdLen = 1; + spiData.addr = &value; + spiData.addrLen = 4; + spiData.data = sendData; + spiData.dataLen = 24; + os_memset(sendData, 0, sizeof(sendData)); + SPIMasterRecvData(SpiNum_HSPI, &spiData); + os_printf(" Recv Slave data0[0x%08x]\r\n", sendData[0]); + os_printf(" Recv Slave data1[0x%08x]\r\n", sendData[1]); + os_printf(" Recv Slave data2[0x%08x]\r\n", sendData[2]); + os_printf(" Recv Slave data3[0x%08x]\r\n", sendData[3]); + os_printf(" Recv Slave data4[0x%08x]\r\n", sendData[4]); + os_printf(" Recv Slave data5[0x%08x]\r\n", sendData[5]); + + value = SPIMasterRecvStatus(SpiNum_HSPI); + os_printf("\r\n Master read slave(8266) status[0x%02x]\r\n", value); + + SPIMasterSendStatus(SpiNum_HSPI, 0x99); + os_printf("\r\n Master write status[0x99] to slavue(8266).\r\n"); + SHOWSPIREG(SpiNum_HSPI); + + +// Test others slave.Communication format:0bytes command + 0 bytes address + x bytes Data +#if 0 + os_printf("\r\n Master send 4 bytes data to slave\r\n"); + os_memset(sendData, 0, sizeof(sendData)); + sendData[0] = 0x2D3E4F50; + spiData.cmd = MASTER_WRITE_DATA_TO_SLAVE_CMD; + spiData.cmdLen = 0; + spiData.addr = &addr; + spiData.addrLen = 0; + spiData.data = sendData; + spiData.dataLen = 4; + SPIMasterSendData(SpiNum_HSPI, &spiData); + + os_printf("\r\n Master receive 4 bytes data from slaver\n"); + spiData.cmd = MASTER_READ_DATA_FROM_SLAVE_CMD; + spiData.cmdLen = 0; + spiData.addr = &addr; + spiData.addrLen = 0; + spiData.data = sendData; + spiData.dataLen = 4; + os_memset(sendData, 0, sizeof(sendData)); + SPIMasterRecvData(SpiNum_HSPI, &spiData); + os_printf(" Recv Slave data[0x%08x]\r\n", sendData[0]); +#endif + +} + +// Test spi slave interfaces. +void ICACHE_FLASH_ATTR spi_slave_test() +{ + // + SpiAttr hSpiAttr; + hSpiAttr.bitOrder = SpiBitOrder_MSBFirst; + hSpiAttr.speed = 0; + hSpiAttr.mode = SpiMode_Slave; + hSpiAttr.subMode = SpiSubMode_0; + + // Init HSPI GPIO + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode + + os_printf("\r\n ============= spi init slave =============\r\n"); + SPIInit(SpiNum_HSPI, &hSpiAttr); + + // Set spi interrupt information. + SpiIntInfo spiInt; + spiInt.src = (SpiIntSrc_TransDone + | SpiIntSrc_WrStaDone + |SpiIntSrc_RdStaDone + |SpiIntSrc_WrBufDone + |SpiIntSrc_RdBufDone); + spiInt.isrFunc = spi_slave_isr_sta; + SPIIntCfg(SpiNum_HSPI, &spiInt); + // SHOWSPIREG(SpiNum_HSPI); + + SPISlaveRecvData(SpiNum_HSPI); + uint32_t sndData[8] = { 0 }; + sndData[0] = 0x35343332; + sndData[1] = 0x39383736; + sndData[2] = 0x3d3c3b3a; + sndData[3] = 0x11103f3e; + sndData[4] = 0x15141312; + sndData[5] = 0x19181716; + sndData[6] = 0x1d1c1b1a; + sndData[7] = 0x21201f1e; + + SPISlaveSendData(SpiNum_HSPI, sndData, 8); + WRITE_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI), 0x8A); + WRITE_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI), 0x83); +} + +void spi_interface_test(void) +{ + // Test spi interfaces. + os_printf("\r\n =======================================================\r\n"); + os_printf("\t ESP8266 %s application \n\r", __func__); + os_printf("\t\t SDK version:%s \n\r", system_get_sdk_version()); + os_printf("\t\t Complie time:%s \n\r", __TIME__); + os_printf("\r\n =======================================================\r\n"); + +#if 0 + spi_master_test(); +#else + spi_slave_test(); +#endif + +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/user_main.c new file mode 100755 index 0000000000..008621e234 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/peripheral_test/user/user_main.c @@ -0,0 +1,94 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2015 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "ets_sys.h" +#include "osapi.h" +#include "spi_test.h" +#include "user_interface.h" + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ +} + +/** + * @brief Test spi interfaces. + * + */ +void ICACHE_FLASH_ATTR +user_init(void) +{ + spi_interface_test(); +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/readme.txt b/Sming/third-party/ESP8266_NONOS_SDK/examples/readme.txt new file mode 100644 index 0000000000..6081d1b808 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/readme.txt @@ -0,0 +1,40 @@ +1¡¢compile options + +(1) COMPILE + Possible value: gcc + Default value: + If not set, use xt-xcc by default. + +(2) BOOT + Possible value: none/old/new + none: no need boot + old: use boot_v1.1 + new: use boot_v1.2+ + Default value: none + +(3) APP + Possible value: 0/1/2 + 0: original mode, generate eagle.app.v6.flash.bin and eagle.app.v6.irom0text.bin + 1: generate user1 + 2: generate user2 + Default value: 0 + +(3) SPI_SPEED + Possible value: 20/26.7/40/80 + Default value: 40 + +(4) SPI_MODE + Possible value: QIO/QOUT/DIO/DOUT + Default value: QIO + +(4) SPI_SIZE_MAP + Possible value: 0/2/3/4/5/6 + Default value: 0 + +For example: + make COMPILE=gcc BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=0 + +2¡¢You can also use gen_misc to make and generate specific bin you needed. + Linux: ./gen_misc.sh + Windows: gen_misc.bat + Follow the tips and steps. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/Makefile new file mode 100644 index 0000000000..3ff322f7e3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/Makefile @@ -0,0 +1,121 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lmain \ + -lespnow \ + -lcrypto \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.sh new file mode 100755 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/include/user_config.h new file mode 100644 index 0000000000..3edc1ee019 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/include/user_config.h @@ -0,0 +1,29 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/user_main.c new file mode 100644 index 0000000000..a0565eacf9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/simple_pair/user/user_main.c @@ -0,0 +1,345 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "user_interface.h" + + +#include "simple_pair.h" + +/******************************************************************************* + * open AS_STA to compile sta test code + * open AS_AP to compile ap test code + * don't open both + * ****************************************************************************/ +#define AS_STA +//#define AS_AP + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ +} +/* STA & AP use the same tmpkey to encrypt Simple Pair communication */ +static u8 tmpkey[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + +#ifdef AS_STA +/* since the ex_key transfer from AP to STA, so STA's ex_key don't care */ +static u8 ex_key[16] = {0x00}; +#endif /* AS_STA */ + +#ifdef AS_AP +/* since the ex_key transfer from AP to STA, so AP's ex_key must be set */ +static u8 ex_key[16] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, + 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; +#endif /* AS_AP */ + +void ICACHE_FLASH_ATTR +show_key(u8 *buf, u8 len) +{ + u8 i; + + for (i = 0; i < len; i++) + os_printf("%02x,%s", buf[i], (i%16 == 15?"\n":" ")); +} + +#ifdef AS_STA +static void ICACHE_FLASH_ATTR +scan_done(void *arg, STATUS status) +{ + int ret; + + if (status == OK) { + + struct bss_info *bss_link = (struct bss_info *)arg; + + while (bss_link != NULL) { + if (bss_link->simple_pair) { + os_printf("Simple Pair: bssid %02x:%02x:%02x:%02x:%02x:%02x Ready!\n", + bss_link->bssid[0], bss_link->bssid[1], bss_link->bssid[2], + bss_link->bssid[3], bss_link->bssid[4], bss_link->bssid[5]); + simple_pair_set_peer_ref(bss_link->bssid, tmpkey, NULL); + ret = simple_pair_sta_start_negotiate(); + if (ret) + os_printf("Simple Pair: STA start NEG Failed\n"); + else + os_printf("Simple Pair: STA start NEG OK\n"); + break; + } + bss_link = bss_link->next.stqe_next; + } + } else { + os_printf("err, scan status %d\n", status); + } + +} +#endif + + +void ICACHE_FLASH_ATTR +sp_status(u8 *sa, u8 status) +{ +#ifdef AS_STA + switch (status) { + case SP_ST_STA_FINISH: + simple_pair_get_peer_ref(NULL, NULL, ex_key); + os_printf("Simple Pair: STA FINISH, Ex_key "); + show_key(ex_key, 16); + /* TODO: Try to use the ex-key communicate with AP, for example use ESP-NOW */ + + /* if test ok , deinit simple pair */ + simple_pair_deinit(); + break; + case SP_ST_STA_AP_REFUSE_NEG: + /* AP refuse , so try simple pair again or scan other ap*/ + os_printf("Simple Pair: Recv AP Refuse\n"); + simple_pair_state_reset(); + simple_pair_sta_enter_scan_mode(); + wifi_station_scan(NULL, scan_done); + break; + case SP_ST_WAIT_TIMEOUT: + /* In negotiate, timeout , so try simple pair again */ + os_printf("Simple Pair: Neg Timeout\n"); + simple_pair_state_reset(); + simple_pair_sta_enter_scan_mode(); + wifi_station_scan(NULL, scan_done); + break; + case SP_ST_SEND_ERROR: + os_printf("Simple Pair: Send Error\n"); + /* maybe the simple_pair_set_peer_ref() haven't called, it send to a wrong mac address */ + + break; + case SP_ST_KEY_INSTALL_ERR: + os_printf("Simple Pair: Key Install Error\n"); + /* 1. maybe something argument error. + 2. maybe the key number is full in system*/ + + /* TODO: Check other modules which use lots of keys + Example: ESPNOW and STA/AP use lots of keys */ + break; + case SP_ST_KEY_OVERLAP_ERR: + os_printf("Simple Pair: Key Overlap Error\n"); + /* 1. maybe something argument error. + 2. maybe the MAC Address is already use in ESP-NOW or other module + the same MAC Address has multi key*/ + + /* TODO: Check if the same MAC Address used already, + Example: del MAC item of ESPNOW or other module */ + break; + case SP_ST_OP_ERROR: + os_printf("Simple Pair: Operation Order Error\n"); + /* 1. maybe the function call order has something wrong */ + + /* TODO: Adjust your function call order */ + break; + default: + os_printf("Simple Pair: Unknown Error\n"); + break; + } + +#endif /* AS_STA */ + +#ifdef AS_AP + switch (status) { + case SP_ST_AP_FINISH: + simple_pair_get_peer_ref(NULL, NULL, ex_key); + os_printf("Simple Pair: AP FINISH\n"); + + /* TODO: Wait STA use the ex-key communicate with AP, for example use ESP-NOW */ + + /* if test ok , deinit simple pair */ + simple_pair_deinit(); + break; + case SP_ST_AP_RECV_NEG: + /* AP recv a STA's negotiate request */ + os_printf("Simple Pair: Recv STA Negotiate Request\n"); + + /* set peer must be called, because the simple pair need to know what peer mac is */ + simple_pair_set_peer_ref(sa, tmpkey, ex_key); + + /* TODO:In this phase, the AP can interaction with Smart Phone, + if the Phone agree, call start_neg or refuse */ + simple_pair_ap_start_negotiate(); + //simple_pair_ap_refuse_negotiate(); + /* TODO:if refuse, maybe call simple_pair_deinit() to ending the simple pair */ + + break; + case SP_ST_WAIT_TIMEOUT: + /* In negotiate, timeout , so re-enter in to announce mode*/ + os_printf("Simple Pair: Neg Timeout\n"); + simple_pair_state_reset(); + simple_pair_ap_enter_announce_mode(); + break; + case SP_ST_SEND_ERROR: + os_printf("Simple Pair: Send Error\n"); + /* maybe the simple_pair_set_peer_ref() haven't called, it send to a wrong mac address */ + + break; + case SP_ST_KEY_INSTALL_ERR: + os_printf("Simple Pair: Key Install Error\n"); + /* 1. maybe something argument error. + 2. maybe the key number is full in system*/ + + /* TODO: Check other modules which use lots of keys + Example: ESPNOW and STA/AP use lots of keys */ + break; + case SP_ST_KEY_OVERLAP_ERR: + os_printf("Simple Pair: Key Overlap Error\n"); + /* 1. maybe something argument error. + 2. maybe the MAC Address is already use in ESP-NOW or other module + the same MAC Address has multi key*/ + + /* TODO: Check if the same MAC Address used already, + Example: del MAC item of ESPNOW or other module */ + break; + case SP_ST_OP_ERROR: + os_printf("Simple Pair: Operation Order Error\n"); + /* 1. maybe the function call order has something wrong */ + + /* TODO: Adjust your function call order */ + break; + default: + os_printf("Simple Pair: Unknown Error\n"); + break; + } + +#endif /* AS_AP */ +} + +void ICACHE_FLASH_ATTR +init_done(void) +{ + int ret; + +#ifdef AS_STA + wifi_set_opmode(STATION_MODE); + + /* init simple pair */ + ret = simple_pair_init(); + if (ret) { + os_printf("Simple Pair: init error, %d\n", ret); + return; + } + /* register simple pair status callback function */ + ret = register_simple_pair_status_cb(sp_status); + if (ret) { + os_printf("Simple Pair: register status cb error, %d\n", ret); + return; + } + + os_printf("Simple Pair: STA Enter Scan Mode ...\n"); + ret = simple_pair_sta_enter_scan_mode(); + if (ret) { + os_printf("Simple Pair: STA Enter Scan Mode Error, %d\n", ret); + return; + } + /* scan ap to searh which ap is ready to simple pair */ + os_printf("Simple Pair: STA Scan AP ...\n"); + wifi_station_scan(NULL,scan_done); +#endif +#ifdef AS_AP + wifi_set_opmode(SOFTAP_MODE); + + /* init simple pair */ + ret = simple_pair_init(); + if (ret) { + os_printf("Simple Pair: init error, %d\n", ret); + return; + } + /* register simple pair status callback function */ + ret = register_simple_pair_status_cb(sp_status); + if (ret) { + os_printf("Simple Pair: register status cb error, %d\n", ret); + return; + } + + os_printf("Simple Pair: AP Enter Announce Mode ...\n"); + /* ap must enter announce mode , so the sta can know which ap is ready to simple pair */ + ret = simple_pair_ap_enter_announce_mode(); + if (ret) { + os_printf("Simple Pair: AP Enter Announce Mode Error, %d\n", ret); + return; + } + +#endif + +} + + +void ICACHE_FLASH_ATTR +user_init(void) +{ + system_init_done_cb(init_done); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/!!!readme!!!.txt b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/!!!readme!!!.txt new file mode 100644 index 0000000000..fed54ec081 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/!!!readme!!!.txt @@ -0,0 +1,8 @@ +if you want to use AIRKISS2.0 LAN discovery, should include airkiss.h and include libairkiss.a in makefile. + +you can follow the steps below to achieve the function of LAN discovery. +1.scan the two-dimension code in your wechat. +2.running this smartconfig example. +3.wait device connect to AP and LAN discovery. + +More detailed introduction refer to wechat. \ No newline at end of file diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/Makefile new file mode 100644 index 0000000000..03dbe4f8fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/Makefile @@ -0,0 +1,125 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lcrypto \ + -lmain \ + -ljson \ + -lssl \ + -lupgrade \ + -lsmartconfig \ + -lairkiss\ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.sh new file mode 100755 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/include/user_config.h new file mode 100644 index 0000000000..3edc1ee019 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/include/user_config.h @@ -0,0 +1,29 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/model two-dimension code.rar b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/model two-dimension code.rar new file mode 100644 index 0000000000000000000000000000000000000000..2d05fad3c5d4265495fb12f130bd4561bd587b92 GIT binary patch literal 15386 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/user_main.c new file mode 100755 index 0000000000..7df96a6001 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/smart_config/user/user_main.c @@ -0,0 +1,260 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "osapi.h" +#include "ip_addr.h" +#include "espconn.h" +#include "mem.h" + + +#include "user_interface.h" +#include "smartconfig.h" +#include "airkiss.h" + + +#define DEVICE_TYPE "gh_9e2cff3dfa51" //wechat public number +#define DEVICE_ID "122475" //model ID + +#define DEFAULT_LAN_PORT 12476 + +LOCAL esp_udp ssdp_udp; +LOCAL struct espconn pssdpudpconn; +LOCAL os_timer_t ssdp_time_serv; + +uint8_t lan_buf[200]; +uint16_t lan_buf_len; +uint8 udp_sent_cnt = 0; + +const airkiss_config_t akconf = +{ + (airkiss_memset_fn)&memset, + (airkiss_memcpy_fn)&memcpy, + (airkiss_memcmp_fn)&memcmp, + 0, +}; + +LOCAL void ICACHE_FLASH_ATTR +airkiss_wifilan_time_callback(void) +{ + uint16 i; + airkiss_lan_ret_t ret; + + if ((udp_sent_cnt++) >30) { + udp_sent_cnt = 0; + os_timer_disarm(&ssdp_time_serv);//s + //return; + } + + ssdp_udp.remote_port = DEFAULT_LAN_PORT; + ssdp_udp.remote_ip[0] = 255; + ssdp_udp.remote_ip[1] = 255; + ssdp_udp.remote_ip[2] = 255; + ssdp_udp.remote_ip[3] = 255; + lan_buf_len = sizeof(lan_buf); + ret = airkiss_lan_pack(AIRKISS_LAN_SSDP_NOTIFY_CMD, + DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf); + if (ret != AIRKISS_LAN_PAKE_READY) { + os_printf("Pack lan packet error!"); + return; + } + + ret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len); + if (ret != 0) { + os_printf("UDP send error!"); + } + os_printf("Finish send notify!\n"); +} + +LOCAL void ICACHE_FLASH_ATTR +airkiss_wifilan_recv_callbk(void *arg, char *pdata, unsigned short len) +{ + uint16 i; + remot_info* pcon_info = NULL; + + airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf); + airkiss_lan_ret_t packret; + + switch (ret){ + case AIRKISS_LAN_SSDP_REQ: + espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0); + os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1], + pcon_info->remote_ip[2],pcon_info->remote_ip[3]); + os_printf("remote port: %d \r\n",pcon_info->remote_port); + + pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port; + os_memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4); + ssdp_udp.remote_port = DEFAULT_LAN_PORT; + + lan_buf_len = sizeof(lan_buf); + packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD, + DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf); + + if (packret != AIRKISS_LAN_PAKE_READY) { + os_printf("Pack lan packet error!"); + return; + } + + os_printf("\r\n\r\n"); + for (i=0; i + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/ca.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/ca.h new file mode 100644 index 0000000000..84a1199024 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/ca.h @@ -0,0 +1,89 @@ +unsigned char ca[] = { +0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, +0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x44, +0x33, 0x44, 0x43, 0x43, 0x41, 0x30, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4a, +0x41, 0x4d, 0x6e, 0x6c, 0x67, 0x4c, 0x31, 0x63, 0x7a, 0x73, 0x6d, 0x6a, 0x4d, 0x41, 0x30, 0x47, +0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43, 0x77, 0x55, 0x41, +0x4d, 0x49, 0x47, 0x54, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, 0x56, 0x51, 0x51, +0x47, 0x45, 0x77, 0x4a, 0x47, 0x55, 0x6a, 0x45, 0x50, 0x4d, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, +0x45, 0x43, 0x41, 0x77, 0x47, 0x55, 0x6d, 0x46, 0x6b, 0x61, 0x58, 0x56, 0x7a, 0x4d, 0x52, 0x49, +0x77, 0x45, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x6c, 0x54, 0x62, 0x32, 0x31, +0x6c, 0x64, 0x32, 0x68, 0x6c, 0x63, 0x6d, 0x55, 0x78, 0x46, 0x54, 0x41, 0x54, 0x0a, 0x42, 0x67, +0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x56, 0x34, 0x59, 0x57, 0x31, 0x77, 0x62, 0x47, +0x55, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x67, 0x4d, 0x42, 0x34, 0x47, 0x43, 0x53, +0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, 0x41, 0x52, 0x59, 0x52, 0x59, 0x57, +0x52, 0x74, 0x61, 0x57, 0x35, 0x41, 0x5a, 0x58, 0x68, 0x68, 0x62, 0x58, 0x42, 0x73, 0x0a, 0x5a, +0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, 0x78, 0x4a, 0x6a, 0x41, 0x6b, 0x42, 0x67, 0x4e, 0x56, 0x42, +0x41, 0x4d, 0x4d, 0x48, 0x55, 0x56, 0x34, 0x59, 0x57, 0x31, 0x77, 0x62, 0x47, 0x55, 0x67, 0x51, +0x32, 0x56, 0x79, 0x64, 0x47, 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x55, 0x67, 0x51, +0x58, 0x56, 0x30, 0x61, 0x47, 0x39, 0x79, 0x61, 0x58, 0x52, 0x35, 0x4d, 0x42, 0x34, 0x58, 0x0a, +0x44, 0x54, 0x45, 0x33, 0x4d, 0x44, 0x59, 0x77, 0x4e, 0x7a, 0x41, 0x34, 0x4d, 0x44, 0x59, 0x30, +0x4f, 0x56, 0x6f, 0x58, 0x44, 0x54, 0x49, 0x33, 0x4d, 0x44, 0x59, 0x77, 0x4e, 0x54, 0x41, 0x34, +0x4d, 0x44, 0x59, 0x30, 0x4f, 0x56, 0x6f, 0x77, 0x67, 0x5a, 0x4d, 0x78, 0x43, 0x7a, 0x41, 0x4a, +0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x5a, 0x53, 0x4d, 0x51, 0x38, 0x77, +0x0a, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x5a, 0x53, 0x59, 0x57, 0x52, +0x70, 0x64, 0x58, 0x4d, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, +0x4d, 0x43, 0x56, 0x4e, 0x76, 0x62, 0x57, 0x56, 0x33, 0x61, 0x47, 0x56, 0x79, 0x5a, 0x54, 0x45, +0x56, 0x4d, 0x42, 0x4d, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77, 0x4d, 0x52, 0x58, 0x68, +0x68, 0x0a, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x53, +0x41, 0x77, 0x48, 0x67, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, +0x6b, 0x42, 0x46, 0x68, 0x46, 0x68, 0x5a, 0x47, 0x31, 0x70, 0x62, 0x6b, 0x42, 0x6c, 0x65, 0x47, +0x46, 0x74, 0x63, 0x47, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x6d, 0x4d, 0x43, +0x51, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x64, 0x52, 0x58, 0x68, 0x68, 0x62, +0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, 0x5a, 0x70, 0x59, +0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, 0x33, 0x4a, 0x70, 0x64, +0x48, 0x6b, 0x77, 0x67, 0x5a, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, +0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x30, 0x41, +0x4d, 0x49, 0x47, 0x4a, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4c, 0x70, 0x57, 0x52, 0x32, 0x33, 0x66, +0x6e, 0x2f, 0x54, 0x6d, 0x48, 0x78, 0x73, 0x58, 0x73, 0x48, 0x64, 0x72, 0x79, 0x64, 0x7a, 0x50, +0x53, 0x64, 0x31, 0x37, 0x66, 0x5a, 0x6b, 0x63, 0x37, 0x31, 0x57, 0x73, 0x61, 0x69, 0x63, 0x67, +0x51, 0x52, 0x36, 0x36, 0x0a, 0x31, 0x74, 0x49, 0x56, 0x59, 0x62, 0x32, 0x32, 0x55, 0x57, 0x47, +0x66, 0x6a, 0x39, 0x4b, 0x50, 0x4d, 0x38, 0x54, 0x48, 0x4d, 0x73, 0x56, 0x37, 0x34, 0x65, 0x77, +0x34, 0x5a, 0x6b, 0x61, 0x51, 0x33, 0x39, 0x71, 0x76, 0x55, 0x30, 0x69, 0x75, 0x51, 0x49, 0x52, +0x72, 0x4b, 0x41, 0x52, 0x46, 0x48, 0x46, 0x6f, 0x6b, 0x2b, 0x76, 0x62, 0x61, 0x65, 0x63, 0x67, +0x57, 0x4d, 0x65, 0x57, 0x65, 0x0a, 0x76, 0x47, 0x49, 0x71, 0x64, 0x6e, 0x6d, 0x79, 0x42, 0x39, +0x67, 0x4a, 0x59, 0x61, 0x46, 0x4f, 0x4b, 0x67, 0x74, 0x53, 0x6b, 0x66, 0x58, 0x73, 0x75, 0x32, +0x64, 0x64, 0x73, 0x71, 0x64, 0x76, 0x4c, 0x59, 0x77, 0x63, 0x44, 0x62, 0x63, 0x7a, 0x72, 0x71, +0x38, 0x58, 0x39, 0x79, 0x45, 0x58, 0x70, 0x4e, 0x36, 0x6d, 0x6e, 0x78, 0x58, 0x65, 0x43, 0x63, +0x50, 0x47, 0x34, 0x46, 0x30, 0x70, 0x0a, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 0x47, 0x6a, 0x67, +0x67, 0x45, 0x30, 0x4d, 0x49, 0x49, 0x42, 0x4d, 0x44, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, +0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x67, 0x69, 0x67, 0x70, 0x64, 0x41, 0x55, 0x70, 0x4f, +0x4e, 0x6f, 0x44, 0x71, 0x30, 0x70, 0x51, 0x33, 0x79, 0x66, 0x78, 0x72, 0x73, 0x6c, 0x43, 0x53, +0x70, 0x63, 0x77, 0x67, 0x63, 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x64, 0x49, 0x77, 0x53, 0x42, +0x77, 0x44, 0x43, 0x42, 0x76, 0x59, 0x41, 0x55, 0x67, 0x69, 0x67, 0x70, 0x64, 0x41, 0x55, 0x70, +0x4f, 0x4e, 0x6f, 0x44, 0x71, 0x30, 0x70, 0x51, 0x33, 0x79, 0x66, 0x78, 0x72, 0x73, 0x6c, 0x43, +0x53, 0x70, 0x65, 0x68, 0x67, 0x5a, 0x6d, 0x6b, 0x67, 0x5a, 0x59, 0x77, 0x67, 0x5a, 0x4d, 0x78, +0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x5a, +0x53, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x5a, +0x53, 0x59, 0x57, 0x52, 0x70, 0x64, 0x58, 0x4d, 0x78, 0x45, 0x6a, 0x41, 0x51, 0x42, 0x67, 0x4e, +0x56, 0x42, 0x41, 0x63, 0x4d, 0x43, 0x56, 0x4e, 0x76, 0x62, 0x57, 0x56, 0x33, 0x61, 0x47, 0x56, +0x79, 0x5a, 0x54, 0x45, 0x56, 0x4d, 0x42, 0x4d, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, +0x77, 0x4d, 0x52, 0x58, 0x68, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x4a, 0x62, 0x6d, +0x4d, 0x75, 0x4d, 0x53, 0x41, 0x77, 0x48, 0x67, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, +0x63, 0x4e, 0x41, 0x51, 0x6b, 0x42, 0x46, 0x68, 0x46, 0x68, 0x5a, 0x47, 0x31, 0x70, 0x62, 0x6b, +0x42, 0x6c, 0x65, 0x47, 0x46, 0x74, 0x63, 0x47, 0x78, 0x6c, 0x0a, 0x4c, 0x6d, 0x4e, 0x76, 0x62, +0x54, 0x45, 0x6d, 0x4d, 0x43, 0x51, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x64, 0x52, +0x58, 0x68, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, +0x57, 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x53, 0x42, 0x42, 0x64, 0x58, 0x52, 0x6f, 0x62, +0x33, 0x4a, 0x70, 0x64, 0x48, 0x6d, 0x43, 0x43, 0x51, 0x44, 0x4a, 0x0a, 0x35, 0x59, 0x43, 0x39, +0x58, 0x4d, 0x37, 0x4a, 0x6f, 0x7a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x45, +0x42, 0x54, 0x41, 0x44, 0x41, 0x51, 0x48, 0x2f, 0x4d, 0x44, 0x59, 0x47, 0x41, 0x31, 0x55, 0x64, +0x48, 0x77, 0x51, 0x76, 0x4d, 0x43, 0x30, 0x77, 0x4b, 0x36, 0x41, 0x70, 0x6f, 0x43, 0x65, 0x47, +0x4a, 0x57, 0x68, 0x30, 0x64, 0x48, 0x41, 0x36, 0x4c, 0x79, 0x39, 0x33, 0x0a, 0x64, 0x33, 0x63, +0x75, 0x5a, 0x58, 0x68, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30, +0x76, 0x5a, 0x58, 0x68, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x56, 0x39, 0x6a, 0x59, 0x53, 0x35, +0x6a, 0x63, 0x6d, 0x77, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, +0x4e, 0x41, 0x51, 0x45, 0x4c, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x45, 0x41, 0x0a, 0x65, 0x75, +0x78, 0x4f, 0x42, 0x50, 0x49, 0x6e, 0x53, 0x4a, 0x52, 0x4b, 0x41, 0x49, 0x73, 0x65, 0x4d, 0x78, +0x50, 0x6d, 0x41, 0x61, 0x62, 0x74, 0x41, 0x71, 0x4b, 0x4e, 0x73, 0x6c, 0x5a, 0x53, 0x6d, 0x70, +0x47, 0x34, 0x48, 0x65, 0x33, 0x6c, 0x6b, 0x4b, 0x74, 0x2b, 0x48, 0x4d, 0x33, 0x6a, 0x66, 0x7a, +0x6e, 0x55, 0x74, 0x33, 0x70, 0x73, 0x6d, 0x44, 0x37, 0x6a, 0x31, 0x68, 0x46, 0x57, 0x0a, 0x53, +0x34, 0x6c, 0x37, 0x4b, 0x58, 0x7a, 0x7a, 0x61, 0x6a, 0x76, 0x61, 0x47, 0x59, 0x79, 0x62, 0x44, +0x71, 0x35, 0x4e, 0x39, 0x4d, 0x71, 0x72, 0x44, 0x6a, 0x68, 0x47, 0x6e, 0x33, 0x56, 0x58, 0x5a, +0x71, 0x4f, 0x4c, 0x4d, 0x55, 0x4e, 0x44, 0x4c, 0x37, 0x4f, 0x51, 0x71, 0x39, 0x36, 0x54, 0x7a, +0x67, 0x71, 0x73, 0x54, 0x42, 0x54, 0x31, 0x64, 0x6d, 0x56, 0x53, 0x62, 0x4e, 0x6c, 0x74, 0x0a, +0x50, 0x51, 0x67, 0x69, 0x41, 0x65, 0x4b, 0x41, 0x6b, 0x33, 0x74, 0x6d, 0x48, 0x34, 0x6c, 0x52, +0x52, 0x69, 0x39, 0x4d, 0x54, 0x42, 0x53, 0x79, 0x4a, 0x36, 0x49, 0x39, 0x32, 0x4a, 0x59, 0x63, +0x53, 0x35, 0x48, 0x36, 0x42, 0x73, 0x34, 0x5a, 0x77, 0x43, 0x63, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, +0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, +0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, }; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.der b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.der new file mode 100644 index 0000000000000000000000000000000000000000..c6dd221d15051fd03dc302162a8bf68e32dac5d9 GIT binary patch literal 992 zcmXqLV!mV0#O%6&nTe5!iId^v(}uk<=T0s*;AP{~YV&CO&dbQi&B|cVIN6ZffRl|m zl!Z;0$t}o`AE*Gx;oxBlN=(TtEjAP~5C93V^Kb^|=cbltq!y(biW&%m#JG5PTq_cD z3vyBwJoA$E3>6II;D&QDiU}sBXCan3-5ciSrtPxTa9;;B! zCsSi1!>%y*-23ytJd>9e-%y@?^3HkByVbQbW!{Ib$x>Hvl-qUfl4#=IZGnmN`!Dqy zA31JxwEE#2i!`?h_iwEa_E_i8lC8nwDifvh>)Wl$6Jmx>=j}<-Dy!VYeuFb{p`R9a z(8RBAcBjW~TAr`lBg4Dhc-?yO?~39}?k$@ydXMw)u?Ml5Ow5c7jEkEXO$?eC4Gd&~ zu^`LGBE}-pq@h{Ds%deHd9_!-ef5v)PC9u_H)uQol2>MFJYdkcw*jk~g^e?pG)^0w z5z&N{+<8Dg5oTdEU}j|eZ(s)E$+PGi=o)A*&|IM2rkYVwQedU8UtV6Whm=tDq3rnN zM7`vq9OP&PW*TN-d{({jWBH`+F~y6aTh3Vc8RN3IOpAIqg$2!;xI^~s(+R8VWX?XW zx4g2wDrbh><7R literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.key b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.key new file mode 100644 index 0000000000..1394ab8c4c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALpWR23fn/TmHxsX +sHdrydzPSd17fZkc71WsaicgQR661tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qv +U0iuQIRrKARFHFok+vbaecgWMeWevGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwc +Dbczrq8X9yEXpN6mnxXeCcPG4F0pAgMBAAECgYAzCTqbL2rCSt0uMHjW3KD3Z5cV +oKMv8qrizkxs1vq/DfGUrOKOcYcss+VSiIJnXR/c0yd36aKppTiKzwaCm6dzpNTL +XhHyvxAk293OXq6ov7LSfpuQTSW0d/bsLceMSD7jm6hnlYhGDg5I5nLaTsiQjedZ +OoLlfqcg5+qAbm6T2QJBAPbHOhJqQ8H0SIYZzYN6te18KAlZ8lNw/jVUvSqWn9g0 +iinGqbbNsmxYp72Y1sb8AtOQkRypE+BUZlZ7LdMRpzcCQQDBTNlU7w82hDb8gzPB +kLdJ8bom2AfNLOtgBlQkNRAItbt6OHA2BzhLMPs8CDDPPBwEKqzR4RC4l2uvcQe/ +n46fAkAPtLBKeb7kOjLfbgb5Zjbr7Wny5mmYy+kx5bnAWyPDM9zTOdSVUNQZNy89 +zttkgKeBZYMGyu/76AM3X9GTzFzTAkAwyZGs8y12yAYM05yThVANlLo0JaBKc8Tw +lohUHyRt3lh0L5x6tnXJ3JH8g+C13WkA0DiQPGr4/BbM0A1xmvbnAkBBbe+FdY/a +dTY6cgg8ywgGaWp8d2DV9gjio9Sm1/EIHkewFRt8/q8OE3VtaZ7t0gNVSKDfb8XU +71a+s4Jqqq8i +-----END PRIVATE KEY----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.pem b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.pem new file mode 100644 index 0000000000..1bdf23d94b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD +VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT +BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs +ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X +DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w +DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh +bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG +A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66 +1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe +vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p +AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG +A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV +BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG +A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl +LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ +5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93 +d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA +euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW +S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt +PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc= +-----END CERTIFICATE----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.crt b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.crt new file mode 100644 index 0000000000..0e03a1b79b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 48 (0x30) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority + Validity + Not Before: Jun 7 08:06:49 2017 GMT + Not After : Jun 5 08:06:49 2027 GMT + Subject: C=FR, ST=Radius, O=Example Inc., CN=user@example.com/emailAddress=user@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d2:f6:be:72:a5:ab:2e:56:0c:dd:f2:3b:2c:7c: + e0:5d:05:40:af:0c:8c:f3:82:0c:d0:18:34:b4:e3: + 7d:5f:8d:0a:3e:aa:79:02:f9:96:ad:10:00:ec:51: + e9:dc:3f:fb:ea:b0:57:eb:48:c7:ca:ef:e8:05:ab: + ee:3f:66:ba:5c:9e:7f:40:85:9f:25:a0:e0:e3:7c: + cf:b6:e6:31:f5:fd:24:03:c8:f4:fb:d8:a4:f3:92: + 29:05:aa:55:43:80:f7:3e:13:10:43:3a:89:24:be: + d8:01:86:d1:69:73:44:7d:f8:b9:46:2b:6b:51:d0: + 11:31:4b:06:ae:9f:45:fa:12:17:0c:ef:6a:fa:d0: + f7:36:46:eb:2e:db:4e:20:46:01:33:ac:b1:f7:4a: + e6:18:3d:53:22:dc:e8:4a:12:78:11:2f:e4:3b:92: + bd:d7:07:5a:c9:81:5d:48:58:c8:0f:9b:e9:a4:0f: + bb:89:b1:ad:38:07:6f:93:d0:a6:12:56:f9:07:48: + d2:23:2f:a3:a9:93:b0:11:0a:27:4c:48:0a:8d:70: + 41:68:76:7a:dd:bc:54:c3:42:33:b0:7b:f6:ae:1f: + e7:95:5e:11:ca:f2:b4:4b:5c:ba:47:64:f0:f3:d7: + 87:95:7f:93:06:a1:72:c9:81:12:a5:b7:8f:9d:7e: + d1:ef + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.example.com/example_ca.crl + + Signature Algorithm: sha1WithRSAEncryption + 2d:02:bc:7b:88:b8:5c:e1:07:b8:bb:ba:b2:f3:98:14:8f:cb: + b0:21:13:b5:e5:6f:05:4f:92:fa:ac:c0:53:a7:b0:cd:7e:ba: + 87:36:85:25:d7:41:c5:29:84:22:74:af:bf:3e:34:36:d5:24: + 7a:81:e2:1b:54:52:85:6f:76:de:dc:63:98:45:fc:2c:31:fa: + 22:a4:72:3a:8d:d4:6a:2e:de:33:10:41:eb:94:1d:e3:59:cd: + b2:be:ab:f0:b6:20:86:9c:b8:46:ee:c5:64:ba:b6:6c:cc:53: + 44:7a:80:12:77:7c:e7:51:67:91:32:2f:88:9d:93:a8:ef:d6: + cd:de +-----BEGIN CERTIFICATE----- +MIIDTjCCAregAwIBAgIBMDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF +eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw +JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw +ODA2NDlaFw0yNzA2MDUwODA2NDlaMHExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS +YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEZMBcGA1UEAwwQdXNlckBleGFt +cGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdXNlckBleGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANL2vnKlqy5WDN3yOyx84F0FQK8MjPOC +DNAYNLTjfV+NCj6qeQL5lq0QAOxR6dw/++qwV+tIx8rv6AWr7j9mulyef0CFnyWg +4ON8z7bmMfX9JAPI9PvYpPOSKQWqVUOA9z4TEEM6iSS+2AGG0WlzRH34uUYra1HQ +ETFLBq6fRfoSFwzvavrQ9zZG6y7bTiBGATOssfdK5hg9UyLc6EoSeBEv5DuSvdcH +WsmBXUhYyA+b6aQPu4mxrTgHb5PQphJW+QdI0iMvo6mTsBEKJ0xICo1wQWh2et28 +VMNCM7B79q4f55VeEcrytEtcukdk8PPXh5V/kwahcsmBEqW3j51+0e8CAwEAAaNP +ME0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov +L3d3dy5leGFtcGxlLmNvbS9leGFtcGxlX2NhLmNybDANBgkqhkiG9w0BAQUFAAOB +gQAtArx7iLhc4Qe4u7qy85gUj8uwIRO15W8FT5L6rMBTp7DNfrqHNoUl10HFKYQi +dK+/PjQ21SR6geIbVFKFb3be3GOYRfwsMfoipHI6jdRqLt4zEEHrlB3jWc2yvqvw +tiCGnLhG7sVkurZszFNEeoASd3znUWeRMi+InZOo79bN3g== +-----END CERTIFICATE----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.key b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.key new file mode 100644 index 0000000000..99936e25b7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA0va+cqWrLlYM3fI7LHzgXQVArwyM84IM0Bg0tON9X40KPqp5 +AvmWrRAA7FHp3D/76rBX60jHyu/oBavuP2a6XJ5/QIWfJaDg43zPtuYx9f0kA8j0 ++9ik85IpBapVQ4D3PhMQQzqJJL7YAYbRaXNEffi5RitrUdARMUsGrp9F+hIXDO9q ++tD3NkbrLttOIEYBM6yx90rmGD1TItzoShJ4ES/kO5K91wdayYFdSFjID5vppA+7 +ibGtOAdvk9CmElb5B0jSIy+jqZOwEQonTEgKjXBBaHZ63bxUw0IzsHv2rh/nlV4R +yvK0S1y6R2Tw89eHlX+TBqFyyYESpbePnX7R7wIDAQABAoIBAQC5PncO3tBIeMEF +pu007FZq9/DLhP7D2B9+HrMxX0y4uXUUf8aQyS74ukPFP0xV3U1M0BnzfU4KscyQ +Jl+nBoKAT6C3vF15wiGXQAJ4vPuD4Ate03fjKWH2ixJAakhCZR01QbIXBnBkdrvf +401BBjlPUDcIGZo8FbLzEMlGTo84vE9v3Qmkbi+PzPCh2YC+NDmsOcIW1zpmwyYC +ZYCpoWgl4++kqXXn0NGhuaOgB0JLsJOBpx/hOOjBU/wXCKaXZ1vchYqfbvvx2gf2 +WX4P0CiTH1z7MEAHanaZkcnNyxV/oF1EIMY5p0vDDzgrKtppvPOqspjydje03+CE +t0wKGPi5AoGBAPAG2Y4efgwLcoWdPjKZtsHLhDhLJnvxkqnNkzdPnLZojNi8pKkV +/Yu++pPemJZZa4YAp+OnqyEfhcha+HYqKMwRC8t3YrEVOlRQTfW/OoSrp059JIRV +jTvq/u7DdYGJRRgMLUJiEI+7xj1WbTc2EceJAgn0qfKvbvBtVJP0LH1TAoGBAOEA +xZB7SwyX+zDGRTugqMYg+sYobbQHJ7utLyoX+ckeG+sPEjEYLpQQfshET/gwF8ZK +4aILkACx/tna799xCjQdmyyc338NO9WULlY1xF+65WfeaxrtTAsqVikX3p19McRI +ijX8k7Msy3gYWJXev3MCtPT2+g68IgbL/W2wY+l1AoGAT7xGy0Jv5vpqid5pig+s +OYatHrJAT445hXUIQaiNy77Bg0JvhMgMWT8RKMwabl+4K2TOYP8TB0bcf2lQ/pgU +w22qOGYpf+AoZ1fh/hAPlYEcbCOAXQG6kDwJgjGmOGjsbgelhVbkX4smWLv8PgoV +L+7goYQIbNlAhlgbb6b+nIcCgYBB7Zr2Cdpkt0en9ACnRx0M6O7yDziNzqbqzAUM +3XeYYZUmnATlk8NaKTcs8S9JdrYQqTJR6/dm7MDTDt7IZvPpb19fhBvMu5DztPaa +1ihTMI01kStq+WsVvnL+mXrmRJ/HdsXgqcCReKep6eBTEbChP4LMYG3G0YNa4HzC +njO4XQKBgQDRnbqqg2CNTnS94BN2D3uzzELtwsIG6aVCtl09ZsLnGaBKVVDtP6BI +j2hGD7xw4g5JeSPIJU5J03nALTY3hz1JyI7AJCX7+JRtUTX2A8C4mlbeul7ilGaU +A7MFT8GqhjYYa84GzNcA1mK8ynlixpL8+yzTT/8lWInWRBa69SkktA== +-----END RSA PRIVATE KEY----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.p12 b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/client.p12 new file mode 100644 index 0000000000000000000000000000000000000000..5cfac74d9d66fab45cda2e51d8367c9c26eb62b2 GIT binary patch literal 2453 zcmV;G32OE*f(elV0Ru3C30DRQDuzgg_YDCD0ic2jNCbijL@_XY_nhDe6@ z4FLxRpn?PFFoFZ*0s#Opf&<+K2`Yw2hW8Bt2LUh~1_~;MNQUgc=DrrqdGUsx_yVz-{B)nUKx{DPzf7ln!9N@%+mYmyM1gZSzJT5{|)kqzG z=ho`rI9B!3o(+2aNE@L2_E?E*paFYjo~dtKk$-?&gk4ujGO6@5r%fJFU~T#U)0?k; z{}olp)ZO0%%-sxm7j`}5FO+y_r_aI_!n}cD;Q3cV(Rz?cu^Vvy)MKN(V#?3;>gdZ? zjuunum<*=UD|_y)?1%~j9wr;oB&vW}0?Ds2iEw;}R3S9$S&-dW#zKNG`C|}QG_ZYC z!yJC3oE3CxjSV3_pRoxG5+Jk%5e=_#IQ8~)y&EH_J9Y5D^ldTj4UNOG&?a8G;WE%p zbbIuqvXm4SU~P0W{VVg^kS(vjT1oCr@z{Hss35gt(g)aOg}kkZ1gyYFa}SB)H5nFs>^b}NRwW(-DP&pMJCt}ulJq~=Ik_2+vyNr69O|4 z&C?ulA6`qaZc>;GK;BK9wLSnm*9QMF_L4D_gZF*aX5;kSWI!GvhbU5IP^Umf4&)fL zMNhzH=$w?h;It|4VhR)f0xAY;meS;vYi(I^vs&B$Bx&LNQUN<*=#N^pZJJ!T_=t1x>4!92h^nLxN{hnNYh^cgHgHG44RJpZ5$ zW(u{J5$v894nxaNq>tMX1Qq$55MuiED4mGkgZpd>kPWEO==~%aT zQM}isweu8ho`dp~*PeY#^W8cMqdF4Lh1)t$`?18J8iU;%+)$9V`-O5Wt`q{a@M&AO z`3--pEpqci>*!3Fe^koE7nY9m^M{2 z#gUm4L~T0& zoH0)m8C{70gd=X9UDrT9b}Zq6Is!T<`-t#Yi%tI7tnfnn7o5p`Dz{?Z*$-$lu9QGP z&Fbsw6uRnC&xtCf*he0^?)r>*bz^ctX z1SpE;ctNjes;+AUH_^3(yI{Y2eM1XF4an8bL#~HOB{XJyH)r+OX@%s3W*43Ek`zkfUR$X;B-X&Mm#!ZgbX{FU=b&Ea`Q^ z=KHK4*kg}9&r=hA2tqBnky2hrWv8*rAqGuG1ghD7w!Y9l_#K&_j(`O5p_xiZiKsjO z_UM>!AOD;qq}W$3!Z?-k;T1gO!<`Fo5vnsuUew}CxW9RPYo)tE$i_%U0Qefxp1q6x zJLSj{zW*fWqRateK~GiRZs%;eY>{0fj^vJRrQ|{;)k4siQNX5uBc=_^O(?YFQ82hR ziqjXpk6f>_3T#WW@L}QuRi3_>p&mj^l%dU%y*me1RU1!`=}lahB&BzAd7r!t6HP{< z#^ofmDchtZns7xeECvWL^$5f9F-6irFc>Q?=j4l(ssqa5qT|BkS%wUb9Al#PT#~t{$sJKtWl=7E0^wLZ}U?`i5kw&3U^qtP|1-YViBTh7o{~b6X)8r-WJ}es}f| zZ}@>L1O?!KU_EJp zR}(4Kaug#P^W2@L2XY=l6C&qAXXk~W{`-W}vWoppRy&yB!+!V8r9>zRQn{hN#=giU z2!^dDCQ@+K=5_%juZH&nHZm|fHn9R(5m}}`)z1xJV78k&p>lty zAmJ7CB8BIOGdfcz_DxAlnb#2ywd*K9Y2t +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIvLOGpsoWmVMCAggA +MBQGCCqGSIb3DQMHBAhE0X+F6dzt+QSCBMjeI5lZaP89SD5MPX7wzByOKAEFrBMF +89epa3xAtxb6r42WRIoidg2MwVxsG5qjNt6+iD4AZuqDCP6J7UDg5LpWGicG0jXe +Wc947pIUUc4q29ZYoAMG4Kx6ccF864rdGPjwhkqCg3KQJsUp8uXNltFdhni7cQ5e +eHNGkL1YHpAYGJJQNchHjbyIMfhzSbc2nSPmCvMbN5PucJH183Cw4UzonfUHkvzA +VZmRrFkbd8F+mojie9x8MghWaNlozs2Rn+pAhk1YSmH+w++ZfSiTwAhN1LA6AdjH +FvCEUJHyrFxEPVPMJsfVTYM1t1PxCIfMykh6bby9esH78L3ItpDkMC4TJWq4q7zA +fxufhC8DCxdz5pLEYSrxBF+3YdG4vqIPF5fXj0IqtiYP8se01Smc5C5JuFtYQxyZ +E10hiSKJvDr0VCiBswyBBc4QPGI2y2vDpg1R5Ure2Mp1phDTcGIoDKw6bwlVfiTb +d0nKYwXDO5OigZ/W92FO4hAMIe+7E+q3If7Rp4fvyECoHlT2WYQ4Sq+xxSWxQSv6 +RHrTyyHTg9VIdMDxI6aLiLZBXhh1Q2fkRrh1utAfYH4hAhUscp8v1+0XQo93efbn +JJ7oPhbeapPIqzabcRyUG5dwuKzdzjN/k/R90h3DEzqFE372MeyYghfPB3VQolHd +GZ1bAEiAYkjgVQbezTZ5vON+hqz1f1gIanpCB+b1pW32ljS4ANEm3SjZfaUt41Wu +lO2Btpp4ugs4dt/HBJbzTGHwEHAqtYux+GYMeBZkXFabMozU1rY8yTsF6Oz1Taj6 +fZlm3NJ4gcnLx8lLAITSTJ63GwhPAxEmhmsA98yCJ4BIPgkBpCDT9wFyRLTD2qr5 +kQat2lS6qVLHTXTJhGaAddzc+ISv+tMskreLluIJo2Y8GKgpmYapnTU00Jeh846R +AUmHBayHdwjWBRHJgdxSuy3EkLuEbskzKeKOKt/2NsoCwgEpt77v87/yYZvqIzFm +wS48oQA/bVTEbRPPfjUfPbqkqg6Lsit1bBLuCSJZ5gSnS6a/q3/ArbZX12Uoyg21 +j4OXCILoqAs69rTZl0aDEWfOkCyAYxlDNcbE4x6JxTjfWuTvSfOGI87ktMuErvZV +IprOVhYF08xk1oGLPMjjqtCU05vrOf2d55vlx6WinZ4+5IMrFnixCYPtlb1V5HGL +w6ZLP5pP4cM0buFwrGaVOzy6dtP3ZX5JAXbV3lnV9SfzsN3t5hnMUsg9GkVW7FDQ +H6G8v2rIVP5VirQiNc2tJUk/46ybvsnrOvlrvTcXGMpWK3iCn27qi2swmwE0CSjW +hXydeKFi/tyxBDwOl/V13dYzpdU1sCVE7NZfVL0LA62jPZdRBAau0s3FMictyha3 +5BGr6mo41XTm2faOwnLoJTjlzGG01Bh8Di/B00+2Y1caDZAaHgpYO4Rs0c5W7NiG +zH0HrFJ4M+5Jw12n4LMYMZYvr+EmsLGlTkLqf26u2D98qH0vG7Hjht3/N66Eu5ct +hwRQaRuiFKx7tnte4K/iI3GjCqaGOACHSF3cQBjOe1jlEgMBXrb3C1SKaw8hnIgX +5T/wgCeVXHSQNlp3udTd9qIYYMi93Jb3ajeZva3bgz2KNbdnwVuk3cUi2vWHShzi +7sY= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/dh b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/dh new file mode 100644 index 0000000000..3bb92c2fb8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/dh @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBAKmGKli1HkbNwmB1UpSJpiAb45AZwO49b3fL0H1XAq3z6bU+ghYhRpZj +gR3zxZ05pMksz/JA1SK2BNg19mIberZMIxr/2SI+Qx/VB4EMR+8UZ0zbOGj3flDM +0lMGKm8EYPPaOdx0ckMostVsND5XwxKPVFvW3f3Fh4fyVwNVA/XDAgEC +-----END DH PARAMETERS----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.crt b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.crt new file mode 100644 index 0000000000..8f1dfcda6c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 47 (0x2f) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority + Validity + Not Before: Jun 7 08:06:49 2017 GMT + Not After : Jun 5 08:06:49 2027 GMT + Subject: C=FR, ST=Radius, O=Example Inc., CN=Example Server Certificate/emailAddress=admin@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c9:d8:e2:e0:75:91:83:87:d8:c8:80:c6:20:4d: + e9:14:24:30:98:33:53:fa:56:0e:ec:9a:43:7f:87: + a9:22:94:26:06:c7:ac:b5:d9:ec:55:06:81:b7:0d: + c9:24:51:49:fa:47:fb:4b:4e:fc:ed:75:8a:e1:28: + 32:bc:c5:e0:4c:45:c4:58:60:15:67:1e:6b:40:19: + 3f:f0:ab:92:61:92:2d:71:10:2e:f2:eb:bc:81:2f: + 5a:3b:74:ca:5f:fd:e0:ee:d1:d9:07:6a:6c:20:c0: + 07:88:b4:8b:0f:ad:1e:c9:4f:7c:11:98:37:89:15: + de:24:b1:11:1a:7c:97:4a:cf:f3:c8:cb:79:9e:9c: + c3:71:da:a6:94:97:f5:95:fd:61:06:44:e2:3f:12: + 43:0b:1d:33:48:91:d2:ce:4f:97:a1:ed:6a:30:c7: + 5d:98:b5:6e:0a:b7:4f:d9:03:ec:80:76:09:b0:40: + a1:a1:af:ab:2a:59:c4:0f:56:22:bc:be:14:be:18: + df:10:7d:5d:22:bf:e5:04:77:7a:75:6b:3e:eb:6d: + 20:a1:a7:60:d4:f1:87:9d:9f:60:b9:d3:db:2c:25: + f4:91:4a:f1:d2:40:e5:a1:10:88:a0:41:5a:98:40: + ca:15:d7:e3:e6:3e:c0:6a:d5:46:b2:b4:90:b4:ae: + 3b:e3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.example.com/example_ca.crl + + Signature Algorithm: sha1WithRSAEncryption + a4:25:21:51:0b:22:6c:63:8d:a9:c1:4f:04:33:69:79:34:f0: + 36:dd:8f:6a:27:5f:07:a2:1d:ef:8b:f0:96:e6:e7:a3:b8:3b: + 85:5e:3f:26:43:8a:8e:95:58:9c:a6:db:9c:51:bf:ea:53:16: + 3e:c1:a8:11:1a:c6:cf:0e:a1:17:18:64:d2:05:f1:c0:9c:a6: + 2b:16:c4:29:54:03:d2:17:bd:15:74:d6:ad:8a:8f:2d:cc:27: + 3b:88:88:f2:ea:d0:a2:cb:e9:42:57:df:26:9f:8a:a2:02:2f: + 35:b6:19:1d:26:43:44:af:12:4b:bc:b9:84:50:02:fd:1d:fa: + 50:e8 +-----BEGIN CERTIFICATE----- +MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF +eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw +JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw +ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS +YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT +ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG +IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy +vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL +D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS +zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6 +dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ +tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug +KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG +SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4 +O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0 +1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo +-----END CERTIFICATE----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.key b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.key new file mode 100644 index 0000000000..9b3433273e --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAydji4HWRg4fYyIDGIE3pFCQwmDNT+lYO7JpDf4epIpQmBses +tdnsVQaBtw3JJFFJ+kf7S0787XWK4SgyvMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu +8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSLD60eyU98EZg3iRXeJLERGnyXSs/zyMt5 +npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHSzk+Xoe1qMMddmLVuCrdP2QPsgHYJsECh +oa+rKlnED1YivL4UvhjfEH1dIr/lBHd6dWs+620goadg1PGHnZ9gudPbLCX0kUrx +0kDloRCIoEFamEDKFdfj5j7AatVGsrSQtK474wIDAQABAoIBAQC2kGDEPBJdMSW2 +VCLfXRiPixwYzXQLXIMrJWwfkQg9qlmqkDd6U50aWkRA2UswegW7RhfYSZ0i+cmf +VMhvTVpOIlwwwtcY6b5/v1bBy60eaySGuuh79xQMlFO8qynQIMStvUfbGTqrdIRb +9VBB4YeS9T12fILejtTZwv2BQ2dj1Y1SCay6Ri85UzJqSClRKgHISybvVdLNjPvP +0TRFBr57zyjL6WE8teKiKchzQko2u86No5uBCdKGsrAkrsdcR0YqlM/pZxd3VKNm ++eny0k+dZZlvcPxzkzP4hEp9+Rw5rP9/s3s/cCwvuuC5JO32ATBWKCbTvPv/XPDb +MdSJtOshAoGBAPzk0eswkcbFYtpnpBNmBAr1dtAdW1lfjUI2ucMMwt7Wns0P/tt+ +gq6Hi1wTaGP0l/dIECgeHwjtWj31ZJjQtFJ1y/kafxo4o9cA8vCydpdvSZaldAfg +sbLlDTDYzEpelaDIbNQBBXFoC5U9JlBhBsIFCL5Z8ZuIeFPsb7t5wwuHAoGBAMxT +jyWfNm1uNxp1xgCnrRsLPQPVnURrSFAqcHrECqRu3F7sozTN7q/cZViemxPvVDGQ +p9c+9bHwaYvW4trO5qDHJ++gGwm5L52bMAY1VUfeTt67fqrey43XpdmzcTX1V9Uj +QWawPUCSDzFjL1MjfCIejtyYf5ash53vj+T8r/vFAoGAA/OPVB1uKazr3n3AEo2F +gqZTNO1AgCT+EArK3EFWyiSQVqPpV4SihheYFdg3yVgJB9QYbIgL9BfBUTaEW97m +8mLkzP+c/Mvlw3ZAVYJ0V+llPPVY2saoACOUES9SAdd4fwqiqK1baGo3xB0wfBEI +CgAKIu9E1ylKuAT5ufQtGAECgYEAtP/kU5h5N3El4QupTdU7VDSdZTMqsHw0v8cI +gsf9AXKvRmtrnBA8u46KPHmruHoO5CVXeSZtsaXdaaH+rYQQ6yXg67WxnehtFLlv +TmCaXiLBTS9cYvMf8FOyuGnsBLeEietEOTov2G5KhR5uwsAxa2wUc7endor5S9/2 +YQuyvV0CgYALbiFpILd5l1ip65eE6JdA3hfttUbV2j2NSW12ej69vqbeOfaSgNse +uYCcXFsBbQPhNPwA+4d1oCe8SyXZg1f7gE812z2Tyr/3vdVnNZlitoxhsHmGiyS7 +gZdaTYCb78l9z0EBdaCVvA16owEle4SR6f9eCwzSI0WPOUra+x/hrA== +-----END RSA PRIVATE KEY----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.p12 b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/certs/server.p12 new file mode 100644 index 0000000000000000000000000000000000000000..9dd9a52911cecac51d644d2a8cbe86205f6bfbbb GIT binary patch literal 2461 zcmV;O31apzf(e-d0Ru3C310>YDuzgg_YDCD0ic2jPy~VrOfZ58NHBr}{{{&vhDe6@ z4FLxRpn?PNFoFZ@0s#Opf&=9S2`Yw2hW8Bt2LUh~1_~;MNQUPU#R7q;inz6jF`n-n7fcOYsZqFrXN zNNebioyTY1V#ejX4!fRPudg|t85Nd{;1BA@Od_EHvrX4GS8w^#X5yXjO9~u9lZ!G< zgKo2(8t={)I#nbaw&v$7J(<&PzQh$f%CvzpQTfhln=jCe3_6O_Y4Kv%UTK3tNR6<0 zuM3I z;qkGbm^%+JWc*eG_Oj*)Ze(sQg3kw*p>}&w{7!sWZNC>5{I#?RSa2`|dBAOIpROS1 zDD&N2(G)y08U`EH{rL9zRR_5q#dDHwPo9<_RzWIiN|Wu{Mno(U>a9uR%G$+>PD$ga zl%pq1kcI~!CnQ-w}}w zL-5^Vfg**9Jx$)&q7F*v1d;E$oBA6B^A=*S?MpBbF_g1Ach&`pP4&lddi{X7_()Eu zBKx{Q(H*a5J^yxF(9^S6{)=ViJZx~T5RfwbI7mj$F!$j;MkqqZycn2pPCsc5Mt&+F1HZ77?yXYM|v1K=Z@?Y4vWFl5< z%7drDLJn&@hLMWlJ;jmc&TTttwJ5{=xK)wosuPe^@=!8p^bFed1k7TaS6%=%;PKAB zar(wEDU+}+*BMZVRvjazycNX-8f9W39ErUXMneHk?-^YqZlL-w&HK2o1tWR~qSHZC5fQNZs~Qz^nI41*quh6?Y9%u;x1EkrU$}Rn9?| z7HT#1*x&-V-)XjCX!NFK744or_&Z^4ssZE>FoFd^1_>&LNQUoNlnC6EQ}M=wPL;R5c>4#pQuq-#q*nT|QdlDx{Q`pb zmj8FlPE&>Gw63fuZHA@PAG6@eaI)vakE^(hrdkv2lC8x%L z;ZN>Q8KSPR6U2QZnsDk>lIjhNNQ3BX38V7Ieb-Rh7Z#NW#o4cF%u8T8lT%)9ioBCV zfaFC6u~bN4on0X)OAmK;RA0++&f6lr)l4<}y7_icK`#v|Woed>$riHI`!d{8m*6%} zz1vL!4sanY?OXjXUjz=fna}I!MglxR0|9960=2TSzh~`Vek>l3?b22QSW&B?a1P_3 z+4mp8Ig`35jJZ~0MUEW_s_9sRDD}@zQ2Bi-l=FJL`)?`|-i%*4Ap=5k7%d{k5}T6a z%L!3cfX+=sM7ODWWfN%(3hlTCZcVu;x~bKV8vCg&6Qki0fOS3`94;ky#)lAba^wMs-ho?`J1+CIP) zWGe-@Bv6=L=2xva25P@?4|mclfkC=+Yojn3IuYZ4q&xe!yz#_;3gbC#HCbI}qD z9=Ol7KO*dDcK0K{Kq}=9KtYge(spfG2uf{^_o7syTmp;_F{-UsLdw_%)|N&Wd73u* ztGFu{9I*#v^#SfGnBd6@L3g_oj}0kmON3vM{B<~n{Du2#`4)nb$6aS{HY+||;2=T0 z>2~o+RX^m8AY#9S?so8%Bt4S-i-PA+v4q2JwWCPE#f*2_k +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIzOJcU8NzjKACAggA +MBQGCCqGSIb3DQMHBAjdK4dY0QgcrgSCBMgCv4euS7bxaRTMSXYliVA+UrAI0iJL +oQgZ6cGFqXqasKu7K6BltLXaKJLX321gV2ofHHAxa1CWFwIgrv/bhci10cJr6BaL +a3+5L5e/EO0eRKVzoplput9mTP27pcJSu8jN5jOu054oamzFKtgGcBuL9mRCAfVq +JSCwbSUHPrwZX6jVDsLggrvE78SIXEYAQDfUrbvBY1kGNNV+U9v410SREYXI3q+8 +a4Paotf2HN5G0nvr0BSJUbY0NUe4AP1NfOM1VE8UiLL3LfZE3ZbOm6XsM8Mxf8rV +BkDOzhErF/dXOE65b5xG4KfoXy78WN7OeJpjNgNUDUl1/3+bc++8f7ZBzOtVAjP7 +diDYU/UrQeLUrLVxTLD6C9J9HvbW5JCEa1FN+pKQKxeaQ9j/dDhJ7XI4ctaIIQui +zrOTLEhBqC10TaNabLNVsLFCgFQMREBVYZoBYbFIZLT4FuRk5yaAYRDCrRKgqlu6 +61E0jOD/hDZIbBO/Vf94d+VaypeFonoz6SdrWgf4heN530d5fd5nOxElRl8LmUcH +LriwJIXB7XCfwgjREceRQpjiqmWPl8hcfe9E2NzwldbE+eLN0mlXgRyLlU+eXova +3r1u60Hb9ocLux3kHUXpZ+MomwkwqIn9qFC0U3KBGt7SmhUWypmoNUPiXP0U4Lno +tynPBODzhDeRv2T0qxULc6OznDE3WOuy88B94/JXhB5D56bRb9FkkpHpmn8MP8SW +fIV3cK/cBoGxgyk+IaL0aQbojFtyeyKbkrz1W3WnPtB3/kqd8USzpCvUBMBVG83D +XzHcU/mRYO61BgyGv0VBXdBtPbmW1CK73eX7gc/uOtqhxUQc3g5hNZDL2rxPCpID +alyGlSQxY8cPWJbYMPq2RHoJNDxnTbFhDm3mdOoTg5qK4+cUZMBqfq1kswXM9Z4p +LSnIviRjpL4a7hhDVAJYOo29rBP+QNdt5CkyLNwjnDv+l8jHOMTP4t1RPvoQx6hc +aOQOcSQnIqDgzot3//dnC2mBTQ66jsOnRPMMs9MQ4up6Wrc5PEt5avBi3B4AQC2Q +TUjL6QAcMR5cJbkecp+5h7W5pUw3OYcYpg6G+unJVGSgZkye2lySGgNuRLmcYjVA +gXfA9a8+HN/TFGHP668pZvHQrfV470ETnHhrh+NLN5AIDR+UFG8is7Xj7Ly2/5bN +M3Q3AYSCb8P8/ZrV3Dfm3qoCoxuNYax0PYt/JBWXTtPG1SClUQg+yo8VMiNw877h +IEdkg1QBxKWY5x+ThK79y+Cwub795ym9bYTwAtH8kpLmamoBT8UvgJumh0i8NGg3 +04B/oyg1P8/TxfbD0uaTPC+tmbIKVyHybTQL6/E0bs2knPp2Zyxno3yE3AI70msZ +mGNuK9mkxITIUbijiRZyeQvZz/x/daYwQ0WuaXXpPQvKcFu7LyIEad8QpIqtSCax +VS9Mtwe7zTCp0jmQDBGltlk1B2rUlQ5rxsFN6kJtBULdQc1TTj0NUp3ESeAE3A/l +wE8fPzBht1OKghJqVndGoh01XhKJfpfaQ85CES0HzA6Nll8SQO0bn6u4SBZGEvBT +pFarRrtS6KbulTDB3yBPrKgd1ZoBQv5/ScW8fPcLi55U6nhR28uu+zKy4yZFgOFR +2KU= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_crt.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_crt.h new file mode 100644 index 0000000000..e91ef8dcef --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_crt.h @@ -0,0 +1,237 @@ +unsigned char client_cert[] = { +0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, +0x20, 0x44, 0x61, 0x74, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, +0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x33, 0x20, 0x28, 0x30, 0x78, 0x32, 0x29, 0x0a, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x4e, +0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x20, 0x34, 0x38, 0x20, 0x28, 0x30, 0x78, 0x33, 0x30, 0x29, +0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x41, +0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x3a, 0x20, 0x73, 0x68, 0x61, 0x31, 0x57, 0x69, +0x74, 0x68, 0x52, 0x53, 0x41, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, +0x43, 0x3d, 0x46, 0x52, 0x2c, 0x20, 0x53, 0x54, 0x3d, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x2c, +0x20, 0x4c, 0x3d, 0x53, 0x6f, 0x6d, 0x65, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2c, 0x20, 0x4f, 0x3d, +0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x2f, 0x65, 0x6d, 0x61, +0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x40, +0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x43, 0x4e, 0x3d, +0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, +0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x0a, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x6f, 0x74, 0x20, 0x42, +0x65, 0x66, 0x6f, 0x72, 0x65, 0x3a, 0x20, 0x4a, 0x75, 0x6e, 0x20, 0x20, 0x37, 0x20, 0x30, 0x38, +0x3a, 0x30, 0x36, 0x3a, 0x34, 0x39, 0x20, 0x32, 0x30, 0x31, 0x37, 0x20, 0x47, 0x4d, 0x54, 0x0a, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x6f, 0x74, 0x20, +0x41, 0x66, 0x74, 0x65, 0x72, 0x20, 0x3a, 0x20, 0x4a, 0x75, 0x6e, 0x20, 0x20, 0x35, 0x20, 0x30, +0x38, 0x3a, 0x30, 0x36, 0x3a, 0x34, 0x39, 0x20, 0x32, 0x30, 0x32, 0x37, 0x20, 0x47, 0x4d, 0x54, +0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, +0x3a, 0x20, 0x43, 0x3d, 0x46, 0x52, 0x2c, 0x20, 0x53, 0x54, 0x3d, 0x52, 0x61, 0x64, 0x69, 0x75, +0x73, 0x2c, 0x20, 0x4f, 0x3d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, +0x2e, 0x2c, 0x20, 0x43, 0x4e, 0x3d, 0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, +0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, +0x65, 0x73, 0x73, 0x3d, 0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, +0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x75, 0x62, +0x6a, 0x65, 0x63, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79, 0x20, +0x49, 0x6e, 0x66, 0x6f, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x41, 0x6c, 0x67, +0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x3a, 0x20, 0x72, 0x73, 0x61, 0x45, 0x6e, 0x63, 0x72, 0x79, +0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x4b, 0x65, 0x79, +0x3a, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x20, 0x62, 0x69, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x6f, 0x64, +0x75, 0x6c, 0x75, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x3a, 0x64, 0x32, 0x3a, +0x66, 0x36, 0x3a, 0x62, 0x65, 0x3a, 0x37, 0x32, 0x3a, 0x61, 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x32, +0x65, 0x3a, 0x35, 0x36, 0x3a, 0x30, 0x63, 0x3a, 0x64, 0x64, 0x3a, 0x66, 0x32, 0x3a, 0x33, 0x62, +0x3a, 0x32, 0x63, 0x3a, 0x37, 0x63, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x30, 0x3a, 0x35, +0x64, 0x3a, 0x30, 0x35, 0x3a, 0x34, 0x30, 0x3a, 0x61, 0x66, 0x3a, 0x30, 0x63, 0x3a, 0x38, 0x63, +0x3a, 0x66, 0x33, 0x3a, 0x38, 0x32, 0x3a, 0x30, 0x63, 0x3a, 0x64, 0x30, 0x3a, 0x31, 0x38, 0x3a, +0x33, 0x34, 0x3a, 0x62, 0x34, 0x3a, 0x65, 0x33, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x37, 0x64, +0x3a, 0x35, 0x66, 0x3a, 0x38, 0x64, 0x3a, 0x30, 0x61, 0x3a, 0x33, 0x65, 0x3a, 0x61, 0x61, 0x3a, +0x37, 0x39, 0x3a, 0x30, 0x32, 0x3a, 0x66, 0x39, 0x3a, 0x39, 0x36, 0x3a, 0x61, 0x64, 0x3a, 0x31, +0x30, 0x3a, 0x30, 0x30, 0x3a, 0x65, 0x63, 0x3a, 0x35, 0x31, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x65, 0x39, 0x3a, 0x64, 0x63, 0x3a, 0x33, 0x66, 0x3a, 0x66, 0x62, 0x3a, 0x65, 0x61, 0x3a, 0x62, +0x30, 0x3a, 0x35, 0x37, 0x3a, 0x65, 0x62, 0x3a, 0x34, 0x38, 0x3a, 0x63, 0x37, 0x3a, 0x63, 0x61, +0x3a, 0x65, 0x66, 0x3a, 0x65, 0x38, 0x3a, 0x30, 0x35, 0x3a, 0x61, 0x62, 0x3a, 0x0a, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x65, 0x65, 0x3a, 0x33, 0x66, 0x3a, 0x36, 0x36, 0x3a, 0x62, 0x61, 0x3a, 0x35, 0x63, +0x3a, 0x39, 0x65, 0x3a, 0x37, 0x66, 0x3a, 0x34, 0x30, 0x3a, 0x38, 0x35, 0x3a, 0x39, 0x66, 0x3a, +0x32, 0x35, 0x3a, 0x61, 0x30, 0x3a, 0x65, 0x30, 0x3a, 0x65, 0x33, 0x3a, 0x37, 0x63, 0x3a, 0x0a, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x63, 0x66, 0x3a, 0x62, 0x36, 0x3a, 0x65, 0x36, 0x3a, 0x33, 0x31, 0x3a, +0x66, 0x35, 0x3a, 0x66, 0x64, 0x3a, 0x32, 0x34, 0x3a, 0x30, 0x33, 0x3a, 0x63, 0x38, 0x3a, 0x66, +0x34, 0x3a, 0x66, 0x62, 0x3a, 0x64, 0x38, 0x3a, 0x61, 0x34, 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x32, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x39, 0x3a, 0x30, 0x35, 0x3a, 0x61, 0x61, 0x3a, 0x35, +0x35, 0x3a, 0x34, 0x33, 0x3a, 0x38, 0x30, 0x3a, 0x66, 0x37, 0x3a, 0x33, 0x65, 0x3a, 0x31, 0x33, +0x3a, 0x31, 0x30, 0x3a, 0x34, 0x33, 0x3a, 0x33, 0x61, 0x3a, 0x38, 0x39, 0x3a, 0x32, 0x34, 0x3a, +0x62, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x38, 0x3a, 0x30, 0x31, 0x3a, 0x38, 0x36, +0x3a, 0x64, 0x31, 0x3a, 0x36, 0x39, 0x3a, 0x37, 0x33, 0x3a, 0x34, 0x34, 0x3a, 0x37, 0x64, 0x3a, +0x66, 0x38, 0x3a, 0x62, 0x39, 0x3a, 0x34, 0x36, 0x3a, 0x32, 0x62, 0x3a, 0x36, 0x62, 0x3a, 0x35, +0x31, 0x3a, 0x64, 0x30, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x3a, 0x33, 0x31, 0x3a, +0x34, 0x62, 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x65, 0x3a, 0x39, 0x66, 0x3a, 0x34, 0x35, 0x3a, 0x66, +0x61, 0x3a, 0x31, 0x32, 0x3a, 0x31, 0x37, 0x3a, 0x30, 0x63, 0x3a, 0x65, 0x66, 0x3a, 0x36, 0x61, +0x3a, 0x66, 0x61, 0x3a, 0x64, 0x30, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x37, 0x3a, 0x33, +0x36, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x62, 0x3a, 0x32, 0x65, 0x3a, 0x64, 0x62, 0x3a, 0x34, 0x65, +0x3a, 0x32, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x30, 0x31, 0x3a, 0x33, 0x33, 0x3a, 0x61, 0x63, 0x3a, +0x62, 0x31, 0x3a, 0x66, 0x37, 0x3a, 0x34, 0x61, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x36, +0x3a, 0x31, 0x38, 0x3a, 0x33, 0x64, 0x3a, 0x35, 0x33, 0x3a, 0x32, 0x32, 0x3a, 0x64, 0x63, 0x3a, +0x65, 0x38, 0x3a, 0x34, 0x61, 0x3a, 0x31, 0x32, 0x3a, 0x37, 0x38, 0x3a, 0x31, 0x31, 0x3a, 0x32, +0x66, 0x3a, 0x65, 0x34, 0x3a, 0x33, 0x62, 0x3a, 0x39, 0x32, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x62, 0x64, 0x3a, 0x64, 0x37, 0x3a, 0x30, 0x37, 0x3a, 0x35, 0x61, 0x3a, 0x63, 0x39, 0x3a, 0x38, +0x31, 0x3a, 0x35, 0x64, 0x3a, 0x34, 0x38, 0x3a, 0x35, 0x38, 0x3a, 0x63, 0x38, 0x3a, 0x30, 0x66, +0x3a, 0x39, 0x62, 0x3a, 0x65, 0x39, 0x3a, 0x61, 0x34, 0x3a, 0x30, 0x66, 0x3a, 0x0a, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x62, 0x62, 0x3a, 0x38, 0x39, 0x3a, 0x62, 0x31, 0x3a, 0x61, 0x64, 0x3a, 0x33, 0x38, +0x3a, 0x30, 0x37, 0x3a, 0x36, 0x66, 0x3a, 0x39, 0x33, 0x3a, 0x64, 0x30, 0x3a, 0x61, 0x36, 0x3a, +0x31, 0x32, 0x3a, 0x35, 0x36, 0x3a, 0x66, 0x39, 0x3a, 0x30, 0x37, 0x3a, 0x34, 0x38, 0x3a, 0x0a, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x32, 0x3a, 0x32, 0x33, 0x3a, 0x32, 0x66, 0x3a, 0x61, 0x33, 0x3a, +0x61, 0x39, 0x3a, 0x39, 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x31, 0x31, 0x3a, 0x30, 0x61, 0x3a, 0x32, +0x37, 0x3a, 0x34, 0x63, 0x3a, 0x34, 0x38, 0x3a, 0x30, 0x61, 0x3a, 0x38, 0x64, 0x3a, 0x37, 0x30, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x31, 0x3a, 0x36, 0x38, 0x3a, 0x37, 0x36, 0x3a, 0x37, +0x61, 0x3a, 0x64, 0x64, 0x3a, 0x62, 0x63, 0x3a, 0x35, 0x34, 0x3a, 0x63, 0x33, 0x3a, 0x34, 0x32, +0x3a, 0x33, 0x33, 0x3a, 0x62, 0x30, 0x3a, 0x37, 0x62, 0x3a, 0x66, 0x36, 0x3a, 0x61, 0x65, 0x3a, +0x31, 0x66, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x37, 0x3a, 0x39, 0x35, 0x3a, 0x35, 0x65, +0x3a, 0x31, 0x31, 0x3a, 0x63, 0x61, 0x3a, 0x66, 0x32, 0x3a, 0x62, 0x34, 0x3a, 0x34, 0x62, 0x3a, +0x35, 0x63, 0x3a, 0x62, 0x61, 0x3a, 0x34, 0x37, 0x3a, 0x36, 0x34, 0x3a, 0x66, 0x30, 0x3a, 0x66, +0x33, 0x3a, 0x64, 0x37, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x37, 0x3a, 0x39, 0x35, 0x3a, +0x37, 0x66, 0x3a, 0x39, 0x33, 0x3a, 0x30, 0x36, 0x3a, 0x61, 0x31, 0x3a, 0x37, 0x32, 0x3a, 0x63, +0x39, 0x3a, 0x38, 0x31, 0x3a, 0x31, 0x32, 0x3a, 0x61, 0x35, 0x3a, 0x62, 0x37, 0x3a, 0x38, 0x66, +0x3a, 0x39, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x31, 0x3a, 0x65, +0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x36, 0x35, 0x35, 0x33, +0x37, 0x20, 0x28, 0x30, 0x78, 0x31, 0x30, 0x30, 0x30, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x58, 0x35, 0x30, 0x39, 0x76, 0x33, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, +0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x58, 0x35, 0x30, 0x39, 0x76, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, +0x65, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x0a, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, +0x4c, 0x53, 0x20, 0x57, 0x65, 0x62, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x41, 0x75, +0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x58, 0x35, 0x30, 0x39, 0x76, 0x33, 0x20, +0x43, 0x52, 0x4c, 0x20, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, +0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x3a, 0x20, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x75, 0x6c, 0x6c, 0x20, +0x4e, 0x61, 0x6d, 0x65, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x52, 0x49, 0x3a, 0x68, 0x74, 0x74, 0x70, +0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, +0x6f, 0x6d, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x2e, 0x63, 0x72, +0x6c, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, +0x20, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x3a, 0x20, 0x73, 0x68, 0x61, 0x31, +0x57, 0x69, 0x74, 0x68, 0x52, 0x53, 0x41, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, +0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x64, 0x3a, 0x30, 0x32, +0x3a, 0x62, 0x63, 0x3a, 0x37, 0x62, 0x3a, 0x38, 0x38, 0x3a, 0x62, 0x38, 0x3a, 0x35, 0x63, 0x3a, +0x65, 0x31, 0x3a, 0x30, 0x37, 0x3a, 0x62, 0x38, 0x3a, 0x62, 0x62, 0x3a, 0x62, 0x61, 0x3a, 0x62, +0x32, 0x3a, 0x66, 0x33, 0x3a, 0x39, 0x38, 0x3a, 0x31, 0x34, 0x3a, 0x38, 0x66, 0x3a, 0x63, 0x62, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x30, 0x3a, 0x32, 0x31, +0x3a, 0x31, 0x33, 0x3a, 0x62, 0x35, 0x3a, 0x65, 0x35, 0x3a, 0x36, 0x66, 0x3a, 0x30, 0x35, 0x3a, +0x34, 0x66, 0x3a, 0x39, 0x32, 0x3a, 0x66, 0x61, 0x3a, 0x61, 0x63, 0x3a, 0x63, 0x30, 0x3a, 0x35, +0x33, 0x3a, 0x61, 0x37, 0x3a, 0x62, 0x30, 0x3a, 0x63, 0x64, 0x3a, 0x37, 0x65, 0x3a, 0x62, 0x61, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x37, 0x3a, 0x33, 0x36, +0x3a, 0x38, 0x35, 0x3a, 0x32, 0x35, 0x3a, 0x64, 0x37, 0x3a, 0x34, 0x31, 0x3a, 0x63, 0x35, 0x3a, +0x32, 0x39, 0x3a, 0x38, 0x34, 0x3a, 0x32, 0x32, 0x3a, 0x37, 0x34, 0x3a, 0x61, 0x66, 0x3a, 0x62, +0x66, 0x3a, 0x33, 0x65, 0x3a, 0x33, 0x34, 0x3a, 0x33, 0x36, 0x3a, 0x64, 0x35, 0x3a, 0x32, 0x34, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x37, 0x61, 0x3a, 0x38, 0x31, +0x3a, 0x65, 0x32, 0x3a, 0x31, 0x62, 0x3a, 0x35, 0x34, 0x3a, 0x35, 0x32, 0x3a, 0x38, 0x35, 0x3a, +0x36, 0x66, 0x3a, 0x37, 0x36, 0x3a, 0x64, 0x65, 0x3a, 0x64, 0x63, 0x3a, 0x36, 0x33, 0x3a, 0x39, +0x38, 0x3a, 0x34, 0x35, 0x3a, 0x66, 0x63, 0x3a, 0x32, 0x63, 0x3a, 0x33, 0x31, 0x3a, 0x66, 0x61, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x32, 0x3a, 0x61, 0x34, +0x3a, 0x37, 0x32, 0x3a, 0x33, 0x61, 0x3a, 0x38, 0x64, 0x3a, 0x64, 0x34, 0x3a, 0x36, 0x61, 0x3a, +0x32, 0x65, 0x3a, 0x64, 0x65, 0x3a, 0x33, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x34, 0x31, 0x3a, 0x65, +0x62, 0x3a, 0x39, 0x34, 0x3a, 0x31, 0x64, 0x3a, 0x65, 0x33, 0x3a, 0x35, 0x39, 0x3a, 0x63, 0x64, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x32, 0x3a, 0x62, 0x65, +0x3a, 0x61, 0x62, 0x3a, 0x66, 0x30, 0x3a, 0x62, 0x36, 0x3a, 0x32, 0x30, 0x3a, 0x38, 0x36, 0x3a, +0x39, 0x63, 0x3a, 0x62, 0x38, 0x3a, 0x34, 0x36, 0x3a, 0x65, 0x65, 0x3a, 0x63, 0x35, 0x3a, 0x36, +0x34, 0x3a, 0x62, 0x61, 0x3a, 0x62, 0x36, 0x3a, 0x36, 0x63, 0x3a, 0x63, 0x63, 0x3a, 0x35, 0x33, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x34, 0x3a, 0x37, 0x61, +0x3a, 0x38, 0x30, 0x3a, 0x31, 0x32, 0x3a, 0x37, 0x37, 0x3a, 0x37, 0x63, 0x3a, 0x65, 0x37, 0x3a, +0x35, 0x31, 0x3a, 0x36, 0x37, 0x3a, 0x39, 0x31, 0x3a, 0x33, 0x32, 0x3a, 0x32, 0x66, 0x3a, 0x38, +0x38, 0x3a, 0x39, 0x64, 0x3a, 0x39, 0x33, 0x3a, 0x61, 0x38, 0x3a, 0x65, 0x66, 0x3a, 0x64, 0x36, +0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x64, 0x3a, 0x64, 0x65, +0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, +0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, +0x44, 0x54, 0x6a, 0x43, 0x43, 0x41, 0x72, 0x65, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, +0x42, 0x4d, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, +0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x43, 0x42, 0x6b, 0x7a, 0x45, 0x4c, 0x4d, 0x41, 0x6b, +0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x52, 0x6c, 0x49, 0x78, 0x0a, 0x44, 0x7a, +0x41, 0x4e, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x42, 0x6c, 0x4a, 0x68, 0x5a, 0x47, +0x6c, 0x31, 0x63, 0x7a, 0x45, 0x53, 0x4d, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, +0x77, 0x4a, 0x55, 0x32, 0x39, 0x74, 0x5a, 0x58, 0x64, 0x6f, 0x5a, 0x58, 0x4a, 0x6c, 0x4d, 0x52, +0x55, 0x77, 0x45, 0x77, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x41, 0x78, 0x46, 0x0a, 0x65, +0x47, 0x46, 0x74, 0x63, 0x47, 0x78, 0x6c, 0x49, 0x45, 0x6c, 0x75, 0x59, 0x79, 0x34, 0x78, 0x49, +0x44, 0x41, 0x65, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x43, +0x51, 0x45, 0x57, 0x45, 0x57, 0x46, 0x6b, 0x62, 0x57, 0x6c, 0x75, 0x51, 0x47, 0x56, 0x34, 0x59, +0x57, 0x31, 0x77, 0x62, 0x47, 0x55, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4d, 0x53, 0x59, 0x77, 0x0a, +0x4a, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, 0x31, 0x46, 0x65, 0x47, 0x46, 0x74, +0x63, 0x47, 0x78, 0x6c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, +0x59, 0x58, 0x52, 0x6c, 0x49, 0x45, 0x46, 0x31, 0x64, 0x47, 0x68, 0x76, 0x63, 0x6d, 0x6c, 0x30, +0x65, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4e, 0x7a, 0x41, 0x32, 0x4d, 0x44, 0x63, 0x77, +0x0a, 0x4f, 0x44, 0x41, 0x32, 0x4e, 0x44, 0x6c, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4e, 0x7a, 0x41, +0x32, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x44, 0x41, 0x32, 0x4e, 0x44, 0x6c, 0x61, 0x4d, 0x48, 0x45, +0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6b, 0x5a, +0x53, 0x4d, 0x51, 0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x5a, +0x53, 0x0a, 0x59, 0x57, 0x52, 0x70, 0x64, 0x58, 0x4d, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, +0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x44, 0x45, 0x56, 0x34, 0x59, 0x57, 0x31, 0x77, 0x62, 0x47, +0x55, 0x67, 0x53, 0x57, 0x35, 0x6a, 0x4c, 0x6a, 0x45, 0x5a, 0x4d, 0x42, 0x63, 0x47, 0x41, 0x31, +0x55, 0x45, 0x41, 0x77, 0x77, 0x51, 0x64, 0x58, 0x4e, 0x6c, 0x63, 0x6b, 0x42, 0x6c, 0x65, 0x47, +0x46, 0x74, 0x0a, 0x63, 0x47, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x45, 0x66, 0x4d, +0x42, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4a, 0x41, +0x52, 0x59, 0x51, 0x64, 0x58, 0x4e, 0x6c, 0x63, 0x6b, 0x42, 0x6c, 0x65, 0x47, 0x46, 0x74, 0x63, +0x47, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x43, 0x43, 0x41, 0x53, 0x49, 0x77, 0x44, +0x51, 0x59, 0x4a, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, +0x42, 0x51, 0x41, 0x44, 0x67, 0x67, 0x45, 0x50, 0x41, 0x44, 0x43, 0x43, 0x41, 0x51, 0x6f, 0x43, +0x67, 0x67, 0x45, 0x42, 0x41, 0x4e, 0x4c, 0x32, 0x76, 0x6e, 0x4b, 0x6c, 0x71, 0x79, 0x35, 0x57, +0x44, 0x4e, 0x33, 0x79, 0x4f, 0x79, 0x78, 0x38, 0x34, 0x46, 0x30, 0x46, 0x51, 0x4b, 0x38, 0x4d, +0x6a, 0x50, 0x4f, 0x43, 0x0a, 0x44, 0x4e, 0x41, 0x59, 0x4e, 0x4c, 0x54, 0x6a, 0x66, 0x56, 0x2b, +0x4e, 0x43, 0x6a, 0x36, 0x71, 0x65, 0x51, 0x4c, 0x35, 0x6c, 0x71, 0x30, 0x51, 0x41, 0x4f, 0x78, +0x52, 0x36, 0x64, 0x77, 0x2f, 0x2b, 0x2b, 0x71, 0x77, 0x56, 0x2b, 0x74, 0x49, 0x78, 0x38, 0x72, +0x76, 0x36, 0x41, 0x57, 0x72, 0x37, 0x6a, 0x39, 0x6d, 0x75, 0x6c, 0x79, 0x65, 0x66, 0x30, 0x43, +0x46, 0x6e, 0x79, 0x57, 0x67, 0x0a, 0x34, 0x4f, 0x4e, 0x38, 0x7a, 0x37, 0x62, 0x6d, 0x4d, 0x66, +0x58, 0x39, 0x4a, 0x41, 0x50, 0x49, 0x39, 0x50, 0x76, 0x59, 0x70, 0x50, 0x4f, 0x53, 0x4b, 0x51, +0x57, 0x71, 0x56, 0x55, 0x4f, 0x41, 0x39, 0x7a, 0x34, 0x54, 0x45, 0x45, 0x4d, 0x36, 0x69, 0x53, +0x53, 0x2b, 0x32, 0x41, 0x47, 0x47, 0x30, 0x57, 0x6c, 0x7a, 0x52, 0x48, 0x33, 0x34, 0x75, 0x55, +0x59, 0x72, 0x61, 0x31, 0x48, 0x51, 0x0a, 0x45, 0x54, 0x46, 0x4c, 0x42, 0x71, 0x36, 0x66, 0x52, +0x66, 0x6f, 0x53, 0x46, 0x77, 0x7a, 0x76, 0x61, 0x76, 0x72, 0x51, 0x39, 0x7a, 0x5a, 0x47, 0x36, +0x79, 0x37, 0x62, 0x54, 0x69, 0x42, 0x47, 0x41, 0x54, 0x4f, 0x73, 0x73, 0x66, 0x64, 0x4b, 0x35, +0x68, 0x67, 0x39, 0x55, 0x79, 0x4c, 0x63, 0x36, 0x45, 0x6f, 0x53, 0x65, 0x42, 0x45, 0x76, 0x35, +0x44, 0x75, 0x53, 0x76, 0x64, 0x63, 0x48, 0x0a, 0x57, 0x73, 0x6d, 0x42, 0x58, 0x55, 0x68, 0x59, +0x79, 0x41, 0x2b, 0x62, 0x36, 0x61, 0x51, 0x50, 0x75, 0x34, 0x6d, 0x78, 0x72, 0x54, 0x67, 0x48, +0x62, 0x35, 0x50, 0x51, 0x70, 0x68, 0x4a, 0x57, 0x2b, 0x51, 0x64, 0x49, 0x30, 0x69, 0x4d, 0x76, +0x6f, 0x36, 0x6d, 0x54, 0x73, 0x42, 0x45, 0x4b, 0x4a, 0x30, 0x78, 0x49, 0x43, 0x6f, 0x31, 0x77, +0x51, 0x57, 0x68, 0x32, 0x65, 0x74, 0x32, 0x38, 0x0a, 0x56, 0x4d, 0x4e, 0x43, 0x4d, 0x37, 0x42, +0x37, 0x39, 0x71, 0x34, 0x66, 0x35, 0x35, 0x56, 0x65, 0x45, 0x63, 0x72, 0x79, 0x74, 0x45, 0x74, +0x63, 0x75, 0x6b, 0x64, 0x6b, 0x38, 0x50, 0x50, 0x58, 0x68, 0x35, 0x56, 0x2f, 0x6b, 0x77, 0x61, +0x68, 0x63, 0x73, 0x6d, 0x42, 0x45, 0x71, 0x57, 0x33, 0x6a, 0x35, 0x31, 0x2b, 0x30, 0x65, 0x38, +0x43, 0x41, 0x77, 0x45, 0x41, 0x41, 0x61, 0x4e, 0x50, 0x0a, 0x4d, 0x45, 0x30, 0x77, 0x45, 0x77, +0x59, 0x44, 0x56, 0x52, 0x30, 0x6c, 0x42, 0x41, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x77, +0x59, 0x42, 0x42, 0x51, 0x55, 0x48, 0x41, 0x77, 0x49, 0x77, 0x4e, 0x67, 0x59, 0x44, 0x56, 0x52, +0x30, 0x66, 0x42, 0x43, 0x38, 0x77, 0x4c, 0x54, 0x41, 0x72, 0x6f, 0x43, 0x6d, 0x67, 0x4a, 0x34, +0x59, 0x6c, 0x61, 0x48, 0x52, 0x30, 0x63, 0x44, 0x6f, 0x76, 0x0a, 0x4c, 0x33, 0x64, 0x33, 0x64, +0x79, 0x35, 0x6c, 0x65, 0x47, 0x46, 0x74, 0x63, 0x47, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, +0x53, 0x39, 0x6c, 0x65, 0x47, 0x46, 0x74, 0x63, 0x47, 0x78, 0x6c, 0x58, 0x32, 0x4e, 0x68, 0x4c, +0x6d, 0x4e, 0x79, 0x62, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, +0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x41, 0x4f, 0x42, 0x0a, 0x67, 0x51, 0x41, 0x74, +0x41, 0x72, 0x78, 0x37, 0x69, 0x4c, 0x68, 0x63, 0x34, 0x51, 0x65, 0x34, 0x75, 0x37, 0x71, 0x79, +0x38, 0x35, 0x67, 0x55, 0x6a, 0x38, 0x75, 0x77, 0x49, 0x52, 0x4f, 0x31, 0x35, 0x57, 0x38, 0x46, +0x54, 0x35, 0x4c, 0x36, 0x72, 0x4d, 0x42, 0x54, 0x70, 0x37, 0x44, 0x4e, 0x66, 0x72, 0x71, 0x48, +0x4e, 0x6f, 0x55, 0x6c, 0x31, 0x30, 0x48, 0x46, 0x4b, 0x59, 0x51, 0x69, 0x0a, 0x64, 0x4b, 0x2b, +0x2f, 0x50, 0x6a, 0x51, 0x32, 0x31, 0x53, 0x52, 0x36, 0x67, 0x65, 0x49, 0x62, 0x56, 0x46, 0x4b, +0x46, 0x62, 0x33, 0x62, 0x65, 0x33, 0x47, 0x4f, 0x59, 0x52, 0x66, 0x77, 0x73, 0x4d, 0x66, 0x6f, +0x69, 0x70, 0x48, 0x49, 0x36, 0x6a, 0x64, 0x52, 0x71, 0x4c, 0x74, 0x34, 0x7a, 0x45, 0x45, 0x48, +0x72, 0x6c, 0x42, 0x33, 0x6a, 0x57, 0x63, 0x32, 0x79, 0x76, 0x71, 0x76, 0x77, 0x0a, 0x74, 0x69, +0x43, 0x47, 0x6e, 0x4c, 0x68, 0x47, 0x37, 0x73, 0x56, 0x6b, 0x75, 0x72, 0x5a, 0x73, 0x7a, 0x46, +0x4e, 0x45, 0x65, 0x6f, 0x41, 0x53, 0x64, 0x33, 0x7a, 0x6e, 0x55, 0x57, 0x65, 0x52, 0x4d, 0x69, +0x2b, 0x49, 0x6e, 0x5a, 0x4f, 0x6f, 0x37, 0x39, 0x62, 0x4e, 0x33, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, +0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, +0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, }; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_key.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_key.h new file mode 100644 index 0000000000..7adf0852ff --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/client_key.h @@ -0,0 +1,106 @@ +unsigned char client_key[] = { +0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, +0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, +0x4d, 0x49, 0x49, 0x45, 0x70, 0x41, 0x49, 0x42, 0x41, 0x41, 0x4b, 0x43, 0x41, 0x51, 0x45, 0x41, +0x30, 0x76, 0x61, 0x2b, 0x63, 0x71, 0x57, 0x72, 0x4c, 0x6c, 0x59, 0x4d, 0x33, 0x66, 0x49, 0x37, +0x4c, 0x48, 0x7a, 0x67, 0x58, 0x51, 0x56, 0x41, 0x72, 0x77, 0x79, 0x4d, 0x38, 0x34, 0x49, 0x4d, +0x30, 0x42, 0x67, 0x30, 0x74, 0x4f, 0x4e, 0x39, 0x58, 0x34, 0x30, 0x4b, 0x50, 0x71, 0x70, 0x35, +0x0a, 0x41, 0x76, 0x6d, 0x57, 0x72, 0x52, 0x41, 0x41, 0x37, 0x46, 0x48, 0x70, 0x33, 0x44, 0x2f, +0x37, 0x36, 0x72, 0x42, 0x58, 0x36, 0x30, 0x6a, 0x48, 0x79, 0x75, 0x2f, 0x6f, 0x42, 0x61, 0x76, +0x75, 0x50, 0x32, 0x61, 0x36, 0x58, 0x4a, 0x35, 0x2f, 0x51, 0x49, 0x57, 0x66, 0x4a, 0x61, 0x44, +0x67, 0x34, 0x33, 0x7a, 0x50, 0x74, 0x75, 0x59, 0x78, 0x39, 0x66, 0x30, 0x6b, 0x41, 0x38, 0x6a, +0x30, 0x0a, 0x2b, 0x39, 0x69, 0x6b, 0x38, 0x35, 0x49, 0x70, 0x42, 0x61, 0x70, 0x56, 0x51, 0x34, +0x44, 0x33, 0x50, 0x68, 0x4d, 0x51, 0x51, 0x7a, 0x71, 0x4a, 0x4a, 0x4c, 0x37, 0x59, 0x41, 0x59, +0x62, 0x52, 0x61, 0x58, 0x4e, 0x45, 0x66, 0x66, 0x69, 0x35, 0x52, 0x69, 0x74, 0x72, 0x55, 0x64, +0x41, 0x52, 0x4d, 0x55, 0x73, 0x47, 0x72, 0x70, 0x39, 0x46, 0x2b, 0x68, 0x49, 0x58, 0x44, 0x4f, +0x39, 0x71, 0x0a, 0x2b, 0x74, 0x44, 0x33, 0x4e, 0x6b, 0x62, 0x72, 0x4c, 0x74, 0x74, 0x4f, 0x49, +0x45, 0x59, 0x42, 0x4d, 0x36, 0x79, 0x78, 0x39, 0x30, 0x72, 0x6d, 0x47, 0x44, 0x31, 0x54, 0x49, +0x74, 0x7a, 0x6f, 0x53, 0x68, 0x4a, 0x34, 0x45, 0x53, 0x2f, 0x6b, 0x4f, 0x35, 0x4b, 0x39, 0x31, +0x77, 0x64, 0x61, 0x79, 0x59, 0x46, 0x64, 0x53, 0x46, 0x6a, 0x49, 0x44, 0x35, 0x76, 0x70, 0x70, +0x41, 0x2b, 0x37, 0x0a, 0x69, 0x62, 0x47, 0x74, 0x4f, 0x41, 0x64, 0x76, 0x6b, 0x39, 0x43, 0x6d, +0x45, 0x6c, 0x62, 0x35, 0x42, 0x30, 0x6a, 0x53, 0x49, 0x79, 0x2b, 0x6a, 0x71, 0x5a, 0x4f, 0x77, +0x45, 0x51, 0x6f, 0x6e, 0x54, 0x45, 0x67, 0x4b, 0x6a, 0x58, 0x42, 0x42, 0x61, 0x48, 0x5a, 0x36, +0x33, 0x62, 0x78, 0x55, 0x77, 0x30, 0x49, 0x7a, 0x73, 0x48, 0x76, 0x32, 0x72, 0x68, 0x2f, 0x6e, +0x6c, 0x56, 0x34, 0x52, 0x0a, 0x79, 0x76, 0x4b, 0x30, 0x53, 0x31, 0x79, 0x36, 0x52, 0x32, 0x54, +0x77, 0x38, 0x39, 0x65, 0x48, 0x6c, 0x58, 0x2b, 0x54, 0x42, 0x71, 0x46, 0x79, 0x79, 0x59, 0x45, +0x53, 0x70, 0x62, 0x65, 0x50, 0x6e, 0x58, 0x37, 0x52, 0x37, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41, +0x42, 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x35, 0x50, 0x6e, 0x63, 0x4f, 0x33, 0x74, 0x42, +0x49, 0x65, 0x4d, 0x45, 0x46, 0x0a, 0x70, 0x75, 0x30, 0x30, 0x37, 0x46, 0x5a, 0x71, 0x39, 0x2f, +0x44, 0x4c, 0x68, 0x50, 0x37, 0x44, 0x32, 0x42, 0x39, 0x2b, 0x48, 0x72, 0x4d, 0x78, 0x58, 0x30, +0x79, 0x34, 0x75, 0x58, 0x55, 0x55, 0x66, 0x38, 0x61, 0x51, 0x79, 0x53, 0x37, 0x34, 0x75, 0x6b, +0x50, 0x46, 0x50, 0x30, 0x78, 0x56, 0x33, 0x55, 0x31, 0x4d, 0x30, 0x42, 0x6e, 0x7a, 0x66, 0x55, +0x34, 0x4b, 0x73, 0x63, 0x79, 0x51, 0x0a, 0x4a, 0x6c, 0x2b, 0x6e, 0x42, 0x6f, 0x4b, 0x41, 0x54, +0x36, 0x43, 0x33, 0x76, 0x46, 0x31, 0x35, 0x77, 0x69, 0x47, 0x58, 0x51, 0x41, 0x4a, 0x34, 0x76, +0x50, 0x75, 0x44, 0x34, 0x41, 0x74, 0x65, 0x30, 0x33, 0x66, 0x6a, 0x4b, 0x57, 0x48, 0x32, 0x69, +0x78, 0x4a, 0x41, 0x61, 0x6b, 0x68, 0x43, 0x5a, 0x52, 0x30, 0x31, 0x51, 0x62, 0x49, 0x58, 0x42, +0x6e, 0x42, 0x6b, 0x64, 0x72, 0x76, 0x66, 0x0a, 0x34, 0x30, 0x31, 0x42, 0x42, 0x6a, 0x6c, 0x50, +0x55, 0x44, 0x63, 0x49, 0x47, 0x5a, 0x6f, 0x38, 0x46, 0x62, 0x4c, 0x7a, 0x45, 0x4d, 0x6c, 0x47, +0x54, 0x6f, 0x38, 0x34, 0x76, 0x45, 0x39, 0x76, 0x33, 0x51, 0x6d, 0x6b, 0x62, 0x69, 0x2b, 0x50, +0x7a, 0x50, 0x43, 0x68, 0x32, 0x59, 0x43, 0x2b, 0x4e, 0x44, 0x6d, 0x73, 0x4f, 0x63, 0x49, 0x57, +0x31, 0x7a, 0x70, 0x6d, 0x77, 0x79, 0x59, 0x43, 0x0a, 0x5a, 0x59, 0x43, 0x70, 0x6f, 0x57, 0x67, +0x6c, 0x34, 0x2b, 0x2b, 0x6b, 0x71, 0x58, 0x58, 0x6e, 0x30, 0x4e, 0x47, 0x68, 0x75, 0x61, 0x4f, +0x67, 0x42, 0x30, 0x4a, 0x4c, 0x73, 0x4a, 0x4f, 0x42, 0x70, 0x78, 0x2f, 0x68, 0x4f, 0x4f, 0x6a, +0x42, 0x55, 0x2f, 0x77, 0x58, 0x43, 0x4b, 0x61, 0x58, 0x5a, 0x31, 0x76, 0x63, 0x68, 0x59, 0x71, +0x66, 0x62, 0x76, 0x76, 0x78, 0x32, 0x67, 0x66, 0x32, 0x0a, 0x57, 0x58, 0x34, 0x50, 0x30, 0x43, +0x69, 0x54, 0x48, 0x31, 0x7a, 0x37, 0x4d, 0x45, 0x41, 0x48, 0x61, 0x6e, 0x61, 0x5a, 0x6b, 0x63, +0x6e, 0x4e, 0x79, 0x78, 0x56, 0x2f, 0x6f, 0x46, 0x31, 0x45, 0x49, 0x4d, 0x59, 0x35, 0x70, 0x30, +0x76, 0x44, 0x44, 0x7a, 0x67, 0x72, 0x4b, 0x74, 0x70, 0x70, 0x76, 0x50, 0x4f, 0x71, 0x73, 0x70, +0x6a, 0x79, 0x64, 0x6a, 0x65, 0x30, 0x33, 0x2b, 0x43, 0x45, 0x0a, 0x74, 0x30, 0x77, 0x4b, 0x47, +0x50, 0x69, 0x35, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x50, 0x41, 0x47, 0x32, 0x59, 0x34, 0x65, 0x66, +0x67, 0x77, 0x4c, 0x63, 0x6f, 0x57, 0x64, 0x50, 0x6a, 0x4b, 0x5a, 0x74, 0x73, 0x48, 0x4c, 0x68, +0x44, 0x68, 0x4c, 0x4a, 0x6e, 0x76, 0x78, 0x6b, 0x71, 0x6e, 0x4e, 0x6b, 0x7a, 0x64, 0x50, 0x6e, +0x4c, 0x5a, 0x6f, 0x6a, 0x4e, 0x69, 0x38, 0x70, 0x4b, 0x6b, 0x56, 0x0a, 0x2f, 0x59, 0x75, 0x2b, +0x2b, 0x70, 0x50, 0x65, 0x6d, 0x4a, 0x5a, 0x5a, 0x61, 0x34, 0x59, 0x41, 0x70, 0x2b, 0x4f, 0x6e, +0x71, 0x79, 0x45, 0x66, 0x68, 0x63, 0x68, 0x61, 0x2b, 0x48, 0x59, 0x71, 0x4b, 0x4d, 0x77, 0x52, +0x43, 0x38, 0x74, 0x33, 0x59, 0x72, 0x45, 0x56, 0x4f, 0x6c, 0x52, 0x51, 0x54, 0x66, 0x57, 0x2f, +0x4f, 0x6f, 0x53, 0x72, 0x70, 0x30, 0x35, 0x39, 0x4a, 0x49, 0x52, 0x56, 0x0a, 0x6a, 0x54, 0x76, +0x71, 0x2f, 0x75, 0x37, 0x44, 0x64, 0x59, 0x47, 0x4a, 0x52, 0x52, 0x67, 0x4d, 0x4c, 0x55, 0x4a, +0x69, 0x45, 0x49, 0x2b, 0x37, 0x78, 0x6a, 0x31, 0x57, 0x62, 0x54, 0x63, 0x32, 0x45, 0x63, 0x65, +0x4a, 0x41, 0x67, 0x6e, 0x30, 0x71, 0x66, 0x4b, 0x76, 0x62, 0x76, 0x42, 0x74, 0x56, 0x4a, 0x50, +0x30, 0x4c, 0x48, 0x31, 0x54, 0x41, 0x6f, 0x47, 0x42, 0x41, 0x4f, 0x45, 0x41, 0x0a, 0x78, 0x5a, +0x42, 0x37, 0x53, 0x77, 0x79, 0x58, 0x2b, 0x7a, 0x44, 0x47, 0x52, 0x54, 0x75, 0x67, 0x71, 0x4d, +0x59, 0x67, 0x2b, 0x73, 0x59, 0x6f, 0x62, 0x62, 0x51, 0x48, 0x4a, 0x37, 0x75, 0x74, 0x4c, 0x79, +0x6f, 0x58, 0x2b, 0x63, 0x6b, 0x65, 0x47, 0x2b, 0x73, 0x50, 0x45, 0x6a, 0x45, 0x59, 0x4c, 0x70, +0x51, 0x51, 0x66, 0x73, 0x68, 0x45, 0x54, 0x2f, 0x67, 0x77, 0x46, 0x38, 0x5a, 0x4b, 0x0a, 0x34, +0x61, 0x49, 0x4c, 0x6b, 0x41, 0x43, 0x78, 0x2f, 0x74, 0x6e, 0x61, 0x37, 0x39, 0x39, 0x78, 0x43, +0x6a, 0x51, 0x64, 0x6d, 0x79, 0x79, 0x63, 0x33, 0x33, 0x38, 0x4e, 0x4f, 0x39, 0x57, 0x55, 0x4c, +0x6c, 0x59, 0x31, 0x78, 0x46, 0x2b, 0x36, 0x35, 0x57, 0x66, 0x65, 0x61, 0x78, 0x72, 0x74, 0x54, +0x41, 0x73, 0x71, 0x56, 0x69, 0x6b, 0x58, 0x33, 0x70, 0x31, 0x39, 0x4d, 0x63, 0x52, 0x49, 0x0a, +0x69, 0x6a, 0x58, 0x38, 0x6b, 0x37, 0x4d, 0x73, 0x79, 0x33, 0x67, 0x59, 0x57, 0x4a, 0x58, 0x65, +0x76, 0x33, 0x4d, 0x43, 0x74, 0x50, 0x54, 0x32, 0x2b, 0x67, 0x36, 0x38, 0x49, 0x67, 0x62, 0x4c, +0x2f, 0x57, 0x32, 0x77, 0x59, 0x2b, 0x6c, 0x31, 0x41, 0x6f, 0x47, 0x41, 0x54, 0x37, 0x78, 0x47, +0x79, 0x30, 0x4a, 0x76, 0x35, 0x76, 0x70, 0x71, 0x69, 0x64, 0x35, 0x70, 0x69, 0x67, 0x2b, 0x73, +0x0a, 0x4f, 0x59, 0x61, 0x74, 0x48, 0x72, 0x4a, 0x41, 0x54, 0x34, 0x34, 0x35, 0x68, 0x58, 0x55, +0x49, 0x51, 0x61, 0x69, 0x4e, 0x79, 0x37, 0x37, 0x42, 0x67, 0x30, 0x4a, 0x76, 0x68, 0x4d, 0x67, +0x4d, 0x57, 0x54, 0x38, 0x52, 0x4b, 0x4d, 0x77, 0x61, 0x62, 0x6c, 0x2b, 0x34, 0x4b, 0x32, 0x54, +0x4f, 0x59, 0x50, 0x38, 0x54, 0x42, 0x30, 0x62, 0x63, 0x66, 0x32, 0x6c, 0x51, 0x2f, 0x70, 0x67, +0x55, 0x0a, 0x77, 0x32, 0x32, 0x71, 0x4f, 0x47, 0x59, 0x70, 0x66, 0x2b, 0x41, 0x6f, 0x5a, 0x31, +0x66, 0x68, 0x2f, 0x68, 0x41, 0x50, 0x6c, 0x59, 0x45, 0x63, 0x62, 0x43, 0x4f, 0x41, 0x58, 0x51, +0x47, 0x36, 0x6b, 0x44, 0x77, 0x4a, 0x67, 0x6a, 0x47, 0x6d, 0x4f, 0x47, 0x6a, 0x73, 0x62, 0x67, +0x65, 0x6c, 0x68, 0x56, 0x62, 0x6b, 0x58, 0x34, 0x73, 0x6d, 0x57, 0x4c, 0x76, 0x38, 0x50, 0x67, +0x6f, 0x56, 0x0a, 0x4c, 0x2b, 0x37, 0x67, 0x6f, 0x59, 0x51, 0x49, 0x62, 0x4e, 0x6c, 0x41, 0x68, +0x6c, 0x67, 0x62, 0x62, 0x36, 0x62, 0x2b, 0x6e, 0x49, 0x63, 0x43, 0x67, 0x59, 0x42, 0x42, 0x37, +0x5a, 0x72, 0x32, 0x43, 0x64, 0x70, 0x6b, 0x74, 0x30, 0x65, 0x6e, 0x39, 0x41, 0x43, 0x6e, 0x52, +0x78, 0x30, 0x4d, 0x36, 0x4f, 0x37, 0x79, 0x44, 0x7a, 0x69, 0x4e, 0x7a, 0x71, 0x62, 0x71, 0x7a, +0x41, 0x55, 0x4d, 0x0a, 0x33, 0x58, 0x65, 0x59, 0x59, 0x5a, 0x55, 0x6d, 0x6e, 0x41, 0x54, 0x6c, +0x6b, 0x38, 0x4e, 0x61, 0x4b, 0x54, 0x63, 0x73, 0x38, 0x53, 0x39, 0x4a, 0x64, 0x72, 0x59, 0x51, +0x71, 0x54, 0x4a, 0x52, 0x36, 0x2f, 0x64, 0x6d, 0x37, 0x4d, 0x44, 0x54, 0x44, 0x74, 0x37, 0x49, +0x5a, 0x76, 0x50, 0x70, 0x62, 0x31, 0x39, 0x66, 0x68, 0x42, 0x76, 0x4d, 0x75, 0x35, 0x44, 0x7a, +0x74, 0x50, 0x61, 0x61, 0x0a, 0x31, 0x69, 0x68, 0x54, 0x4d, 0x49, 0x30, 0x31, 0x6b, 0x53, 0x74, +0x71, 0x2b, 0x57, 0x73, 0x56, 0x76, 0x6e, 0x4c, 0x2b, 0x6d, 0x58, 0x72, 0x6d, 0x52, 0x4a, 0x2f, +0x48, 0x64, 0x73, 0x58, 0x67, 0x71, 0x63, 0x43, 0x52, 0x65, 0x4b, 0x65, 0x70, 0x36, 0x65, 0x42, +0x54, 0x45, 0x62, 0x43, 0x68, 0x50, 0x34, 0x4c, 0x4d, 0x59, 0x47, 0x33, 0x47, 0x30, 0x59, 0x4e, +0x61, 0x34, 0x48, 0x7a, 0x43, 0x0a, 0x6e, 0x6a, 0x4f, 0x34, 0x58, 0x51, 0x4b, 0x42, 0x67, 0x51, +0x44, 0x52, 0x6e, 0x62, 0x71, 0x71, 0x67, 0x32, 0x43, 0x4e, 0x54, 0x6e, 0x53, 0x39, 0x34, 0x42, +0x4e, 0x32, 0x44, 0x33, 0x75, 0x7a, 0x7a, 0x45, 0x4c, 0x74, 0x77, 0x73, 0x49, 0x47, 0x36, 0x61, +0x56, 0x43, 0x74, 0x6c, 0x30, 0x39, 0x5a, 0x73, 0x4c, 0x6e, 0x47, 0x61, 0x42, 0x4b, 0x56, 0x56, +0x44, 0x74, 0x50, 0x36, 0x42, 0x49, 0x0a, 0x6a, 0x32, 0x68, 0x47, 0x44, 0x37, 0x78, 0x77, 0x34, +0x67, 0x35, 0x4a, 0x65, 0x53, 0x50, 0x49, 0x4a, 0x55, 0x35, 0x4a, 0x30, 0x33, 0x6e, 0x41, 0x4c, +0x54, 0x59, 0x33, 0x68, 0x7a, 0x31, 0x4a, 0x79, 0x49, 0x37, 0x41, 0x4a, 0x43, 0x58, 0x37, 0x2b, +0x4a, 0x52, 0x74, 0x55, 0x54, 0x58, 0x32, 0x41, 0x38, 0x43, 0x34, 0x6d, 0x6c, 0x62, 0x65, 0x75, +0x6c, 0x37, 0x69, 0x6c, 0x47, 0x61, 0x55, 0x0a, 0x41, 0x37, 0x4d, 0x46, 0x54, 0x38, 0x47, 0x71, +0x68, 0x6a, 0x59, 0x59, 0x61, 0x38, 0x34, 0x47, 0x7a, 0x4e, 0x63, 0x41, 0x31, 0x6d, 0x4b, 0x38, +0x79, 0x6e, 0x6c, 0x69, 0x78, 0x70, 0x4c, 0x38, 0x2b, 0x79, 0x7a, 0x54, 0x54, 0x2f, 0x38, 0x6c, +0x57, 0x49, 0x6e, 0x57, 0x52, 0x42, 0x61, 0x36, 0x39, 0x53, 0x6b, 0x6b, 0x74, 0x41, 0x3d, 0x3d, +0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, +0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, }; diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/import_ca_crt_key.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/import_ca_crt_key.sh new file mode 100755 index 0000000000..275ddb31fc --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/import_ca_crt_key.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +CA_FILE=./certs/ca.pem +CRT_FILE=./certs/client.crt +KEY_FILE=./certs/client.key + +if [ -f $CA_FILE ];then + echo "unsigned char ca[] = {" > ./ca.h + ./str2hex $CA_FILE >> ./ca.h + echo "0x00, };" >> ./ca.h +fi + +if [ -f $CRT_FILE ];then + echo "unsigned char client_cert[] = {" > ./client_crt.h + ./str2hex $CRT_FILE >> ./client_crt.h + echo "0x00, };" >> ./client_crt.h +fi + +if [ -f $KEY_FILE ];then + echo "unsigned char client_key[] = {" > ./client_key.h + ./str2hex $KEY_FILE >> ./client_key.h + echo "0x00, };" >> ./client_key.h +fi diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/str2hex b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/include/wpa2_pki/str2hex new file mode 100755 index 0000000000000000000000000000000000000000..1fe37dfaea93a3d568039e75345c4a468bb3f750 GIT binary patch literal 8778 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 PE7{^f*US!k+>8GKVJHBr literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/user_main.c new file mode 100644 index 0000000000..9751ee608c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wpa2_enterprise/user/user_main.c @@ -0,0 +1,145 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "user_interface.h" + +#include "wpa2_enterprise.h" + +#include "wpa2_pki/ca.h" +#include "wpa2_pki/client_crt.h" +#include "wpa2_pki/client_key.h" + +#define SSID "wpa2_test" +#define PASSWORD "" + +#define WPA2_IDENTITY "user1" +#define WPA2_USERNAME "espressif" +#define WPA2_PASSWORD "test11" + +typedef enum { + EAP_TLS, + EAP_PEAP, + EAP_TTLS, +} eap_method_t; + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ +} + +void user_set_station_config(void) +{ + char ssid[32] = SSID; + char password[64] = PASSWORD; + struct station_config sta_conf = { 0 }; + + os_memcpy(sta_conf.ssid, ssid, 32); + os_memcpy(sta_conf.password, password, 64); + wifi_station_set_config(&sta_conf); +} + +void user_set_wpa2_config(void) +{ + eap_method_t method = EAP_TLS; + char *identity = WPA2_IDENTITY; + char *username = WPA2_USERNAME; + char *password = WPA2_PASSWORD; + + wifi_station_set_wpa2_enterprise_auth(1); + + //wifi_station_set_enterprise_identity(identity, os_strlen(identity));//This is an option. If not call this API, the outer identity will be "anonymous@espressif.com". + + if (method == EAP_TLS) { + wifi_station_set_enterprise_cert_key(client_cert, os_strlen(client_cert)+1, client_key, os_strlen(client_key)+1, NULL, 1); + //wifi_station_set_enterprise_username(username, os_strlen(username));//This is an option for EAP_PEAP and EAP_TLS. + } + else if (method == EAP_PEAP || method == EAP_TTLS) { + wifi_station_set_enterprise_username(username, os_strlen(username)); + wifi_station_set_enterprise_password(password, os_strlen(password)); + //wifi_station_set_enterprise_ca_cert(ca, os_strlen(ca)+1);//This is an option for EAP_PEAP and EAP_TTLS. + } +} + +void ICACHE_FLASH_ATTR +user_init(void) +{ + os_printf("This is an example for wpa2 enterprise...\n"); + + wifi_set_opmode(STATION_MODE); + user_set_station_config(); + user_set_wpa2_config(); + wifi_station_connect(); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/Makefile new file mode 100644 index 0000000000..576632581a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/Makefile @@ -0,0 +1,123 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +#EXTRA_CCFLAGS += -u + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS= \ + user \ + driver + +endif # } PDIR + +APPDIR = . +LDDIR = ../ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a \ + driver/libdriver.a + +LINKFLAGS_eagle.app.v6 = \ + -L../lib \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -Wl,--gc-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -llwip \ + -lwpa \ + -lmain \ + -lwps \ + -lcrypto \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + +.PHONY: FORCE +FORCE: + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/Makefile new file mode 100644 index 0000000000..38fd29fcd6 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/Makefile @@ -0,0 +1,44 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libdriver.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/key.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/key.c new file mode 100644 index 0000000000..2a931607b3 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/driver/key.c @@ -0,0 +1,177 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "gpio.h" +#include "user_interface.h" + +#include "driver/key.h" + +LOCAL void key_intr_handler(void *arg); + +/****************************************************************************** + * FunctionName : key_init_single + * Description : init single key's gpio and register function + * Parameters : uint8 gpio_id - which gpio to use + * uint32 gpio_name - gpio mux name + * uint32 gpio_func - gpio function + * key_function long_press - long press function, needed to install + * key_function short_press - short press function, needed to install + * Returns : single_key_param - single key parameter, needed by key init +*******************************************************************************/ +struct single_key_param *ICACHE_FLASH_ATTR +key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press) +{ + struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param)); + + single_key->gpio_id = gpio_id; + single_key->gpio_name = gpio_name; + single_key->gpio_func = gpio_func; + single_key->long_press = long_press; + single_key->short_press = short_press; + + return single_key; +} + +/****************************************************************************** + * FunctionName : key_init + * Description : init keys + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +key_init(struct keys_param *keys) +{ + uint8 i; + + ETS_GPIO_INTR_ATTACH(key_intr_handler, keys); + + ETS_GPIO_INTR_DISABLE(); + + for (i = 0; i < keys->key_num; i++) { + keys->single_key[i]->key_level = 1; + + PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func); + + gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id)); + + gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE) + | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) + | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE)); + + //clear gpio14 status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id)); + + //enable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE); + } + + ETS_GPIO_INTR_ENABLE(); +} + +/****************************************************************************** + * FunctionName : key_5s_cb + * Description : long press 5s timer callback + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_5s_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_5s); + + // low, then restart + if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + if (single_key->long_press) { + single_key->long_press(); + } + } +} + +/****************************************************************************** + * FunctionName : key_50ms_cb + * Description : 50ms timer callback to check it's a real key push + * Parameters : single_key_param *single_key - single key parameter + * Returns : none +*******************************************************************************/ +LOCAL void ICACHE_FLASH_ATTR +key_50ms_cb(struct single_key_param *single_key) +{ + os_timer_disarm(&single_key->key_50ms); + + // high, then key is up + if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) { + os_timer_disarm(&single_key->key_5s); + single_key->key_level = 1; + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE); + + if (single_key->short_press) { + single_key->short_press(); + } + } else { + gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE); + } +} + +/****************************************************************************** + * FunctionName : key_intr_handler + * Description : key interrupt handler + * Parameters : key_param *keys - keys parameter, which inited by key_init_single + * Returns : none +*******************************************************************************/ +LOCAL void +key_intr_handler(void *arg) +{ + uint8 i; + uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + struct keys_param *keys = (struct keys_param *)arg; + + for (i = 0; i < keys->key_num; i++) { + if (gpio_status & BIT(keys->single_key[i]->gpio_id)) { + //disable interrupt + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE); + + //clear interrupt status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id)); + + if (keys->single_key[i]->key_level == 1) { + // 5s, restart & enter softap mode + os_timer_disarm(&keys->single_key[i]->key_5s); + os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0); + keys->single_key[i]->key_level = 0; + gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE); + } else { + // 50ms, check if this is a real key up + os_timer_disarm(&keys->single_key[i]->key_50ms); + os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]); + os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0); + } + } + } +} + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.bat b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.bat new file mode 100644 index 0000000000..d78cac517a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.bat @@ -0,0 +1,147 @@ +@echo off + +echo gen_misc.bat version 20150511 +echo . + +echo Please follow below steps(1-5) to generate specific bin(s): +echo STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none) +set input=default +set /p input=enter(0/1/2, default 2): + +if %input% equ 0 ( + set boot=old +) else ( +if %input% equ 1 ( + set boot=new +) else ( + set boot=none +) +) + +echo boot mode: %boot% +echo. + +echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin) +set input=default +set /p input=enter (0/1/2, default 0): + +if %input% equ 1 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=1 + echo generate bin: user1.bin + ) +) else ( +if %input% equ 2 ( + if %boot% equ none ( + set app=0 + echo choose no boot before + echo generate bin: eagle.flash.bin+eagle.irom0text.bin + ) else ( + set app=2 + echo generate bin: user2.bin + ) +) else ( + if %boot% neq none ( + set boot=none + echo ignore boot + ) + set app=0 + echo generate bin: eagle.flash.bin+eagle.irom0text.bin +)) + +echo. + +echo STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz) +set input=default +set /p input=enter (0/1/2/3, default 2): + +if %input% equ 0 ( + set spi_speed=20 +) else ( +if %input% equ 1 ( + set spi_speed=26.7 +) else ( +if %input% equ 3 ( + set spi_speed=80 +) else ( + set spi_speed=40 +))) + +echo spi speed: %spi_speed% MHz +echo. + +echo STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT) +set input=default +set /p input=enter (0/1/2/3, default 0): + +if %input% equ 1 ( + set spi_mode=QOUT +) else ( +if %input% equ 2 ( + set spi_mode=DIO +) else ( +if %input% equ 3 ( + set spi_mode=DOUT +) else ( + set spi_mode=QIO +))) + +echo spi mode: %spi_mode% +echo. + +echo STEP 5: choose flash size and map +echo 0= 512KB( 256KB+ 256KB) +echo 2=1024KB( 512KB+ 512KB) +echo 3=2048KB( 512KB+ 512KB) +echo 4=4096KB( 512KB+ 512KB) +echo 5=2048KB(1024KB+1024KB) +echo 6=4096KB(1024KB+1024KB) +set input=default +set /p input=enter (0/1/2/3/4/5/6, default 0): + +if %input% equ 2 ( + set spi_size_map=2 + echo spi size: 1024KB + echo spi ota map: 512KB + 512KB +) else ( + if %input% equ 3 ( + set spi_size_map=3 + echo spi size: 2048KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 4 ( + set spi_size_map=4 + echo spi size: 4096KB + echo spi ota map: 512KB + 512KB + ) else ( + if %input% equ 5 ( + set spi_size_map=5 + echo spi size: 2048KB + echo spi ota map: 1024KB + 1024KB + ) else ( + if %input% equ 6 ( + set spi_size_map=6 + echo spi size: 4096KB + echo spi ota map: 1024KB + 1024KB + ) else ( + set spi_size_map=0 + echo spi size: 512KB + echo spi ota map: 256KB + 256KB + ) + ) + ) + ) +) + +touch user/user_main.c + +echo. +echo start... +echo. + +make BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE=%spi_size_map% + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.sh b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.sh new file mode 100755 index 0000000000..0051fb91fb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/gen_misc.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +echo "gen_misc.sh version 20150511" +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: choose boot version(0=boot_v1.1, 1=boot_v1.2+, 2=none)" +echo "enter(0/1/2, default 2):" +read input + +if [ -z "$input" ]; then + boot=none +elif [ $input == 0 ]; then + boot=old +elif [ $input == 1 ]; then + boot=new +else + boot=none +fi + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board" +echo " 8=8192KB(1024KB+1024KB)" +echo " 9=16384KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6/7/8/9, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 7 ]; then + spi_size_map=7 + echo"not support ,just for compatible with nodeMCU board" + exit +elif [ $input == 8 ]; then + spi_size_map=8 + echo "spi size: 8192KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 9 ]; then + spi_size_map=9 + echo "spi size: 16384KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +touch user/user_main.c + +echo "" +echo "start..." +echo "" + +make COMPILE=gcc BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/driver/key.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/driver/key.h new file mode 100644 index 0000000000..e0aa771784 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/driver/key.h @@ -0,0 +1,51 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#include "gpio.h" + +typedef void (* key_function)(void); + +struct single_key_param { + uint8 key_level; + uint8 gpio_id; + uint8 gpio_func; + uint32 gpio_name; + os_timer_t key_5s; + os_timer_t key_50ms; + key_function short_press; + key_function long_press; +}; + +struct keys_param { + uint8 key_num; + struct single_key_param **single_key; +}; + +struct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press); +void key_init(struct keys_param *key); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/user_config.h b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/user_config.h new file mode 100644 index 0000000000..3edc1ee019 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/include/user_config.h @@ -0,0 +1,29 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/Makefile b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/Makefile new file mode 100644 index 0000000000..639fe9b10c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/Makefile @@ -0,0 +1,45 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ../../include/ets +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/user_main.c b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/user_main.c new file mode 100644 index 0000000000..6496302cf0 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/examples/wps/user/user_main.c @@ -0,0 +1,131 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "osapi.h" +#include "user_interface.h" + +#include "driver/key.h" + +#define WPS_KEY_NUM 1 + +#define WPS_KEY_IO_MUX PERIPHS_IO_MUX_MTCK_U +#define WPS_KEY_IO_NUM 13 +#define WPS_KEY_IO_FUNC FUNC_GPIO13 + +LOCAL struct keys_param keys; +LOCAL struct single_key_param *single_key; + +LOCAL void ICACHE_FLASH_ATTR +user_wps_status_cb(int status) +{ + switch (status) { + case WPS_CB_ST_SUCCESS: + wifi_wps_disable(); + wifi_station_connect(); + break; + case WPS_CB_ST_FAILED: + case WPS_CB_ST_TIMEOUT: + wifi_wps_start(); + break; + } +} + +LOCAL void ICACHE_FLASH_ATTR +user_wps_key_short_press(void) +{ + wifi_wps_disable(); + wifi_wps_enable(WPS_TYPE_PBC); + wifi_set_wps_cb(user_wps_status_cb); + wifi_wps_start(); +} + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32 ICACHE_FLASH_ATTR +user_rf_cal_sector_set(void) +{ + enum flash_size_map size_map = system_get_flash_size_map(); + uint32 rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void ICACHE_FLASH_ATTR +user_rf_pre_init(void) +{ +} + +void ICACHE_FLASH_ATTR +user_init(void) +{ + single_key = key_init_single(WPS_KEY_IO_NUM, WPS_KEY_IO_MUX, WPS_KEY_IO_FUNC, + NULL, user_wps_key_short_press); + + keys.key_num = WPS_KEY_NUM; + keys.single_key = &single_key; + + key_init(&keys); + + wifi_set_opmode(STATION_MODE); +} diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/airkiss.h b/Sming/third-party/ESP8266_NONOS_SDK/include/airkiss.h new file mode 100644 index 0000000000..4ac0a12d8f --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/airkiss.h @@ -0,0 +1,122 @@ +/* + * airkiss.h + * + * Created on: 2015-1-26 + * Author: peterfan + */ + +#ifndef AIRKISS_H_ +#define AIRKISS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void* (*airkiss_memset_fn) (void* ptr, int value, unsigned int num); +typedef void* (*airkiss_memcpy_fn) (void* dst, const void* src, unsigned int num); +typedef int (*airkiss_memcmp_fn) (const void* ptr1, const void* ptr2, unsigned int num); +typedef int (*airkiss_printf_fn) (const char* format, ...); + + + +typedef struct +{ + airkiss_memset_fn memset; + airkiss_memcpy_fn memcpy; + airkiss_memcmp_fn memcmp; + airkiss_printf_fn printf; + +} airkiss_config_t; + +/** + * @brief Get airkiss lib version. + * + * @attention The lenth of version is unknown + * + * @param null. + * + * @return const char* + */ + +const char* airkiss_version(void); + + +typedef enum +{ + /* the length of the data buffer is lack*/ + AIRKISS_LAN_ERR_OVERFLOW = -5, + + /* Do not support the type of instruction */ + AIRKISS_LAN_ERR_CMD = -4, + + /* Error reading data package */ + AIRKISS_LAN_ERR_PAKE = -3, + + /* Error function passing parameters */ + AIRKISS_LAN_ERR_PARA = -2, + + /* Packet data error */ + AIRKISS_LAN_ERR_PKG = -1, + + /* Message format is correct */ + AIRKISS_LAN_CONTINUE = 0, + + /* Find equipment request packet is received */ + AIRKISS_LAN_SSDP_REQ = 1, + + /* Packet packaging complete */ + AIRKISS_LAN_PAKE_READY = 2 + + +} airkiss_lan_ret_t; + + +typedef enum +{ + AIRKISS_LAN_SSDP_REQ_CMD = 0x1, + AIRKISS_LAN_SSDP_RESP_CMD = 0x1001, + AIRKISS_LAN_SSDP_NOTIFY_CMD = 0x1002 +} airkiss_lan_cmdid_t; + +/** + * @brief Receive UDP packet and input this API for analyzing. + * + * @attention null. + * + * @param const void* body : The start of the UDP message body data pointer. + * @param unsigned short length : the effective length of data. + * @param const airkiss_config_t* config : input struct airkiss_config_t + * + * @return >=0 : succeed (reference airkiss_lan_ret_t) + * @return <0 : error code (reference airkiss_lan_ret_t) + */ + +int airkiss_lan_recv(const void* body, unsigned short length, const airkiss_config_t* config); + + +/** + * @brief Packaging the UDP packet to send. + * + * @attention null. + * + * @param airkiss_lan_cmdid_t ak_lan_cmdid : The packet type. + * @param void* appid : Vendor's Wechat public number id. + * @param void* deviceid : device model id. + * @param void* _datain : the data to be sent. + * @param unsigned short inlength : the lenth of data to be sent. + * @param void* _dataout : Data buffer addr. + * @param unsigned short* outlength : the size of data buffer. + * @param const airkiss_config_t* config : input struct airkiss_config_t + * + * @return >=0 : succeed (reference airkiss_lan_ret_t) + * @return <0 : error code (reference airkiss_lan_ret_t) + */ + +int airkiss_lan_pack(airkiss_lan_cmdid_t ak_lan_cmdid, void* appid, void* deviceid, void* _datain, unsigned short inlength, void* _dataout, unsigned short* outlength, const airkiss_config_t* config); + +#ifdef __cplusplus +} +#endif + +#endif /* AIRKISS_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/at_custom.h b/Sming/third-party/ESP8266_NONOS_SDK/include/at_custom.h new file mode 100644 index 0000000000..fcf3de61d7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/at_custom.h @@ -0,0 +1,172 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef CUSTOM_AT_H_ +#define CUSTOM_AT_H_ + +#include "c_types.h" + +typedef struct +{ + char *at_cmdName; + int8_t at_cmdLen; + void (*at_testCmd)(uint8_t id); + void (*at_queryCmd)(uint8_t id); + void (*at_setupCmd)(uint8_t id, char *pPara); + void (*at_exeCmd)(uint8_t id); +}at_funcationType; + +typedef void (*at_custom_uart_rx_intr)(uint8* data,int32 len); + +typedef void (*at_custom_response_func_type)(const char *str); + +typedef void (*at_fake_uart_tx_func_type)(const uint8*data,uint32 length); + +extern uint8 at_customLinkMax; + +/** + * @brief Response "OK" to uart. + * @param None + * @retval None + */ +void at_response_ok(void); +/** + * @brief Response "ERROR" to uart. + * @param None + * @retval None + */ +void at_response_error(void); +/** + * @brief Response string. + * It is equivalent to at_port_print,if not call at_register_response_func or call at_register_response_func(NULL); + * It will run custom response function,if call at_register_response_func and parameter is not NULL. + * @param string + * @retval None + */ +void at_response(const char *str); +/** + * @brief register custom response function. + * @param response_func: the function that will run when call at_response + * @retval None + */ +void at_register_response_func(at_custom_response_func_type response_func); +/** + * @brief Task of process command or txdata. + * @param custom_at_cmd_array: the array of at cmd that custom defined + * cmd_num : the num of at cmd that custom defined + * @retval None + */ +void at_cmd_array_regist(at_funcationType *custom_at_cmd_array,uint32 cmd_num); +/** + * @brief get digit form at cmd line.the maybe alter pSrc + * @param p_src: at cmd line string + * result:the buffer to be placed result + * err : err num + * @retval TRUE: + * FALSE: + */ +bool at_get_next_int_dec(char **p_src,int*result,int* err); +/** + * @brief get string form at cmd line.the maybe alter pSrc + * @param p_dest: the buffer to be placed result + * p_src: at cmd line string + * max_len :max len of string excepted to get + * @retval None + */ +int32 at_data_str_copy(char *p_dest, char **p_src, int32 max_len); + +/** + * @brief initialize at module + * @param None + * @retval None + */ +void at_init(void); +/** + * @brief print string to at port + * @param string + * @retval None + */ +void at_port_print(const char *str); +/** + * @brief print custom information when AT+GMR + * @param string + * @retval None + */ +void at_set_custom_info(char* info); +/** + * @brief if current at command is processing,you can call at_enter_special_state, + * then if other comamnd coming,it will return busy. + * @param None + * @retval None + */ +void at_enter_special_state(void); +/** + * @brief + * @param None + * @retval None + */ +void at_leave_special_state(void); +/** + * @brief get at version + * @param None + * @retval at version + * bit24~31: at main version + * bit23~16: at sub version + * bit15~8 : at test version + * bit7~0 : customized version + */ +uint32 at_get_version(void); + +/** + * @brief register custom uart rx interrupt function + * @param rx_func: custom uart rx interrupt function. + * If rx_func is non-void,when rx interrupt comming,it will call rx_func(data,len), + * data is the buffer of data,len is the length of data.Otherwise,it will run AT rx function. + * @retval None + */ +void at_register_uart_rx_intr(at_custom_uart_rx_intr rx_func); +/** + * @brief notify at module that has receive data + * @param data: data buffer. + * @param length: data length + * @retval data len,if ok len == length + */ +uint32 at_fake_uart_rx(uint8* data,uint32 length); + +/** + * @brief enable fake uart,and register fake uart tx + * @param enable: enable fake uart. + * @param at_fake_uart_tx_func: + * @retval data len,if ok len == length + */ +bool at_fake_uart_enable(bool enable,at_fake_uart_tx_func_type at_fake_uart_tx_func); + +/** + * @brief set at escape character + * @param ch: escape character. + * @retval TRUE,if set ok,otherwize FALSE. + */ +bool at_set_escape_character(uint8 ch); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h b/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h new file mode 100644 index 0000000000..50f4445890 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/c_types.h @@ -0,0 +1,114 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _C_TYPES_H_ +#define _C_TYPES_H_ + +typedef unsigned char uint8_t; +typedef signed char sint8_t; +typedef signed char int8_t; +typedef unsigned short uint16_t; +typedef signed short sint16_t; +typedef signed short int16_t; +typedef unsigned int uint32_t; +typedef signed long sint32_t; +typedef signed int int32_t; +typedef signed long long sint64_t; +typedef unsigned long long uint64_t; +typedef unsigned long long u_int64_t; +typedef float real32_t; +typedef double real64_t; + +typedef unsigned char uint8; +typedef unsigned char u8; +typedef signed char sint8; +typedef signed char int8; +typedef signed char s8; +typedef unsigned short uint16; +typedef unsigned short u16; +typedef signed short sint16; +typedef signed short s16; +typedef unsigned int uint32; +typedef unsigned int u_int; +typedef unsigned int u32; +typedef signed int sint32; +typedef signed int s32; +typedef int int32; +typedef signed long long sint64; +typedef unsigned long long uint64; +typedef unsigned long long u64; +typedef float real32; +typedef double real64; + +#define __le16 u16 + +typedef unsigned int size_t; + +#define __packed __attribute__((packed)) + +#define LOCAL static + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/* probably should not put STATUS here */ +typedef enum { + OK = 0, + FAIL, + PENDING, + BUSY, + CANCEL, +} STATUS; + +#define BIT(nr) (1UL << (nr)) + +#define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b)) +#define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b)) + +#define DMEM_ATTR __attribute__((section(".bss"))) +#define SHMEM_ATTR + +#ifdef ICACHE_FLASH +#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text"))) +#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) +#else +#define ICACHE_FLASH_ATTR +#define ICACHE_RODATA_ATTR +#endif /* ICACHE_FLASH */ + +#define STORE_ATTR __attribute__((aligned(4))) + +#ifndef __cplusplus +typedef unsigned char bool; +#define BOOL bool +#define true (1) +#define false (0) +#define TRUE true +#define FALSE false + + +#endif /* !__cplusplus */ + +#endif /* _C_TYPES_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h b/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h new file mode 100644 index 0000000000..d7015dc792 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/eagle_soc.h @@ -0,0 +1,279 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _EAGLE_SOC_H_ +#define _EAGLE_SOC_H_ + +//Register Bits{{ +#define BIT31 0x80000000 +#define BIT30 0x40000000 +#define BIT29 0x20000000 +#define BIT28 0x10000000 +#define BIT27 0x08000000 +#define BIT26 0x04000000 +#define BIT25 0x02000000 +#define BIT24 0x01000000 +#define BIT23 0x00800000 +#define BIT22 0x00400000 +#define BIT21 0x00200000 +#define BIT20 0x00100000 +#define BIT19 0x00080000 +#define BIT18 0x00040000 +#define BIT17 0x00020000 +#define BIT16 0x00010000 +#define BIT15 0x00008000 +#define BIT14 0x00004000 +#define BIT13 0x00002000 +#define BIT12 0x00001000 +#define BIT11 0x00000800 +#define BIT10 0x00000400 +#define BIT9 0x00000200 +#define BIT8 0x00000100 +#define BIT7 0x00000080 +#define BIT6 0x00000040 +#define BIT5 0x00000020 +#define BIT4 0x00000010 +#define BIT3 0x00000008 +#define BIT2 0x00000004 +#define BIT1 0x00000002 +#define BIT0 0x00000001 +//}} + +//Registers Operation {{ +#define ETS_UNCACHED_ADDR(addr) (addr) +#define ETS_CACHED_ADDR(addr) (addr) + + +#define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) +#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val) +#define CLEAR_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask)))) +#define SET_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))) +#define GET_PERI_REG_BITS(reg, hipos,lowpos) ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1)) +#define SET_PERI_REG_BITS(reg,bit_map,value,shift) (WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|((value)<<(shift)) )) +//}} + +//Periheral Clock {{ +#define APB_CLK_FREQ 80*1000000 //unit: Hz +#define UART_CLK_FREQ APB_CLK_FREQ +#define TIMER_CLK_FREQ (APB_CLK_FREQ>>8) //divided by 256 +//}} + +//Peripheral device base address define{{ +#define PERIPHS_DPORT_BASEADDR 0x3ff00000 +#define PERIPHS_GPIO_BASEADDR 0x60000300 +#define PERIPHS_TIMER_BASEDDR 0x60000600 +#define PERIPHS_RTC_BASEADDR 0x60000700 +#define PERIPHS_IO_MUX 0x60000800 +//}} + +//Interrupt remap control registers define{{ +#define EDGE_INT_ENABLE_REG (PERIPHS_DPORT_BASEADDR+0x04) +#define TM1_EDGE_INT_ENABLE() SET_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1) +#define TM1_EDGE_INT_DISABLE() CLEAR_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1) +//}} + +//GPIO reg {{ +#define GPIO_REG_READ(reg) READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg) +#define GPIO_REG_WRITE(reg, val) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val) +#define GPIO_OUT_ADDRESS 0x00 +#define GPIO_OUT_W1TS_ADDRESS 0x04 +#define GPIO_OUT_W1TC_ADDRESS 0x08 + +#define GPIO_ENABLE_ADDRESS 0x0c +#define GPIO_ENABLE_W1TS_ADDRESS 0x10 +#define GPIO_ENABLE_W1TC_ADDRESS 0x14 +#define GPIO_OUT_W1TC_DATA_MASK 0x0000ffff + +#define GPIO_IN_ADDRESS 0x18 + +#define GPIO_STATUS_ADDRESS 0x1c +#define GPIO_STATUS_W1TS_ADDRESS 0x20 +#define GPIO_STATUS_W1TC_ADDRESS 0x24 +#define GPIO_STATUS_INTERRUPT_MASK 0x0000ffff + +#define GPIO_RTC_CALIB_SYNC PERIPHS_GPIO_BASEADDR+0x6c +#define RTC_CALIB_START BIT31 //first write to zero, then to one to start +#define RTC_PERIOD_NUM_MASK 0x3ff //max 8ms +#define GPIO_RTC_CALIB_VALUE PERIPHS_GPIO_BASEADDR+0x70 +#define RTC_CALIB_RDY_S 31 //after measure, flag to one, when start from zero to one, turn to zero +#define RTC_CALIB_VALUE_MASK 0xfffff + +#define GPIO_PIN0_ADDRESS 0x28 + +#define GPIO_ID_PIN0 0 +#define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n)) +#define GPIO_LAST_REGISTER_ID GPIO_ID_PIN(15) +#define GPIO_ID_NONE 0xffffffff + +#define GPIO_PIN_COUNT 16 + +#define GPIO_PIN_CONFIG_MSB 12 +#define GPIO_PIN_CONFIG_LSB 11 +#define GPIO_PIN_CONFIG_MASK 0x00001800 +#define GPIO_PIN_CONFIG_GET(x) (((x) & GPIO_PIN_CONFIG_MASK) >> GPIO_PIN_CONFIG_LSB) +#define GPIO_PIN_CONFIG_SET(x) (((x) << GPIO_PIN_CONFIG_LSB) & GPIO_PIN_CONFIG_MASK) + +#define GPIO_WAKEUP_ENABLE 1 +#define GPIO_WAKEUP_DISABLE (~GPIO_WAKEUP_ENABLE) +#define GPIO_PIN_WAKEUP_ENABLE_MSB 10 +#define GPIO_PIN_WAKEUP_ENABLE_LSB 10 +#define GPIO_PIN_WAKEUP_ENABLE_MASK 0x00000400 +#define GPIO_PIN_WAKEUP_ENABLE_GET(x) (((x) & GPIO_PIN_WAKEUP_ENABLE_MASK) >> GPIO_PIN_WAKEUP_ENABLE_LSB) +#define GPIO_PIN_WAKEUP_ENABLE_SET(x) (((x) << GPIO_PIN_WAKEUP_ENABLE_LSB) & GPIO_PIN_WAKEUP_ENABLE_MASK) + +#define GPIO_PIN_INT_TYPE_MASK 0x380 +#define GPIO_PIN_INT_TYPE_MSB 9 +#define GPIO_PIN_INT_TYPE_LSB 7 +#define GPIO_PIN_INT_TYPE_GET(x) (((x) & GPIO_PIN_INT_TYPE_MASK) >> GPIO_PIN_INT_TYPE_LSB) +#define GPIO_PIN_INT_TYPE_SET(x) (((x) << GPIO_PIN_INT_TYPE_LSB) & GPIO_PIN_INT_TYPE_MASK) + +#define GPIO_PAD_DRIVER_ENABLE 1 +#define GPIO_PAD_DRIVER_DISABLE (~GPIO_PAD_DRIVER_ENABLE) +#define GPIO_PIN_PAD_DRIVER_MSB 2 +#define GPIO_PIN_PAD_DRIVER_LSB 2 +#define GPIO_PIN_PAD_DRIVER_MASK 0x00000004 +#define GPIO_PIN_PAD_DRIVER_GET(x) (((x) & GPIO_PIN_PAD_DRIVER_MASK) >> GPIO_PIN_PAD_DRIVER_LSB) +#define GPIO_PIN_PAD_DRIVER_SET(x) (((x) << GPIO_PIN_PAD_DRIVER_LSB) & GPIO_PIN_PAD_DRIVER_MASK) + +#define GPIO_AS_PIN_SOURCE 0 +#define SIGMA_AS_PIN_SOURCE (~GPIO_AS_PIN_SOURCE) +#define GPIO_PIN_SOURCE_MSB 0 +#define GPIO_PIN_SOURCE_LSB 0 +#define GPIO_PIN_SOURCE_MASK 0x00000001 +#define GPIO_PIN_SOURCE_GET(x) (((x) & GPIO_PIN_SOURCE_MASK) >> GPIO_PIN_SOURCE_LSB) +#define GPIO_PIN_SOURCE_SET(x) (((x) << GPIO_PIN_SOURCE_LSB) & GPIO_PIN_SOURCE_MASK) +// }} + +// TIMER reg {{ +#define RTC_REG_READ(addr) READ_PERI_REG(PERIPHS_TIMER_BASEDDR + addr) +#define RTC_REG_WRITE(addr, val) WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + addr, val) +#define RTC_CLR_REG_MASK(reg, mask) CLEAR_PERI_REG_MASK(PERIPHS_TIMER_BASEDDR +reg, mask) +/* Returns the current time according to the timer timer. */ +#define NOW() RTC_REG_READ(FRC2_COUNT_ADDRESS) + +//load initial_value to timer1 +#define FRC1_LOAD_ADDRESS 0x00 + +//timer1's counter value(count from initial_value to 0) +#define FRC1_COUNT_ADDRESS 0x04 + +#define FRC1_CTRL_ADDRESS 0x08 + +//clear timer1's interrupt when write this address +#define FRC1_INT_ADDRESS 0x0c +#define FRC1_INT_CLR_MASK 0x00000001 + +//timer2's counter value(count from initial_value to 0) +#define FRC2_COUNT_ADDRESS 0x24 +// }} + +//RTC reg {{ +#define REG_RTC_BASE PERIPHS_RTC_BASEADDR + +#define RTC_STORE0 (REG_RTC_BASE + 0x030) +#define RTC_STORE1 (REG_RTC_BASE + 0x034) +#define RTC_STORE2 (REG_RTC_BASE + 0x038) +#define RTC_STORE3 (REG_RTC_BASE + 0x03C) + +#define RTC_GPIO_OUT (REG_RTC_BASE + 0x068) +#define RTC_GPIO_ENABLE (REG_RTC_BASE + 0x074) +#define RTC_GPIO_IN_DATA (REG_RTC_BASE + 0x08C) +#define RTC_GPIO_CONF (REG_RTC_BASE + 0x090) +#define PAD_XPD_DCDC_CONF (REG_RTC_BASE + 0x0A0) +//}} + +//PIN Mux reg {{ +#define PERIPHS_IO_MUX_FUNC 0x13 +#define PERIPHS_IO_MUX_FUNC_S 4 +#define PERIPHS_IO_MUX_PULLUP BIT7 +#define PERIPHS_IO_MUX_PULLUP2 BIT6 +#define PERIPHS_IO_MUX_SLEEP_PULLUP BIT3 +#define PERIPHS_IO_MUX_SLEEP_PULLUP2 BIT2 +#define PERIPHS_IO_MUX_SLEEP_OE BIT1 +#define PERIPHS_IO_MUX_OE BIT0 + +#define PERIPHS_IO_MUX_CONF_U (PERIPHS_IO_MUX + 0x00) +#define SPI0_CLK_EQU_SYS_CLK BIT8 +#define SPI1_CLK_EQU_SYS_CLK BIT9 +#define PERIPHS_IO_MUX_MTDI_U (PERIPHS_IO_MUX + 0x04) +#define FUNC_GPIO12 3 +#define PERIPHS_IO_MUX_MTCK_U (PERIPHS_IO_MUX + 0x08) +#define FUNC_GPIO13 3 +#define PERIPHS_IO_MUX_MTMS_U (PERIPHS_IO_MUX + 0x0C) +#define FUNC_GPIO14 3 +#define PERIPHS_IO_MUX_MTDO_U (PERIPHS_IO_MUX + 0x10) +#define FUNC_GPIO15 3 +#define FUNC_U0RTS 4 +#define PERIPHS_IO_MUX_U0RXD_U (PERIPHS_IO_MUX + 0x14) +#define FUNC_GPIO3 3 +#define PERIPHS_IO_MUX_U0TXD_U (PERIPHS_IO_MUX + 0x18) +#define FUNC_U0TXD 0 +#define FUNC_GPIO1 3 +#define PERIPHS_IO_MUX_SD_CLK_U (PERIPHS_IO_MUX + 0x1c) +#define FUNC_SDCLK 0 +#define FUNC_SPICLK 1 +#define PERIPHS_IO_MUX_SD_DATA0_U (PERIPHS_IO_MUX + 0x20) +#define FUNC_SDDATA0 0 +#define FUNC_SPIQ 1 +#define FUNC_U1TXD 4 +#define PERIPHS_IO_MUX_SD_DATA1_U (PERIPHS_IO_MUX + 0x24) +#define FUNC_SDDATA1 0 +#define FUNC_SPID 1 +#define FUNC_U1RXD 4 +#define FUNC_SDDATA1_U1RXD 7 +#define PERIPHS_IO_MUX_SD_DATA2_U (PERIPHS_IO_MUX + 0x28) +#define FUNC_SDDATA2 0 +#define FUNC_SPIHD 1 +#define FUNC_GPIO9 3 +#define PERIPHS_IO_MUX_SD_DATA3_U (PERIPHS_IO_MUX + 0x2c) +#define FUNC_SDDATA3 0 +#define FUNC_SPIWP 1 +#define FUNC_GPIO10 3 +#define PERIPHS_IO_MUX_SD_CMD_U (PERIPHS_IO_MUX + 0x30) +#define FUNC_SDCMD 0 +#define FUNC_SPICS0 1 +#define PERIPHS_IO_MUX_GPIO0_U (PERIPHS_IO_MUX + 0x34) +#define FUNC_GPIO0 0 +#define PERIPHS_IO_MUX_GPIO2_U (PERIPHS_IO_MUX + 0x38) +#define FUNC_GPIO2 0 +#define FUNC_U1TXD_BK 2 +#define FUNC_U0TXD_BK 4 +#define PERIPHS_IO_MUX_GPIO4_U (PERIPHS_IO_MUX + 0x3C) +#define FUNC_GPIO4 0 +#define PERIPHS_IO_MUX_GPIO5_U (PERIPHS_IO_MUX + 0x40) +#define FUNC_GPIO5 0 + +#define PIN_PULLUP_DIS(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) +#define PIN_PULLUP_EN(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) + +#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ + WRITE_PERI_REG(PIN_NAME, \ + (READ_PERI_REG(PIN_NAME) \ + & (~(PERIPHS_IO_MUX_FUNC< + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ESPCONN_H__ +#define __ESPCONN_H__ + +typedef sint8 err_t; + +typedef void *espconn_handle; +typedef void (* espconn_connect_callback)(void *arg); +typedef void (* espconn_reconnect_callback)(void *arg, sint8 err); + +/* Definitions for error constants. */ + +#define ESPCONN_OK 0 /* No error, everything OK. */ +#define ESPCONN_MEM -1 /* Out of memory error. */ +#define ESPCONN_TIMEOUT -3 /* Timeout. */ +#define ESPCONN_RTE -4 /* Routing problem. */ +#define ESPCONN_INPROGRESS -5 /* Operation in progress */ +#define ESPCONN_MAXNUM -7 /* Total number exceeds the set maximum*/ + +#define ESPCONN_ABRT -8 /* Connection aborted. */ +#define ESPCONN_RST -9 /* Connection reset. */ +#define ESPCONN_CLSD -10 /* Connection closed. */ +#define ESPCONN_CONN -11 /* Not connected. */ + +#define ESPCONN_ARG -12 /* Illegal argument. */ +#define ESPCONN_IF -14 /* UDP send error */ +#define ESPCONN_ISCONN -15 /* Already connected. */ + +#define ESPCONN_HANDSHAKE -28 /* ssl handshake failed */ +#define ESPCONN_SSL_INVALID_DATA -61 /* ssl application invalid */ + +/** Protocol family and type of the espconn */ +enum espconn_type { + ESPCONN_INVALID = 0, + /* ESPCONN_TCP Group */ + ESPCONN_TCP = 0x10, + /* ESPCONN_UDP Group */ + ESPCONN_UDP = 0x20, +}; + +/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */ +enum espconn_state { + ESPCONN_NONE, + ESPCONN_WAIT, + ESPCONN_LISTEN, + ESPCONN_CONNECT, + ESPCONN_WRITE, + ESPCONN_READ, + ESPCONN_CLOSE +}; + +typedef struct _esp_tcp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; + espconn_connect_callback connect_callback; + espconn_reconnect_callback reconnect_callback; + espconn_connect_callback disconnect_callback; + espconn_connect_callback write_finish_fn; +} esp_tcp; + +typedef struct _esp_udp { + int remote_port; + int local_port; + uint8 local_ip[4]; + uint8 remote_ip[4]; +} esp_udp; + +typedef struct _remot_info{ + enum espconn_state state; + int remote_port; + uint8 remote_ip[4]; +}remot_info; + +/** A callback prototype to inform about events for a espconn */ +typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len); +typedef void (* espconn_sent_callback)(void *arg); + +/** A espconn descriptor */ +struct espconn { + /** type of the espconn (TCP, UDP) */ + enum espconn_type type; + /** current state of the espconn */ + enum espconn_state state; + union { + esp_tcp *tcp; + esp_udp *udp; + } proto; + /** A callback function that is informed about events for this espconn */ + espconn_recv_callback recv_callback; + espconn_sent_callback sent_callback; + uint8 link_cnt; + void *reverse; +}; + +enum espconn_option{ + ESPCONN_START = 0x00, + ESPCONN_REUSEADDR = 0x01, + ESPCONN_NODELAY = 0x02, + ESPCONN_COPY = 0x04, + ESPCONN_KEEPALIVE = 0x08, + ESPCONN_MANUALRECV = 0x10, + ESPCONN_END +}; + +enum espconn_level{ + ESPCONN_KEEPIDLE, + ESPCONN_KEEPINTVL, + ESPCONN_KEEPCNT +}; + +enum { + ESPCONN_IDLE = 0, + ESPCONN_CLIENT, + ESPCONN_SERVER, + ESPCONN_BOTH, + ESPCONN_MAX +}; + +struct espconn_packet{ + uint16 sent_length; /* sent length successful*/ + uint16 snd_buf_size; /* Available buffer size for sending */ + uint16 snd_queuelen; /* Available buffer space for sending */ + uint16 total_queuelen; /* total Available buffer space for sending */ + uint32 packseqno; /* seqno to be sent */ + uint32 packseq_nxt; /* seqno expected */ + uint32 packnum; +}; + +struct mdns_info { + char *host_name; + char *server_name; + uint16 server_port; + unsigned long ipAddr; + char *txt_data[10]; +}; +/****************************************************************************** + * FunctionName : espconn_connect + * Description : The function given as the connect + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +sint8 espconn_connect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_disconnect + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +sint8 espconn_disconnect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_delete + * Description : disconnect with host + * Parameters : espconn -- the espconn used to disconnect the connection + * Returns : none +*******************************************************************************/ + +sint8 espconn_delete(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : none +*******************************************************************************/ + +sint8 espconn_accept(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_create + * Description : sent data for client or server + * Parameters : espconn -- espconn to the data transmission + * Returns : result +*******************************************************************************/ + +sint8 espconn_create(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con + * Description : get the number of simulatenously active TCP connections + * Parameters : none + * Returns : none +*******************************************************************************/ + +uint8 espconn_tcp_get_max_con(void); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con + * Description : set the number of simulatenously active TCP connections + * Parameters : num -- total number + * Returns : none +*******************************************************************************/ + +sint8 espconn_tcp_set_max_con(uint8 num); + +/****************************************************************************** + * FunctionName : espconn_tcp_get_max_con_allow + * Description : get the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to get the count + * Returns : result +*******************************************************************************/ + +sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_tcp_set_max_con_allow + * Description : set the count of simulatenously active connections on the server + * Parameters : espconn -- espconn to set the count + * num -- support the connection number + * Returns : result +*******************************************************************************/ + +sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num); + +/****************************************************************************** + * FunctionName : espconn_regist_time + * Description : used to specify the time that should be called when don't recv data + * Parameters : espconn -- the espconn used to the connection + * interval -- the timer when don't recv data + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag); + +/****************************************************************************** + * FunctionName : espconn_get_connection_info + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags); + +/****************************************************************************** + * FunctionName : espconn_get_packet_info + * Description : get the packet info with host + * Parameters : espconn -- the espconn used to disconnect the connection + * infoarg -- the packet info + * Returns : the errur code +*******************************************************************************/ + +sint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : struct espconn *espconn -- espconn to set the sent callback + * espconn_sent_callback sent_cb -- sent callback function to + * call for this espconn when data is successfully sent + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_sentcb + * Description : Used to specify the function that should be called when data + * has been successfully delivered to the remote host. + * Parameters : espconn -- espconn to set the sent callback + * sent_cb -- sent callback function to call for this espconn + * when data is successfully sent + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn); + +/****************************************************************************** + * FunctionName : espconn_send + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_sendto + * Description : send data for UDP + * Parameters : espconn -- espconn to set for UDP + * psent -- data to send + * length -- length of data to send + * Returns : error +*******************************************************************************/ + +sint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_regist_connectcb + * Description : used to specify the function that should be called when + * connects to host. + * Parameters : espconn -- espconn to set the connect callback + * connect_cb -- connected callback function to call when connected + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_recvcb + * Description : used to specify the function that should be called when recv + * data from host. + * Parameters : espconn -- espconn to set the recv callback + * recv_cb -- recv callback function to call when recv data + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_reconcb + * Description : used to specify the function that should be called when connection + * because of err disconnect. + * Parameters : espconn -- espconn to set the err callback + * recon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb); + +/****************************************************************************** + * FunctionName : espconn_regist_disconcb + * Description : used to specify the function that should be called when disconnect + * Parameters : espconn -- espconn to set the err callback + * discon_cb -- err callback function to call when err + * Returns : none +*******************************************************************************/ + +sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb); + +/****************************************************************************** + * FunctionName : espconn_port + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ + +uint32 espconn_port(void); + +/****************************************************************************** + * FunctionName : espconn_set_opt + * Description : access port value for client so that we don't end up bouncing + * all connections at the same time . + * Parameters : none + * Returns : access port value +*******************************************************************************/ + +sint8 espconn_set_opt(struct espconn *espconn, uint8 opt); + +/****************************************************************************** + * FunctionName : espconn_clear_opt + * Description : clear the option for connections so that we don't end up bouncing + * all connections at the same time . + * Parameters : espconn -- the espconn used to set the connection + * opt -- the option for clear + * Returns : the result +*******************************************************************************/ + +sint8 espconn_clear_opt(struct espconn *espconn, uint8 opt); + +/****************************************************************************** + * FunctionName : espconn_set_keepalive + * Description : access level value for connection so that we set the value for + * keep alive + * Parameters : espconn -- the espconn used to set the connection + * level -- the connection's level + * value -- the value of time(s) + * Returns : access port value +*******************************************************************************/ + +sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg); + +/****************************************************************************** + * FunctionName : espconn_get_keepalive + * Description : access level value for connection so that we get the value for + * keep alive + * Parameters : espconn -- the espconn used to get the connection + * level -- the connection's level + * Returns : access keep alive value +*******************************************************************************/ + +sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg); + +/****************************************************************************** + * TypedefName : dns_found_callback + * Description : Callback which is invoked when a hostname is found. + * Parameters : name -- pointer to the name that was looked up. + * ipaddr -- pointer to an ip_addr_t containing the IP address of + * the hostname, or NULL if the name could not be found (or on any + * other error). + * callback_arg -- a user-specified callback argument passed to + * dns_gethostbyname +*******************************************************************************/ + +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); + +/****************************************************************************** + * FunctionName : espconn_gethostbyname + * Description : Resolve a hostname (string) into an IP address. + * Parameters : pespconn -- espconn to resolve a hostname + * hostname -- the hostname that is to be queried + * addr -- pointer to a ip_addr_t where to store the address if + * it is already cached in the dns_table (only valid if ESPCONN_OK + * is returned!) + * found -- a callback function to be called on success, failure + * or timeout (only if ERR_INPROGRESS is returned!) + * Returns : err_t return code + * - ESPCONN_OK if hostname is a valid IP address string or the host + * name is already in the local names table. + * - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server + * for resolution if no errors are present. + * - ESPCONN_ARG: dns client not initialized or invalid hostname +*******************************************************************************/ + +err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found); + +/****************************************************************************** + * FunctionName : espconn_abort + * Description : Forcely abort with host + * Parameters : espconn -- the espconn used to connect with the host + * Returns : result +*******************************************************************************/ + +sint8 espconn_abort(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_encry_connect + * Description : The function given as connection + * Parameters : espconn -- the espconn used to connect with the host + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_connect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_encry_disconnect + * Description : The function given as the disconnection + * Parameters : espconn -- the espconn used to disconnect with the host + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_disconnect(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_secure_send + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_send(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_encry_sent + * Description : sent data for client or server + * Parameters : espconn -- espconn to set for client or server + * psent -- data to send + * length -- length of data to send + * Returns : none +*******************************************************************************/ + +sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_secure_set_size + * Description : set the buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * size -- buffer size + * Returns : true or false +*******************************************************************************/ + +bool espconn_secure_set_size(uint8 level, uint16 size); + +/****************************************************************************** + * FunctionName : espconn_secure_get_size + * Description : get buffer size for client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : buffer size for client or server +*******************************************************************************/ + +sint16 espconn_secure_get_size(uint8 level); + +/****************************************************************************** + * FunctionName : espconn_secure_ca_enable + * Description : enable the certificate authenticate and set the flash sector + * as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * flash_sector -- flash sector for save certificate + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_ca_enable(uint8 level, uint32 flash_sector ); + +/****************************************************************************** + * FunctionName : espconn_secure_ca_disable + * Description : disable the certificate authenticate as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_ca_disable(uint8 level); + + +/****************************************************************************** + * FunctionName : espconn_secure_cert_req_enable + * Description : enable the client certificate authenticate and set the flash sector + * as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * flash_sector -- flash sector for save certificate + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_cert_req_enable(uint8 level, uint32 flash_sector ); + +/****************************************************************************** + * FunctionName : espconn_secure_ca_disable + * Description : disable the client certificate authenticate as client or server + * Parameters : level -- set for client or server + * 1: client,2:server,3:client and server + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_cert_req_disable(uint8 level); + +/****************************************************************************** + * FunctionName : espconn_secure_set_default_certificate + * Description : Load the certificates in memory depending on compile-time + * and user options. + * Parameters : certificate -- Load the certificate + * length -- Load the certificate length + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_set_default_certificate(const uint8* certificate, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_secure_set_default_private_key + * Description : Load the key in memory depending on compile-time + * and user options. + * Parameters : private_key -- Load the key + * length -- Load the key length + * Returns : result true or false +*******************************************************************************/ + +bool espconn_secure_set_default_private_key(const uint8* private_key, uint16 length); + +/****************************************************************************** + * FunctionName : espconn_secure_accept + * Description : The function given as the listen + * Parameters : espconn -- the espconn used to listen the connection + * Returns : result +*******************************************************************************/ + +sint8 espconn_secure_accept(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_secure_accepts + * Description : delete the secure server host + * Parameters : espconn -- the espconn used to listen the connection + * Returns : result +*******************************************************************************/ + +sint8 espconn_secure_delete(struct espconn *espconn); + +/****************************************************************************** + * FunctionName : espconn_igmp_join + * Description : join a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_igmp_leave + * Description : leave a multicast group + * Parameters : host_ip -- the ip address of udp server + * multicast_ip -- multicast ip given by user + * Returns : none +*******************************************************************************/ +sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip); + +/****************************************************************************** + * FunctionName : espconn_recv_hold + * Description : hold tcp receive + * Parameters : espconn -- espconn to hold + * Returns : none +*******************************************************************************/ +sint8 espconn_recv_hold(struct espconn *pespconn); + +/****************************************************************************** + * FunctionName : espconn_recv_unhold + * Description : unhold tcp receive + * Parameters : espconn -- espconn to unhold + * Returns : none +*******************************************************************************/ +sint8 espconn_recv_unhold(struct espconn *pespconn); + +/****************************************************************************** + * FunctionName : espconn_mdns_init + * Description : register a device with mdns + * Parameters : ipAddr -- the ip address of device + * hostname -- the hostname of device + * Returns : none +*******************************************************************************/ + +void espconn_mdns_init(struct mdns_info *info); +/****************************************************************************** + * FunctionName : espconn_mdns_close + * Description : close a device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ + +void espconn_mdns_close(void); +/****************************************************************************** + * FunctionName : espconn_mdns_server_register + * Description : register a device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_server_register(void); + +/****************************************************************************** + * FunctionName : espconn_mdns_server_unregister + * Description : unregister a device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_server_unregister(void); + +/****************************************************************************** + * FunctionName : espconn_mdns_get_servername + * Description : get server name of device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ + +char* espconn_mdns_get_servername(void); +/****************************************************************************** + * FunctionName : espconn_mdns_set_servername + * Description : set server name of device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_set_servername(const char *name); + +/****************************************************************************** + * FunctionName : espconn_mdns_set_hostname + * Description : set host name of device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_set_hostname(char *name); + +/****************************************************************************** + * FunctionName : espconn_mdns_get_hostname + * Description : get host name of device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +char* espconn_mdns_get_hostname(void); + +/****************************************************************************** + * FunctionName : espconn_mdns_disable + * Description : disable a device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_disable(void); + +/****************************************************************************** + * FunctionName : espconn_mdns_enable + * Description : disable a device with mdns + * Parameters : a + * Returns : none +*******************************************************************************/ +void espconn_mdns_enable(void); +/****************************************************************************** + * FunctionName : espconn_dns_setserver + * Description : Initialize one of the DNS servers. + * Parameters : numdns -- the index of the DNS server to set must + * be < DNS_MAX_SERVERS = 2 + * dnsserver -- IP address of the DNS server to set + * Returns : none +*******************************************************************************/ +void espconn_dns_setserver(uint8 numdns, ip_addr_t *dnsserver); +/****************************************************************************** + * FunctionName : espconn_dns_getserver + * Description : get dns server. + * Parameters : numdns -- the index of the DNS server, must + * be < DNS_MAX_SERVERS = 2 + * Returns : dnsserver -- IP address of the DNS server to set +*******************************************************************************/ +ip_addr_t espconn_dns_getserver(uint8 numdns); +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/espnow.h b/Sming/third-party/ESP8266_NONOS_SDK/include/espnow.h new file mode 100644 index 0000000000..220412c0ad --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/espnow.h @@ -0,0 +1,73 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __ESPNOW_H__ +#define __ESPNOW_H__ + +enum esp_now_role { + ESP_NOW_ROLE_IDLE = 0, + ESP_NOW_ROLE_CONTROLLER, + ESP_NOW_ROLE_SLAVE, + ESP_NOW_ROLE_COMBO, + ESP_NOW_ROLE_MAX, +}; + +typedef void (*esp_now_recv_cb_t)(u8 *mac_addr, u8 *data, u8 len); +typedef void (*esp_now_send_cb_t)(u8 *mac_addr, u8 status); + +int esp_now_init(void); +int esp_now_deinit(void); + +int esp_now_register_send_cb(esp_now_send_cb_t cb); +int esp_now_unregister_send_cb(void); + +int esp_now_register_recv_cb(esp_now_recv_cb_t cb); +int esp_now_unregister_recv_cb(void); + +int esp_now_send(u8 *da, u8 *data, int len); + +int esp_now_add_peer(u8 *mac_addr, u8 role, u8 channel, u8 *key, u8 key_len); +int esp_now_del_peer(u8 *mac_addr); + +int esp_now_set_self_role(u8 role); +int esp_now_get_self_role(void); + +int esp_now_set_peer_role(u8 *mac_addr, u8 role); +int esp_now_get_peer_role(u8 *mac_addr); + +int esp_now_set_peer_channel(u8 *mac_addr, u8 channel); +int esp_now_get_peer_channel(u8 *mac_addr); + +int esp_now_set_peer_key(u8 *mac_addr, u8 *key, u8 key_len); +int esp_now_get_peer_key(u8 *mac_addr, u8 *key, u8 *key_len); + +u8 *esp_now_fetch_peer(bool restart); + +int esp_now_is_peer_exist(u8 *mac_addr); + +int esp_now_get_cnt_info(u8 *all_cnt, u8 *encrypt_cnt); + +int esp_now_set_kok(u8 *key, u8 len); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h b/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h new file mode 100755 index 0000000000..aed52f33aa --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/ets_sys.h @@ -0,0 +1,130 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _ETS_SYS_H +#define _ETS_SYS_H + +#include "c_types.h" +#include "eagle_soc.h" + +typedef uint32_t ETSSignal; +typedef uint32_t ETSParam; + +typedef struct ETSEventTag ETSEvent; + +struct ETSEventTag { + ETSSignal sig; + ETSParam par; +}; + +typedef void (*ETSTask)(ETSEvent *e); + +/* timer related */ +typedef uint32_t ETSHandle; +typedef void ETSTimerFunc(void *timer_arg); + +typedef struct _ETSTIMER_ { + struct _ETSTIMER_ *timer_next; + uint32_t timer_expire; + uint32_t timer_period; + ETSTimerFunc *timer_func; + void *timer_arg; +} ETSTimer; + +/* interrupt related */ +#define ETS_SDIO_INUM 1 +#define ETS_SPI_INUM 2 +#define ETS_GPIO_INUM 4 +#define ETS_UART_INUM 5 +#define ETS_UART1_INUM 5 +#define ETS_FRC_TIMER1_INUM 9 /* use edge*/ + +typedef void (* ets_isr_t)(void *); + +void ets_intr_lock(void); +void ets_intr_unlock(void); +void ets_isr_attach(int i, ets_isr_t func, void *arg); + +void NmiTimSetFunc(void (*func)(void)); + +#define ETS_INTR_LOCK() \ + ets_intr_lock() + +#define ETS_INTR_UNLOCK() \ + ets_intr_unlock() + +#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \ + ets_isr_attach(ETS_FRC_TIMER1_INUM, (func), (void *)(arg)) + +#define ETS_FRC_TIMER1_NMI_INTR_ATTACH(func) \ + NmiTimSetFunc(func) + +#define ETS_SDIO_INTR_ATTACH(func, arg)\ + ets_isr_attach(ETS_SDIO_INUM, (func), (void *)(arg)) + +#define ETS_GPIO_INTR_ATTACH(func, arg) \ + ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg)) + +#define ETS_UART_INTR_ATTACH(func, arg) \ + ets_isr_attach(ETS_UART_INUM, (func), (void *)(arg)) + +#define ETS_SPI_INTR_ATTACH(func, arg) \ + ets_isr_attach(ETS_SPI_INUM, (func), (void *)(arg)) + +#define ETS_INTR_ENABLE(inum) \ + ets_isr_unmask((1< + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4) + +#define GPIO_ID_IS_PIN_REGISTER(reg_id) \ + ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1))) + +#define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0) + +typedef enum { + GPIO_PIN_INTR_DISABLE = 0, + GPIO_PIN_INTR_POSEDGE = 1, + GPIO_PIN_INTR_NEGEDGE = 2, + GPIO_PIN_INTR_ANYEDGE = 3, + GPIO_PIN_INTR_LOLEVEL = 4, + GPIO_PIN_INTR_HILEVEL = 5 +} GPIO_INT_TYPE; + +#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ + gpio_output_set((bit_value)<>gpio_no)&BIT0) + +/* GPIO interrupt handler, registered through gpio_intr_handler_register */ +typedef void (* gpio_intr_handler_fn_t)(uint32 intr_mask, void *arg); + + +/* + * Initialize GPIO. This includes reading the GPIO Configuration DataSet + * to initialize "output enables" and pin configurations for each gpio pin. + * Must be called once during startup. + */ +void gpio_init(void); + +/* + * Change GPIO pin output by setting, clearing, or disabling pins. + * In general, it is expected that a bit will be set in at most one + * of these masks. If a bit is clear in all masks, the output state + * remains unchanged. + * + * There is no particular ordering guaranteed; so if the order of + * writes is significant, calling code should divide a single call + * into multiple calls. + */ +void gpio_output_set(uint32 set_mask, + uint32 clear_mask, + uint32 enable_mask, + uint32 disable_mask); + +/* + * Sample the value of GPIO input pins and returns a bitmask. + */ +uint32 gpio_input_get(void); + +/* + * Set the specified GPIO register to the specified value. + * This is a very general and powerful interface that is not + * expected to be used during normal operation. It is intended + * mainly for debug, or for unusual requirements. + */ +void gpio_register_set(uint32 reg_id, uint32 value); + +/* Get the current value of the specified GPIO register. */ +uint32 gpio_register_get(uint32 reg_id); + +/* + * Register an application-specific interrupt handler for GPIO pin + * interrupts. Once the interrupt handler is called, it will not + * be called again until after a call to gpio_intr_ack. Any GPIO + * interrupts that occur during the interim are masked. + * + * The application-specific handler is called with a mask of + * pending GPIO interrupts. After processing pin interrupts, the + * application-specific handler may wish to use gpio_intr_pending + * to check for any additional pending interrupts before it returns. + */ +void gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg); + +/* Determine which GPIO interrupts are pending. */ +uint32 gpio_intr_pending(void); + +/* + * Acknowledge GPIO interrupts. + * Intended to be called from the gpio_intr_handler_fn. + */ +void gpio_intr_ack(uint32 ack_mask); + +void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state); + +void gpio_pin_wakeup_disable(); + +void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state); + +#endif // _GPIO_H_ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/ip_addr.h b/Sming/third-party/ESP8266_NONOS_SDK/include/ip_addr.h new file mode 100644 index 0000000000..2f2767e7de --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/ip_addr.h @@ -0,0 +1,87 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __IP_ADDR_H__ +#define __IP_ADDR_H__ + +#include "c_types.h" + +struct ip_addr { + uint32 addr; +}; + +typedef struct ip_addr ip_addr_t; + +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) + +/** Set an IP address given by the four byte-parts. + Little-endian version that prevents the use of htonl. */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((uint32)((d) & 0xff) << 24) | \ + ((uint32)((c) & 0xff) << 16) | \ + ((uint32)((b) & 0xff) << 8) | \ + (uint32)((a) & 0xff) + +#define ip4_addr1(ipaddr) (((uint8*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((uint8*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((uint8*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((uint8*)(ipaddr))[3]) + +#define ip4_addr1_16(ipaddr) ((uint16)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((uint16)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((uint16)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((uint16)ip4_addr4(ipaddr)) + + +/** 255.255.255.255 */ +#define IPADDR_NONE ((uint32)0xffffffffUL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((uint32)0x00000000UL) +uint32 ipaddr_addr(const char *cp); + +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +#define IPSTR "%d.%d.%d.%d" + +#endif /* __IP_ADDR_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/json/json.h b/Sming/third-party/ESP8266_NONOS_SDK/include/json/json.h new file mode 100644 index 0000000000..2308b5b7a4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/json/json.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * A few JSON defines used for parsing and generating JSON. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __JSON_H__ +#define __JSON_H__ + +#define JSON_TYPE_ARRAY '[' +#define JSON_TYPE_OBJECT '{' +#define JSON_TYPE_PAIR ':' +#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */ +#define JSON_TYPE_STRING '"' +#define JSON_TYPE_INT 'I' +#define JSON_TYPE_NUMBER '0' +#define JSON_TYPE_ERROR 0 + +/* how should we handle null vs false - both can be 0? */ +#define JSON_TYPE_NULL 'n' +#define JSON_TYPE_TRUE 't' +#define JSON_TYPE_FALSE 'f' + +#define JSON_TYPE_CALLBACK 'C' + +enum { + JSON_ERROR_OK, + JSON_ERROR_SYNTAX, + JSON_ERROR_UNEXPECTED_ARRAY, + JSON_ERROR_UNEXPECTED_END_OF_ARRAY, + JSON_ERROR_UNEXPECTED_OBJECT, + JSON_ERROR_UNEXPECTED_STRING +}; + +#define JSON_CONTENT_TYPE "application/json" + +#endif /* __JSON_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsonparse.h b/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsonparse.h new file mode 100644 index 0000000000..e1cb67a466 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsonparse.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +#ifndef __JSONPARSE_H__ +#define __JSONPARSE_H__ + +#include "c_types.h" +#include "json/json.h" + +#ifdef JSONPARSE_CONF_MAX_DEPTH +#define JSONPARSE_MAX_DEPTH JSONPARSE_CONF_MAX_DEPTH +#else +#define JSONPARSE_MAX_DEPTH 10 +#endif + +struct jsonparse_state { + const char *json; + int pos; + int len; + int depth; + /* for handling atomic values */ + int vstart; + int vlen; + char vtype; + char error; + char stack[JSONPARSE_MAX_DEPTH]; +}; + +/** + * \brief Initialize a JSON parser state. + * \param state A pointer to a JSON parser state + * \param json The string to parse as JSON + * \param len The length of the string to parse + * + * This function initializes a JSON parser state for + * parsing a string as JSON. + */ +void jsonparse_setup(struct jsonparse_state *state, const char *json, + int len); + +/* move to next JSON element */ +int jsonparse_next(struct jsonparse_state *state); + +/* copy the current JSON value into the specified buffer */ +int jsonparse_copy_value(struct jsonparse_state *state, char *buf, + int buf_size); + +/* get the current JSON value parsed as an int */ +int jsonparse_get_value_as_int(struct jsonparse_state *state); + +/* get the current JSON value parsed as a long */ +long jsonparse_get_value_as_long(struct jsonparse_state *state); + +/* get the current JSON value parsed as a unsigned long */ +unsigned long jsonparse_get_value_as_ulong(struct jsonparse_state *state); + +/* get the length of the current JSON value */ +int jsonparse_get_len(struct jsonparse_state *state); + +/* get the type of the current JSON value */ +int jsonparse_get_type(struct jsonparse_state *state); + +/* compare the JSON value with the specified string */ +int jsonparse_strcmp_value(struct jsonparse_state *state, const char *str); + +#endif /* __JSONPARSE_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsontree.h b/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsontree.h new file mode 100644 index 0000000000..0ffe9d1549 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/json/jsontree.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * JSON output generation + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __JSONTREE_H__ +#define __JSONTREE_H__ + +#include "c_types.h" +#include "json/json.h" + +#ifdef JSONTREE_CONF_MAX_DEPTH +#define JSONTREE_MAX_DEPTH JSONTREE_CONF_MAX_DEPTH +#else +#define JSONTREE_MAX_DEPTH 10 +#endif /* JSONTREE_CONF_MAX_DEPTH */ + +struct jsontree_context { + struct jsontree_value *values[JSONTREE_MAX_DEPTH]; + uint16_t index[JSONTREE_MAX_DEPTH]; + int (* putchar)(int); + uint8_t depth; + uint8_t path; + int callback_state; +}; + +struct jsontree_value { + uint8_t type; + /* followed by a value */ +}; + +struct jsontree_string { + uint8_t type; + const char *value; +}; + +struct jsontree_int { + uint8_t type; + int value; +}; + +/* NOTE: the jsontree_callback set will receive a jsonparse state */ +struct jsonparse_state; +struct jsontree_callback { + uint8_t type; + int (* output)(struct jsontree_context *js_ctx); + int (* set)(struct jsontree_context *js_ctx, struct jsonparse_state *parser); +}; + +struct jsontree_pair { + const char *name; + struct jsontree_value *value; +}; + +struct jsontree_object { + uint8_t type; + uint8_t count; + struct jsontree_pair *pairs; +}; + +struct jsontree_array { + uint8_t type; + uint8_t count; + struct jsontree_value **values; +}; + +#define JSONTREE_STRING(text) {JSON_TYPE_STRING, (text)} +#define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)} +#define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)} + +#define JSONTREE_OBJECT(name, ...) \ + static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ + static struct jsontree_object name = { \ + JSON_TYPE_OBJECT, \ + sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ + jsontree_pair_##name } + +#define JSONTREE_PAIR_ARRAY(value) (struct jsontree_value *)(value) +#define JSONTREE_ARRAY(name, ...) \ + static struct jsontree_value* jsontree_value_##name[] = {__VA_ARGS__}; \ + static struct jsontree_array name = { \ + JSON_TYPE_ARRAY, \ + sizeof(jsontree_value_##name)/sizeof(struct jsontree_value*), \ + jsontree_value_##name } + +#define JSONTREE_OBJECT_EXT(name, ...) \ + static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ + struct jsontree_object name = { \ + JSON_TYPE_OBJECT, \ + sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ + jsontree_pair_##name } + +void jsontree_setup(struct jsontree_context *js_ctx, + struct jsontree_value *root, int (* putchar)(int)); +void jsontree_reset(struct jsontree_context *js_ctx); + +const char *jsontree_path_name(const struct jsontree_context *js_ctx, + int depth); + +void jsontree_write_int(const struct jsontree_context *js_ctx, int value); +void jsontree_write_int_array(const struct jsontree_context *js_ctx, const int *text, uint32 length); + +void jsontree_write_atom(const struct jsontree_context *js_ctx, + const char *text); +void jsontree_write_string(const struct jsontree_context *js_ctx, + const char *text); +int jsontree_print_next(struct jsontree_context *js_ctx); +struct jsontree_value *jsontree_find_next(struct jsontree_context *js_ctx, + int type); + +#endif /* __JSONTREE_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h b/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h new file mode 100644 index 0000000000..b979da966c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/mem.h @@ -0,0 +1,88 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + +#include + +/* Note: check_memleak_debug_enable is a weak function inside SDK. + * please copy following codes to user_main.c. +#include "mem.h" + +bool ICACHE_FLASH_ATTR check_memleak_debug_enable(void) +{ + return MEMLEAK_DEBUG_ENABLE; +} +*/ + +void *pvPortMalloc (size_t sz, const char *, unsigned); +void vPortFree (void *p, const char *, unsigned); +void *pvPortZalloc (size_t sz, const char *, unsigned); +void *pvPortRealloc (void *p, size_t n, const char *, unsigned); + +#ifndef MEMLEAK_DEBUG +#define MEMLEAK_DEBUG_ENABLE 0 +#define os_free(s) vPortFree(s, "", 0) +#define os_malloc(s) pvPortMalloc(s, "", 0) +#define os_calloc(s) pvPortCalloc(s, "", 0); +#define os_realloc(p, s) pvPortRealloc(p, s, "", 0) +#define os_zalloc(s) pvPortZalloc(s, "", 0) +#else +#define MEMLEAK_DEBUG_ENABLE 1 + +#define os_free(s) \ +do{\ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + vPortFree(s, mem_debug_file, __LINE__);\ +}while(0) + +#define os_malloc(s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortMalloc(s, mem_debug_file, __LINE__); \ + }) + +#define os_calloc(s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortCalloc(s, mem_debug_file, __LINE__); \ + }) + +#define os_realloc(p, s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortRealloc(p, s, mem_debug_file, __LINE__); \ + }) + +#define os_zalloc(s) \ + ({ \ + static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; \ + pvPortZalloc(s, mem_debug_file, __LINE__); \ + }) + +#endif + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/mesh.h b/Sming/third-party/ESP8266_NONOS_SDK/include/mesh.h new file mode 100644 index 0000000000..b55376c393 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/mesh.h @@ -0,0 +1,341 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2015 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __LWIP_API_MESH_H__ +#define __LWIP_API_MESH_H__ + +#include "ip_addr.h" +#include "user_interface.h" +#include "espconn.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_MESH_GROUP_ID_LEN (6) + +typedef void (* espconn_mesh_callback)(); +typedef void (* espconn_mesh_scan_callback)(void *arg, int8_t status); + +enum mesh_type { + MESH_CLOSE = 0, + MESH_LOCAL, + MESH_ONLINE, + MESH_NONE = 0xFF +}; +/** \defgroup Mesh_APIs Mesh APIs + * @brief Mesh APIs + * + * + * + */ + +/** @addtogroup Mesh_APIs + * @{ + */ + +enum mesh_status { + MESH_DISABLE = 0, + MESH_WIFI_CONN, + MESH_NET_CONN, + MESH_LOCAL_AVAIL, + MESH_ONLINE_AVAIL +}; + +enum mesh_node_type { + MESH_NODE_PARENT = 0, + MESH_NODE_CHILD, + MESH_NODE_ALL +}; + +struct mesh_scan_para_type { + espconn_mesh_scan_callback usr_scan_cb; // scan done callback + uint8_t grp_id[ESP_MESH_GROUP_ID_LEN]; // group id + bool grp_set; // group set +}; + + +/** + * @brief Check whether the IP address is mesh local IP address or not. + * + * @attention 1. The range of mesh local IP address is 2.255.255.* ~ max_hop.255.255.*. + * @attention 2. IP pointer should not be NULL. If the IP pointer is NULL, it will return false. + * + * @param struct ip_addr *ip : IP address + * + * @return true : the IP address is mesh local IP address + * @return false : the IP address is not mesh local IP address + */ +bool espconn_mesh_local_addr(struct ip_addr *ip); + +/** + * @brief Get the information of router used by mesh network. + * + * @attention 1. The function should be called after mesh_enable_done + * + * @param struct station_config *router: router inforamtion + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_get_router(struct station_config *router); + +/** + * @brief Set the information of router used by mesh network. + * + * @attention The function must be called before espconn_mesh_enable. + * + * @param struct station_config *router: router information. + * user should initialize the ssid and password. + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_set_router(struct station_config *router); + +/** + * @brief Set server setup by user. + * + * @attention If users wants to use themself server, they use the function. + * but the function must be called before espconn_mesh_enable. + * at the same time, users need to implement the server. + * + * @param struct ip_addr *ip : ip address of server. + * @param uint16_t port : port used by server. + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_server_init(struct ip_addr *ip, uint16_t port); + +/** + * @brief Get the information of mesh node. + * + * @param enum mesh_node_type typ : mesh node type. + * @param uint8_t **info : the information will be saved in *info. + * @param uint8_t *count : the node count in *info. + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_get_node_info(enum mesh_node_type type, + uint8_t **info, uint8_t *count); + +/** + * @brief Set WiFi cryption algrithm and password for mesh node. + * + * @attention The function must be called before espconn_mesh_enable. + * + * @param AUTH_MODE mode : cryption algrithm (WPA/WAP2/WPA_WPA2). + * @param uint8_t *passwd : password of WiFi. + * @param uint8_t passwd_len : length of password (8 <= passwd_len <= 64). + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_encrypt_init(AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len); +/** + * @brief Set prefix of SSID for mesh node. + * + * @attention The function must be called before espconn_mesh_enable. + * + * @param uint8_t *prefix : prefix of SSID. + * @param uint8_t prefix_len : length of prefix (0 < passwd_len <= 22). + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_set_ssid_prefix(uint8_t *prefix, uint8_t prefix_len); + +/** + * @brief Set max hop for mesh network. + * + * @attention The function must be called before espconn_mesh_enable. + * + * @param uint8_t max_hops : max hop of mesh network (1 <= max_hops < 10, 4 is recommended). + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_set_max_hops(uint8_t max_hops); + +/** + * @brief Set group ID of mesh node. + * + * @attention The function must be called before espconn_mesh_enable. + * + * @param uint8_t *grp_id : group ID. + * @param uint16_t gid_len: length of group ID, now gid_len = 6. + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_group_id_init(uint8_t *grp_id, uint16_t gid_len); + +/** + * @brief Set the curent device type. + * + * @param uint8_t dev_type : device type of mesh node + * + * @return true : succeed + * @return false : fail + */ +bool espconn_mesh_set_dev_type(uint8_t dev_type); +/** + * @brief Get the curent device type. + * + * @param none + * + * @return device type + */ +uint8_t espconn_mesh_get_dev_type(); + +/** + * @brief Try to establish mesh connection to server. + * + * @attention If espconn_mesh_connect fail, returns non-0 value, there is no connection, so it + * won't enter any espconn callback. + * + * @param struct espconn *usr_esp : the network connection structure, the usr_esp to + * listen to the connection + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_RTE - Routing Problem + * - ESPCONN_MEM - Out of memory + * - ESPCONN_ISCONN - Already connected + * - ESPCONN_ARG - Illegal argument, can't find the corresponding connection + * according to structure espconn + */ +int8_t espconn_mesh_connect(struct espconn *usr_esp); + +/** + * @brief Disconnect a mesh connection. + * + * @attention Do not call this API in any espconn callback. If needed, please use system + * task to trigger espconn_mesh_disconnect. + * + * @param struct espconn *usr_esp : the network connection structure + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_ARG - illegal argument, can't find the corresponding TCP connection + * according to structure espconn + */ + +int8_t espconn_mesh_disconnect(struct espconn *usr_esp); + +/** + * @brief Get current mesh status. + * + * @param null + * + * @return the current mesh status, please refer to enum mesh_status. + */ +int8_t espconn_mesh_get_status(); + +/** + * @brief Send data through mesh network. + * + * @attention Please call espconn_mesh_sent after espconn_sent_callback of the pre-packet. + * + * @param struct espconn *usr_esp : the network connection structure + * @param uint8 *pdata : pointer of data + * @param uint16 len : data length + * + * @return 0 : succeed + * @return Non-0 : error code + * - ESPCONN_MEM - out of memory + * - ESPCONN_ARG - illegal argument, can't find the corresponding network transmission + * according to structure espconn + * - ESPCONN_MAXNUM - buffer of sending data is full + * - ESPCONN_IF - send UDP data fail + */ +int8_t espconn_mesh_sent(struct espconn *usr_esp, uint8 *pdata, uint16 len); + +/** + * @brief Get max hop of mesh network. + * + * @param null. + * + * @return the current max hop of mesh + */ +uint8_t espconn_mesh_get_max_hops(); + +/** + * @brief To enable mesh network. + * + * @attention 1. the function should be called in user_init. + * @attention 2. if mesh node can not scan the mesh AP, it will be isolate node without trigger enable_cb. + * user can use espconn_mesh_get_status to get current status of node. + * @attention 3. if user try to enable online mesh, but node fails to establish mesh connection + * the node will work with local mesh. + * + * @param espconn_mesh_callback enable_cb : callback function of mesh-enable + * @param enum mesh_type type : type of mesh, local or online. + * + * @return null + */ +void espconn_mesh_enable(espconn_mesh_callback enable_cb, enum mesh_type type); + +/** + * @brief To disable mesh network. + * + * @attention When mesh network is disabed, the system will trigger disable_cb. + * + * @param espconn_mesh_callback disable_cb : callback function of mesh-disable + * @param enum mesh_type type : type of mesh, local or online. + * + * @return null + */ +void espconn_mesh_disable(espconn_mesh_callback disable_cb); + +/** + * @brief To print version of mesh. + * + * @param null + * + * @return null + */ +void espconn_mesh_print_ver(); + +/** + * @brief To get AP around node. + * + * @attention User can get normal AP or mesh AP using the function. + * If user plans to get normal AP, he/she needs to clear grp_set flag in para. + * If user plans to get mesh AP, he/she needs to set grp_set and grp_id; + * + * @param struct mesh_scan_para_type *para : callback function of mesh-disable + * + * @return null + */ +void espconn_mesh_scan(struct mesh_scan_para_type *para); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h b/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h new file mode 100644 index 0000000000..9e43472bb7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/os_type.h @@ -0,0 +1,37 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _OS_TYPES_H_ +#define _OS_TYPES_H_ + +#include "ets_sys.h" + +#define os_signal_t ETSSignal +#define os_param_t ETSParam +#define os_event_t ETSEvent +#define os_task_t ETSTask +#define os_timer_t ETSTimer +#define os_timer_func_t ETSTimerFunc + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h b/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h new file mode 100644 index 0000000000..52ad21f9f7 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/osapi.h @@ -0,0 +1,94 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _OSAPI_H_ +#define _OSAPI_H_ + +#include +#include "os_type.h" +#include "user_config.h" + +void ets_bzero(void *s, size_t n); +void ets_delay_us(uint32_t us); +void ets_install_putc1(void (*p)(char c)); + +#define os_bzero ets_bzero +#define os_delay_us ets_delay_us +#define os_install_putc1 ets_install_putc1 + +int ets_memcmp(const void *str1, const void *str2, unsigned int nbyte); +void *ets_memcpy(void *dest, const void *src, unsigned int nbyte); +void *ets_memmove(void *dest, const void *src, unsigned int nbyte); +void *ets_memset(void *dest, int val, unsigned int nbyte); + +int ets_strcmp(const char *s1, const char *s2); +char *ets_strcpy(char *s1, const char *s2); +int ets_strlen(const char *s); +int ets_strncmp(const char *s1, const char *s2, unsigned int n); +char *ets_strncpy(char *s1, const char *s2, unsigned int n); +char *ets_strstr(const char *s1, const char *s2); + +#define os_memcmp ets_memcmp +#define os_memcpy ets_memcpy +#define os_memmove ets_memmove +#define os_memset ets_memset +#define os_strcat strcat +#define os_strchr strchr +#define os_strcmp ets_strcmp +#define os_strcpy ets_strcpy +#define os_strlen ets_strlen +#define os_strncmp ets_strncmp +#define os_strncpy ets_strncpy +#define os_strstr ets_strstr + +void ets_timer_arm_new(os_timer_t *ptimer, uint32_t time, bool repeat_flag, bool ms_flag); +void ets_timer_disarm(os_timer_t *ptimer); +void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg); + +#ifdef USE_US_TIMER +#define os_timer_arm_us(a, b, c) ets_timer_arm_new(a, b, c, 0) +#endif +#define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1) +#define os_timer_disarm ets_timer_disarm +#define os_timer_setfn ets_timer_setfn + +int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); + +#define os_sprintf ets_sprintf + +#ifdef USE_OPTIMIZE_PRINTF +#define os_printf(fmt, ...) do { \ + static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ + os_printf_plus(flash_str, ##__VA_ARGS__); \ + } while(0) +#else +#define os_printf os_printf_plus +#endif + +unsigned long os_random(void); +int os_get_random(unsigned char *buf, size_t len); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/ping.h b/Sming/third-party/ESP8266_NONOS_SDK/include/ping.h new file mode 100644 index 0000000000..6537a7a464 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/ping.h @@ -0,0 +1,56 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __PING_H__ +#define __PING_H__ + + +typedef void (* ping_recv_function)(void* arg, void *pdata); +typedef void (* ping_sent_function)(void* arg, void *pdata); + +struct ping_option{ + uint32 count; + uint32 ip; + uint32 coarse_time; + ping_recv_function recv_function; + ping_sent_function sent_function; + void* reverse; +}; + +struct ping_resp{ + uint32 total_count; + uint32 resp_time; + uint32 seqno; + uint32 timeout_count; + uint32 bytes; + uint32 total_bytes; + uint32 total_time; + sint8 ping_err; +}; + +bool ping_start(struct ping_option *ping_opt); +bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv); +bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent); + +#endif /* __PING_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/pwm.h b/Sming/third-party/ESP8266_NONOS_SDK/include/pwm.h new file mode 100644 index 0000000000..eae782f8b8 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/pwm.h @@ -0,0 +1,58 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __PWM_H__ +#define __PWM_H__ + +/*pwm.h: function and macro definition of PWM API , driver level */ +/*user_light.h: user interface for light API, user level*/ +/*user_light_adj: API for color changing and lighting effects, user level*/ + + + /*NOTE!! : DO NOT CHANGE THIS FILE*/ + + /*SUPPORT UP TO 8 PWM CHANNEL*/ +#define PWM_CHANNEL_NUM_MAX 8 + +struct pwm_param { + uint32 period; + uint32 freq; + uint32 duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8 +}; + + +/* pwm_init should be called only once, for now */ +void pwm_init(uint32 period, uint32 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3]); +void pwm_start(void); + +void pwm_set_duty(uint32 duty, uint8 channel); +uint32 pwm_get_duty(uint8 channel); +void pwm_set_period(uint32 period); +uint32 pwm_get_period(void); + +uint32 get_pwm_version(void); +void set_pwm_debug_en(uint8 print_en); + +#endif + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h b/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h new file mode 100644 index 0000000000..579e5a8f4c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/queue.h @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#define QMD_SAVELINK(name, link) +#define TRASHIT(x) + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ + struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ + } + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ + struct { \ + struct type *stqe_next; /* next element */ \ + } + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ + } while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ + } while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ + } while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ + } while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ + } while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ + } while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ + } while (0) + +#define STAILQ_INSERT_CHAIN_HEAD(head, elm_chead, elm_ctail, field) do { \ + if ((STAILQ_NEXT(elm_ctail, field) = STAILQ_FIRST(head)) == NULL ) { \ + (head)->stqh_last = &STAILQ_NEXT(elm_ctail, field); \ + } \ + STAILQ_FIRST(head) = (elm_chead); \ + } while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/simple_pair.h b/Sming/third-party/ESP8266_NONOS_SDK/include/simple_pair.h new file mode 100644 index 0000000000..8014809427 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/simple_pair.h @@ -0,0 +1,64 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SIMPLE_PAIR_H__ +#define __SIMPLE_PAIR_H__ + +typedef enum { + SP_ST_STA_FINISH = 0, + SP_ST_AP_FINISH = 0, + SP_ST_AP_RECV_NEG, + SP_ST_STA_AP_REFUSE_NEG, + /* all following is err */ + SP_ST_WAIT_TIMEOUT, + SP_ST_SEND_ERROR, + SP_ST_KEY_INSTALL_ERR, + SP_ST_KEY_OVERLAP_ERR, //means the same macaddr has two different keys + SP_ST_OP_ERROR, + SP_ST_UNKNOWN_ERROR, + SP_ST_MAX, +} SP_ST_t; + + +typedef void (*simple_pair_status_cb_t)(u8 *sa, u8 status); + +int register_simple_pair_status_cb(simple_pair_status_cb_t cb); +void unregister_simple_pair_status_cb(void); + +int simple_pair_init(void); +void simple_pair_deinit(void); + +int simple_pair_state_reset(void); +int simple_pair_ap_enter_announce_mode(void); +int simple_pair_sta_enter_scan_mode(void); + +int simple_pair_sta_start_negotiate(void); +int simple_pair_ap_start_negotiate(void); +int simple_pair_ap_refuse_negotiate(void); + +int simple_pair_set_peer_ref(u8 *peer_mac, u8 *tmp_key, u8 *ex_key); +int simple_pair_get_peer_ref(u8 *peer_mac, u8 *tmp_key, u8 *ex_key); + + +#endif /* __SIMPLE_PAIR_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/smartconfig.h b/Sming/third-party/ESP8266_NONOS_SDK/include/smartconfig.h new file mode 100644 index 0000000000..6f3802addb --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/smartconfig.h @@ -0,0 +1,50 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SMARTCONFIG_H__ +#define __SMARTCONFIG_H__ + +typedef enum { + SC_STATUS_WAIT = 0, + SC_STATUS_FIND_CHANNEL, + SC_STATUS_GETTING_SSID_PSWD, + SC_STATUS_LINK, + SC_STATUS_LINK_OVER, +} sc_status; + +typedef enum { + SC_TYPE_ESPTOUCH = 0, + SC_TYPE_AIRKISS, + SC_TYPE_ESPTOUCH_AIRKISS, +} sc_type; + +typedef void (*sc_callback_t)(sc_status status, void *pdata); + +const char *smartconfig_get_version(void); +bool smartconfig_start(sc_callback_t cb, ...); +bool smartconfig_stop(void); +bool esptouch_set_timeout(uint8 time_s); //15s~255s, offset:45s +bool smartconfig_set_type(sc_type type); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/sntp.h b/Sming/third-party/ESP8266_NONOS_SDK/include/sntp.h new file mode 100644 index 0000000000..db02748959 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/sntp.h @@ -0,0 +1,68 @@ +#ifndef __SNTP_H__ +#define __SNTP_H__ + +#include "os_type.h" +#ifdef LWIP_OPEN_SRC +#include "lwip/ip_addr.h" +#else +#include "ip_addr.h" +#endif +/** + * get the seconds since Jan 01, 1970, 00:00 (GMT + 8) + */ +uint32 sntp_get_current_timestamp(); +/** + * get real time (GTM + 8 time zone) + */ +char* sntp_get_real_time(long t); +/** + * SNTP get time_zone default GMT + 8 + */ +sint8 sntp_get_timezone(void); +/** + * SNTP set time_zone (default GMT + 8) + */ +bool sntp_set_timezone(sint8 timezone); +/** + * Initialize this module. + * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). + */ +void sntp_init(void); +/** + * Stop this module. + */ +void sntp_stop(void); +/** + * Initialize one of the NTP servers by IP address + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS + * @param dnsserver IP address of the NTP server to set + */ +void sntp_setserver(unsigned char idx, ip_addr_t *addr); +/** + * Obtain one of the currently configured by IP address (or DHCP) NTP servers + * + * @param numdns the index of the NTP server + * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP + * server has not been configured by address (or at all). + */ +ip_addr_t sntp_getserver(unsigned char idx); +/** + * Initialize one of the NTP servers by name + * + * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS,now sdk support SNTP_MAX_SERVERS = 3 + * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time + */ +void sntp_setservername(unsigned char idx, char *server); +/** + * Obtain one of the currently configured by name NTP servers. + * + * @param numdns the index of the NTP server + * @return IP address of the indexed NTP server or NULL if the NTP + * server has not been configured by name (or at all) + */ +char *sntp_getservername(unsigned char idx); + +#define sntp_servermode_dhcp(x) + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h b/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h new file mode 100644 index 0000000000..2ff478653d --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/spi_flash.h @@ -0,0 +1,61 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef SPI_FLASH_H +#define SPI_FLASH_H + +typedef enum { + SPI_FLASH_RESULT_OK, + SPI_FLASH_RESULT_ERR, + SPI_FLASH_RESULT_TIMEOUT +} SpiFlashOpResult; + +typedef struct{ + uint32 deviceId; + uint32 chip_size; // chip size in byte + uint32 block_size; + uint32 sector_size; + uint32 page_size; + uint32 status_mask; +} SpiFlashChip; + +#define SPI_FLASH_SEC_SIZE 4096 + +uint32 spi_flash_get_id(void); +SpiFlashOpResult spi_flash_erase_sector(uint16 sec); +SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); +SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size); + +typedef SpiFlashOpResult (* user_spi_flash_read)( + SpiFlashChip *spi, + uint32 src_addr, + uint32 *des_addr, + uint32 size); + +void spi_flash_set_read_func(user_spi_flash_read read); + +bool spi_flash_erase_protect_enable(void); +bool spi_flash_erase_protect_disable(void); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/upgrade.h b/Sming/third-party/ESP8266_NONOS_SDK/include/upgrade.h new file mode 100644 index 0000000000..e7e69681be --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/upgrade.h @@ -0,0 +1,74 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __UPGRADE_H__ +#define __UPGRADE_H__ + +#define SPI_FLASH_SEC_SIZE 4096 +#define LIMIT_ERASE_SIZE 0x10000 + +#define USER_BIN1 0x00 +#define USER_BIN2 0x01 + +#define UPGRADE_FLAG_IDLE 0x00 +#define UPGRADE_FLAG_START 0x01 +#define UPGRADE_FLAG_FINISH 0x02 + +#define UPGRADE_FW_BIN1 0x00 +#define UPGRADE_FW_BIN2 0x01 + +typedef void (*upgrade_states_check_callback)(void * arg); + +//#define UPGRADE_SSL_ENABLE + +struct upgrade_server_info { + uint8 ip[4]; + uint16 port; + + uint8 upgrade_flag; + + uint8 pre_version[16]; + uint8 upgrade_version[16]; + + uint32 check_times; + uint8 *url; + + upgrade_states_check_callback check_cb; + struct espconn *pespconn; +}; + +#define UPGRADE_FLAG_IDLE 0x00 +#define UPGRADE_FLAG_START 0x01 +#define UPGRADE_FLAG_FINISH 0x02 + +void system_upgrade_init(); +void system_upgrade_deinit(); +bool system_upgrade(uint8 *data, uint16 len); + +#ifdef UPGRADE_SSL_ENABLE +bool system_upgrade_start_ssl(struct upgrade_server_info *server); // not supported now +#else +bool system_upgrade_start(struct upgrade_server_info *server); +#endif +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h b/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h new file mode 100644 index 0000000000..dbd171dcee --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/user_interface.h @@ -0,0 +1,654 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __USER_INTERFACE_H__ +#define __USER_INTERFACE_H__ + +#include "os_type.h" +#ifdef LWIP_OPEN_SRC +#include "lwip/ip_addr.h" +#else +#include "ip_addr.h" +#endif + +#include "queue.h" +#include "user_config.h" +#include "spi_flash.h" +#include "gpio.h" + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +enum rst_reason { + REASON_DEFAULT_RST = 0, + REASON_WDT_RST = 1, + REASON_EXCEPTION_RST = 2, + REASON_SOFT_WDT_RST = 3, + REASON_SOFT_RESTART = 4, + REASON_DEEP_SLEEP_AWAKE = 5, + REASON_EXT_SYS_RST = 6 +}; + +struct rst_info{ + uint32 reason; + uint32 exccause; + uint32 epc1; + uint32 epc2; + uint32 epc3; + uint32 excvaddr; + uint32 depc; +}; + +struct rst_info* system_get_rst_info(void); + +#define UPGRADE_FW_BIN1 0x00 +#define UPGRADE_FW_BIN2 0x01 + +void system_restore(void); +void system_restart(void); + +bool system_deep_sleep_set_option(uint8 option); +bool system_deep_sleep(uint64 time_in_us); +bool system_deep_sleep_instant(uint64 time_in_us); + +uint8 system_upgrade_userbin_check(void); +void system_upgrade_reboot(void); +uint8 system_upgrade_flag_check(); +void system_upgrade_flag_set(uint8 flag); + +void system_timer_reinit(void); +uint32 system_get_time(void); + +/* user task's prio must be 0/1/2 !!!*/ +enum { + USER_TASK_PRIO_0 = 0, + USER_TASK_PRIO_1, + USER_TASK_PRIO_2, + USER_TASK_PRIO_MAX +}; + +bool system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen); +bool system_os_post(uint8 prio, os_signal_t sig, os_param_t par); + +void system_print_meminfo(void); +uint32 system_get_free_heap_size(void); + +void system_set_os_print(uint8 onoff); +uint8 system_get_os_print(); + +uint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec); + +uint32 system_get_chip_id(void); + +typedef void (* init_done_cb_t)(void); + +void system_init_done_cb(init_done_cb_t cb); + +uint32 system_rtc_clock_cali_proc(void); +uint32 system_get_rtc_time(void); + +bool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size); +bool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size); + +void system_uart_swap(void); +void system_uart_de_swap(void); + +uint16 system_adc_read(void); +void system_adc_read_fast(uint16 *adc_addr, uint16 adc_num, uint8 adc_clk_div); +uint16 system_get_vdd33(void); + +const char *system_get_sdk_version(void); + +#define SYS_BOOT_ENHANCE_MODE 0 +#define SYS_BOOT_NORMAL_MODE 1 + +#define SYS_BOOT_NORMAL_BIN 0 +#define SYS_BOOT_TEST_BIN 1 + +uint8 system_get_boot_version(void); +uint32 system_get_userbin_addr(void); +uint8 system_get_boot_mode(void); +bool system_restart_enhance(uint8 bin_type, uint32 bin_addr); + +#define SYS_CPU_80MHZ 80 +#define SYS_CPU_160MHZ 160 + +bool system_update_cpu_freq(uint8 freq); +uint8 system_get_cpu_freq(void); + +enum flash_size_map { + FLASH_SIZE_4M_MAP_256_256 = 0, /**< Flash size : 4Mbits. Map : 256KBytes + 256KBytes */ + FLASH_SIZE_2M, /**< Flash size : 2Mbits. Map : 256KBytes */ + FLASH_SIZE_8M_MAP_512_512, /**< Flash size : 8Mbits. Map : 512KBytes + 512KBytes */ + FLASH_SIZE_16M_MAP_512_512, /**< Flash size : 16Mbits. Map : 512KBytes + 512KBytes */ + FLASH_SIZE_32M_MAP_512_512, /**< Flash size : 32Mbits. Map : 512KBytes + 512KBytes */ + FLASH_SIZE_16M_MAP_1024_1024, /**< Flash size : 16Mbits. Map : 1024KBytes + 1024KBytes */ + FLASH_SIZE_32M_MAP_1024_1024, /**< Flash size : 32Mbits. Map : 1024KBytes + 1024KBytes */ + FLASH_SIZE_32M_MAP_2048_2048, /**< attention: don't support now ,just compatible for nodemcu; + Flash size : 32Mbits. Map : 2048KBytes + 2048KBytes */ + FLASH_SIZE_64M_MAP_1024_1024, /**< Flash size : 64Mbits. Map : 1024KBytes + 1024KBytes */ + FLASH_SIZE_128M_MAP_1024_1024 /**< Flash size : 128Mbits. Map : 1024KBytes + 1024KBytes */ +}; + +enum flash_size_map system_get_flash_size_map(void); + +void system_phy_set_max_tpw(uint8 max_tpw); +void system_phy_set_tpw_via_vdd33(uint16 vdd33); +void system_phy_set_rfoption(uint8 option); +void system_phy_set_powerup_option(uint8 option); +void system_phy_freq_trace_enable(bool enable); + +bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len); +bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len); + +void system_soft_wdt_stop(void); +void system_soft_wdt_restart(void); +void system_soft_wdt_feed(void); + +void system_show_malloc(void); + +#define NULL_MODE 0x00 +#define STATION_MODE 0x01 +#define SOFTAP_MODE 0x02 +#define STATIONAP_MODE 0x03 + +typedef enum _auth_mode { + AUTH_OPEN = 0, + AUTH_WEP, + AUTH_WPA_PSK, + AUTH_WPA2_PSK, + AUTH_WPA_WPA2_PSK, + AUTH_MAX +} AUTH_MODE; + +uint8 wifi_get_opmode(void); +uint8 wifi_get_opmode_default(void); +bool wifi_set_opmode(uint8 opmode); +bool wifi_set_opmode_current(uint8 opmode); +uint8 wifi_get_broadcast_if(void); +bool wifi_set_broadcast_if(uint8 interface); + +struct bss_info { + STAILQ_ENTRY(bss_info) next; + + uint8 bssid[6]; + uint8 ssid[32]; + uint8 ssid_len; + uint8 channel; + sint8 rssi; + AUTH_MODE authmode; + uint8 is_hidden; + sint16 freq_offset; + sint16 freqcal_val; + uint8 *esp_mesh_ie; + uint8 simple_pair; +}; + +typedef struct _scaninfo { + STAILQ_HEAD(, bss_info) *pbss; + struct espconn *pespconn; + uint8 totalpage; + uint8 pagenum; + uint8 page_sn; + uint8 data_cnt; +} scaninfo; + +typedef void (* scan_done_cb_t)(void *arg, STATUS status); + +struct station_config { + uint8 ssid[32]; + uint8 password[64]; + uint8 bssid_set; // Note: If bssid_set is 1, station will just connect to the router + // with both ssid[] and bssid[] matched. Please check about this. + uint8 bssid[6]; +}; + +bool wifi_station_get_config(struct station_config *config); +bool wifi_station_get_config_default(struct station_config *config); +bool wifi_station_set_config(struct station_config *config); +bool wifi_station_set_config_current(struct station_config *config); + +bool wifi_station_connect(void); +bool wifi_station_disconnect(void); + +sint8 wifi_station_get_rssi(void); + +typedef enum { + WIFI_SCAN_TYPE_ACTIVE = 0, /**< active scan */ + WIFI_SCAN_TYPE_PASSIVE, /**< passive scan */ +} wifi_scan_type_t; + +struct scan_config { + uint8 *ssid; // Note: ssid == NULL, don't filter ssid. + uint8 *bssid; // Note: bssid == NULL, don't filter bssid. + uint8 channel; // Note: channel == 0, scan all channels, otherwise scan set channel. + uint8 show_hidden; // Note: show_hidden == 1, can get hidden ssid routers' info. + wifi_scan_type_t scan_type; // scan type, active or passive +}; + +bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb); + +uint8 wifi_station_get_auto_connect(void); +bool wifi_station_set_auto_connect(uint8 set); + +bool wifi_station_set_reconnect_policy(bool set); + +enum { + STATION_IDLE = 0, + STATION_CONNECTING, + STATION_WRONG_PASSWORD, + STATION_NO_AP_FOUND, + STATION_CONNECT_FAIL, + STATION_GOT_IP +}; + +enum dhcp_status { + DHCP_STOPPED, + DHCP_STARTED +}; + +uint8 wifi_station_get_connect_status(void); + +uint8 wifi_station_get_current_ap_id(void); +bool wifi_station_ap_change(uint8 current_ap_id); +bool wifi_station_ap_number_set(uint8 ap_number); +uint8 wifi_station_get_ap_info(struct station_config config[]); + +bool wifi_station_dhcpc_start(void); +bool wifi_station_dhcpc_stop(void); +enum dhcp_status wifi_station_dhcpc_status(void); +bool wifi_station_dhcpc_set_maxtry(uint8 num); + +char* wifi_station_get_hostname(void); +bool wifi_station_set_hostname(char *name); + +int wifi_station_set_cert_key(uint8 *client_cert, int client_cert_len, + uint8 *private_key, int private_key_len, + uint8 *private_key_passwd, int private_key_passwd_len); +void wifi_station_clear_cert_key(void); +int wifi_station_set_username(uint8 *username, int len); +void wifi_station_clear_username(void); + +struct softap_config { + uint8 ssid[32]; + uint8 password[64]; + uint8 ssid_len; // Note: Recommend to set it according to your ssid + uint8 channel; // Note: support 1 ~ 13 + AUTH_MODE authmode; // Note: Don't support AUTH_WEP in softAP mode. + uint8 ssid_hidden; // Note: default 0 + uint8 max_connection; // Note: default 4, max 4 + uint16 beacon_interval; // Note: support 100 ~ 60000 ms, default 100 +}; + +bool wifi_softap_get_config(struct softap_config *config); +bool wifi_softap_get_config_default(struct softap_config *config); +bool wifi_softap_set_config(struct softap_config *config); +bool wifi_softap_set_config_current(struct softap_config *config); + +struct station_info { + STAILQ_ENTRY(station_info) next; + + uint8 bssid[6]; + struct ip_addr ip; +}; + +struct dhcps_lease { + bool enable; + struct ip_addr start_ip; + struct ip_addr end_ip; +}; + +enum dhcps_offer_option{ + OFFER_START = 0x00, + OFFER_ROUTER = 0x01, + OFFER_END +}; + +uint8 wifi_softap_get_station_num(void); +struct station_info * wifi_softap_get_station_info(void); +void wifi_softap_free_station_info(void); + +bool wifi_softap_dhcps_start(void); +bool wifi_softap_dhcps_stop(void); + +bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please); +bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please); +uint32 wifi_softap_get_dhcps_lease_time(void); +bool wifi_softap_set_dhcps_lease_time(uint32 minute); +bool wifi_softap_reset_dhcps_lease_time(void); + +enum dhcp_status wifi_softap_dhcps_status(void); +bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg); + +#define STATION_IF 0x00 +#define SOFTAP_IF 0x01 + +bool wifi_get_ip_info(uint8 if_index, struct ip_info *info); +bool wifi_set_ip_info(uint8 if_index, struct ip_info *info); +bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr); +bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr); + +uint8 wifi_get_channel(void); +bool wifi_set_channel(uint8 channel); + +void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func); +void wifi_status_led_uninstall(); + +/** Get the absolute difference between 2 u32_t values (correcting overflows) + * 'a' is expected to be 'higher' (without overflow) than 'b'. */ +#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) + +void wifi_promiscuous_enable(uint8 promiscuous); + +typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len); + +void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); + +void wifi_promiscuous_set_mac(const uint8_t *address); + +enum phy_mode { + PHY_MODE_11B = 1, + PHY_MODE_11G = 2, + PHY_MODE_11N = 3 +}; + +enum phy_mode wifi_get_phy_mode(void); +bool wifi_set_phy_mode(enum phy_mode mode); + +enum sleep_type { + NONE_SLEEP_T = 0, + LIGHT_SLEEP_T, + MODEM_SLEEP_T +}; + +bool wifi_set_sleep_type(enum sleep_type type); +enum sleep_type wifi_get_sleep_type(void); + +void wifi_fpm_open(void); +void wifi_fpm_close(void); +void wifi_fpm_do_wakeup(void); +sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us); +void wifi_fpm_set_sleep_type(enum sleep_type type); +enum sleep_type wifi_fpm_get_sleep_type(void); + +typedef void (*fpm_wakeup_cb)(void); +void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb); + +void wifi_fpm_auto_sleep_set_in_null_mode(uint8 req); + +enum { + EVENT_STAMODE_CONNECTED = 0, + EVENT_STAMODE_DISCONNECTED, + EVENT_STAMODE_AUTHMODE_CHANGE, + EVENT_STAMODE_GOT_IP, + EVENT_STAMODE_DHCP_TIMEOUT, + EVENT_SOFTAPMODE_STACONNECTED, + EVENT_SOFTAPMODE_STADISCONNECTED, + EVENT_SOFTAPMODE_PROBEREQRECVED, + EVENT_OPMODE_CHANGED, + EVENT_MAX +}; + +enum { + REASON_UNSPECIFIED = 1, + REASON_AUTH_EXPIRE = 2, + REASON_AUTH_LEAVE = 3, + REASON_ASSOC_EXPIRE = 4, + REASON_ASSOC_TOOMANY = 5, + REASON_NOT_AUTHED = 6, + REASON_NOT_ASSOCED = 7, + REASON_ASSOC_LEAVE = 8, + REASON_ASSOC_NOT_AUTHED = 9, + REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */ + REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */ + REASON_IE_INVALID = 13, /* 11i */ + REASON_MIC_FAILURE = 14, /* 11i */ + REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */ + REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */ + REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */ + REASON_GROUP_CIPHER_INVALID = 18, /* 11i */ + REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */ + REASON_AKMP_INVALID = 20, /* 11i */ + REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */ + REASON_INVALID_RSN_IE_CAP = 22, /* 11i */ + REASON_802_1X_AUTH_FAILED = 23, /* 11i */ + REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */ + + REASON_BEACON_TIMEOUT = 200, + REASON_NO_AP_FOUND = 201, + REASON_AUTH_FAIL = 202, + REASON_ASSOC_FAIL = 203, + REASON_HANDSHAKE_TIMEOUT = 204, +}; + +typedef struct { + uint8 ssid[32]; + uint8 ssid_len; + uint8 bssid[6]; + uint8 channel; +} Event_StaMode_Connected_t; + +typedef struct { + uint8 ssid[32]; + uint8 ssid_len; + uint8 bssid[6]; + uint8 reason; +} Event_StaMode_Disconnected_t; + +typedef struct { + uint8 old_mode; + uint8 new_mode; +} Event_StaMode_AuthMode_Change_t; + +typedef struct { + struct ip_addr ip; + struct ip_addr mask; + struct ip_addr gw; +} Event_StaMode_Got_IP_t; + +typedef struct { + uint8 mac[6]; + uint8 aid; +} Event_SoftAPMode_StaConnected_t; + +typedef struct { + uint8 mac[6]; + uint8 aid; +} Event_SoftAPMode_StaDisconnected_t; + +typedef struct { + int rssi; + uint8 mac[6]; +} Event_SoftAPMode_ProbeReqRecved_t; + +typedef struct { + uint8 old_opmode; + uint8 new_opmode; +} Event_OpMode_Change_t; + +typedef union { + Event_StaMode_Connected_t connected; + Event_StaMode_Disconnected_t disconnected; + Event_StaMode_AuthMode_Change_t auth_change; + Event_StaMode_Got_IP_t got_ip; + Event_SoftAPMode_StaConnected_t sta_connected; + Event_SoftAPMode_StaDisconnected_t sta_disconnected; + Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved; + Event_OpMode_Change_t opmode_changed; +} Event_Info_u; + +typedef struct _esp_event { + uint32 event; + Event_Info_u event_info; +} System_Event_t; + +typedef void (* wifi_event_handler_cb_t)(System_Event_t *event); + +void wifi_set_event_handler_cb(wifi_event_handler_cb_t cb); + +typedef enum wps_type { + WPS_TYPE_DISABLE = 0, + WPS_TYPE_PBC, + WPS_TYPE_PIN, + WPS_TYPE_DISPLAY, + WPS_TYPE_MAX, +} WPS_TYPE_t; + +enum wps_cb_status { + WPS_CB_ST_SUCCESS = 0, + WPS_CB_ST_FAILED, + WPS_CB_ST_TIMEOUT, + WPS_CB_ST_WEP, +}; + +bool wifi_wps_enable(WPS_TYPE_t wps_type); +bool wifi_wps_disable(void); +bool wifi_wps_start(void); + +typedef void (*wps_st_cb_t)(int status); +bool wifi_set_wps_cb(wps_st_cb_t cb); + +typedef void (*freedom_outside_cb_t)(uint8 status); +int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); +void wifi_unregister_send_pkt_freedom_cb(void); +int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq); + +int wifi_rfid_locp_recv_open(void); +void wifi_rfid_locp_recv_close(void); + +typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi); +int wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb); +void wifi_unregister_rfid_locp_recv_cb(void); + +enum FIXED_RATE { + PHY_RATE_48 = 0x8, + PHY_RATE_24 = 0x9, + PHY_RATE_12 = 0xA, + PHY_RATE_6 = 0xB, + PHY_RATE_54 = 0xC, + PHY_RATE_36 = 0xD, + PHY_RATE_18 = 0xE, + PHY_RATE_9 = 0xF, +}; + +#define FIXED_RATE_MASK_NONE 0x00 +#define FIXED_RATE_MASK_STA 0x01 +#define FIXED_RATE_MASK_AP 0x02 +#define FIXED_RATE_MASK_ALL 0x03 + +int wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate); +int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate); + +enum support_rate { + RATE_11B5M = 0, + RATE_11B11M = 1, + RATE_11B1M = 2, + RATE_11B2M = 3, + RATE_11G6M = 4, + RATE_11G12M = 5, + RATE_11G24M = 6, + RATE_11G48M = 7, + RATE_11G54M = 8, + RATE_11G9M = 9, + RATE_11G18M = 10, + RATE_11G36M = 11, +}; + +int wifi_set_user_sup_rate(uint8 min, uint8 max); + +enum RATE_11B_ID { + RATE_11B_B11M = 0, + RATE_11B_B5M = 1, + RATE_11B_B2M = 2, + RATE_11B_B1M = 3, +}; + +enum RATE_11G_ID { + RATE_11G_G54M = 0, + RATE_11G_G48M = 1, + RATE_11G_G36M = 2, + RATE_11G_G24M = 3, + RATE_11G_G18M = 4, + RATE_11G_G12M = 5, + RATE_11G_G9M = 6, + RATE_11G_G6M = 7, + RATE_11G_B5M = 8, + RATE_11G_B2M = 9, + RATE_11G_B1M = 10 +}; + +enum RATE_11N_ID { + RATE_11N_MCS7S = 0, + RATE_11N_MCS7 = 1, + RATE_11N_MCS6 = 2, + RATE_11N_MCS5 = 3, + RATE_11N_MCS4 = 4, + RATE_11N_MCS3 = 5, + RATE_11N_MCS2 = 6, + RATE_11N_MCS1 = 7, + RATE_11N_MCS0 = 8, + RATE_11N_B5M = 9, + RATE_11N_B2M = 10, + RATE_11N_B1M = 11 +}; + +#define RC_LIMIT_11B 0 +#define RC_LIMIT_11G 1 +#define RC_LIMIT_11N 2 +#define RC_LIMIT_P2P_11G 3 +#define RC_LIMIT_P2P_11N 4 +#define RC_LIMIT_NUM 5 + +#define LIMIT_RATE_MASK_NONE 0x00 +#define LIMIT_RATE_MASK_STA 0x01 +#define LIMIT_RATE_MASK_AP 0x02 +#define LIMIT_RATE_MASK_ALL 0x03 + +bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min); +uint8 wifi_get_user_limit_rate_mask(void); +bool wifi_set_user_limit_rate_mask(uint8 enable_mask); + +enum { + USER_IE_BEACON = 0, + USER_IE_PROBE_REQ, + USER_IE_PROBE_RESP, + USER_IE_ASSOC_REQ, + USER_IE_ASSOC_RESP, + USER_IE_MAX +}; + +typedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi); + +bool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len); +int wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb); +void wifi_unregister_user_ie_manufacturer_recv_cb(void); + +void wifi_enable_gpio_wakeup(uint32 i, GPIO_INT_TYPE intr_status); +void wifi_disable_gpio_wakeup(void); + +void uart_div_modify(uint8 uart_no, uint32 DivLatchValue); + +#endif diff --git a/Sming/third-party/ESP8266_NONOS_SDK/include/wpa2_enterprise.h b/Sming/third-party/ESP8266_NONOS_SDK/include/wpa2_enterprise.h new file mode 100644 index 0000000000..9bd0ba516a --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/include/wpa2_enterprise.h @@ -0,0 +1,65 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __WPA2_ENTERPRISE_H__ +#define __WPA2_ENTERPRISE_H__ + +typedef long os_time_t; + +struct os_time { + os_time_t sec; + os_time_t usec; +}; + +typedef int (* get_time_func_t)(struct os_time *t); + +int wifi_station_set_wpa2_enterprise_auth(int enable); + +int wifi_station_set_enterprise_cert_key(u8 *client_cert, int client_cert_len, + u8 *private_key, int private_key_len, + u8 *private_key_passwd, int private_key_passwd_len); +void wifi_station_clear_enterprise_cert_key(void); + +int wifi_station_set_enterprise_ca_cert(u8 *ca_cert, int ca_cert_len); +void wifi_station_clear_enterprise_ca_cert(void); + +int wifi_station_set_enterprise_identity(u8 *identity, int len); +void wifi_station_clear_enterprise_identity(void); + +int wifi_station_set_enterprise_username(u8 *username, int len); +void wifi_station_clear_enterprise_username(void); + +int wifi_station_set_enterprise_password(u8 *password, int len); +void wifi_station_clear_enterprise_password(void); + +int wifi_station_set_enterprise_new_password(u8 *new_password, int len); +void wifi_station_clear_enterprise_new_password(void); + +void wifi_station_set_enterprise_disable_time_check(bool disable); +bool wifi_station_get_enterprise_disable_time_check(void); + +void wpa2_enterprise_set_user_get_time(get_time_func_t cb); + + +#endif /* __WPA2_ENTERPRISE_H__ */ diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.ld new file mode 100644 index 0000000000..a04d3405da --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0x5C000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app1.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app1.ld new file mode 100644 index 0000000000..d5dfa9d732 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app1.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0x6B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app2.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app2.ld new file mode 100644 index 0000000000..624e80ed3b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.1024.app2.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40281010, len = 0x6B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.2048.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.2048.ld new file mode 100644 index 0000000000..f143e4bd70 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.2048.ld @@ -0,0 +1,231 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xE0000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" + diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app1.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app1.ld new file mode 100644 index 0000000000..229ecbdf0c --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app1.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0x2B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app2.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app2.ld new file mode 100644 index 0000000000..4a7f7e2ee9 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.new.512.app2.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40241010, len = 0x2B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app1.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app1.ld new file mode 100644 index 0000000000..d0787e67b4 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app1.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40211000, len = 0x6B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app2.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app2.ld new file mode 100644 index 0000000000..9458e9e207 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.1024.app2.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40291000, len = 0x6B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app1.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app1.ld new file mode 100644 index 0000000000..3db1312049 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app1.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40211000, len = 0x2B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app2.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app2.ld new file mode 100644 index 0000000000..b761c4d70b --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.app.v6.old.512.app2.ld @@ -0,0 +1,230 @@ +/* This linker script generated from xt-genldscripts.tpp for LSP . */ +/* Linker Script for ld -N */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40251000, len = 0x2B000 +} + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + + +/* Default entry point: */ +ENTRY(call_user_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) +PROVIDE(_memmap_vecbase_reset = 0x40000000); +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); +/* _stack_sentry = ALIGN(0x8); */ + } >dram0_0_seg :dram0_0_bss_phdr +/* __stack = 0x3ffc8000; */ + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + + *libat.a:(.literal.* .text.*) + *libcrypto.a:(.literal.* .text.*) + *libespnow.a:(.literal.* .text.*) + *libjson.a:(.literal.* .text.*) + *liblwip.a:(.literal.* .text.*) + *libmesh.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libsmartconfig.a:(.literal.* .text.*) + *libssl.a:(.literal.* .text.*) + *libupgrade.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + *libwps.a:(.literal.* .text.*) + + *libmbedtls.a:(.literal.* .text.*) + + *libm.a:(.literal .text .literal.* .text.*) + + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr +} + +/* get ROM code address */ +INCLUDE "../ld/eagle.rom.addr.v6.ld" diff --git a/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld new file mode 100644 index 0000000000..2628776040 --- /dev/null +++ b/Sming/third-party/ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld @@ -0,0 +1,350 @@ +PROVIDE ( Cache_Read_Disable = 0x400047f0 ); +PROVIDE ( Cache_Read_Enable = 0x40004678 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); +PROVIDE ( GetUartDevice = 0x40003f4c ); +PROVIDE ( MD5Final = 0x40009900 ); +PROVIDE ( MD5Init = 0x40009818 ); +PROVIDE ( MD5Update = 0x40009834 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); +PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); +PROVIDE ( RcvMsg = 0x40003eac ); +PROVIDE ( SHA1Final = 0x4000b648 ); +PROVIDE ( SHA1Init = 0x4000b584 ); +PROVIDE ( SHA1Transform = 0x4000a364 ); +PROVIDE ( SHA1Update = 0x4000b5a8 ); +PROVIDE ( SPI_read_status = 0x400043c8 ); +PROVIDE ( SPI_write_status = 0x40004400 ); +PROVIDE ( SPI_write_enable = 0x4000443c ); +PROVIDE ( Wait_SPI_Idle = 0x4000448c ); +PROVIDE ( Enable_QMode = 0x400044c0 ); +PROVIDE ( SPIEraseArea = 0x40004b44 ); +PROVIDE ( SPIEraseBlock = 0x400049b4 ); +PROVIDE ( SPIEraseChip = 0x40004984 ); +PROVIDE ( SPIEraseSector = 0x40004a00 ); +PROVIDE ( SPILock = 0x400048a8 ); +PROVIDE ( SPIParamCfg = 0x40004c2c ); +PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( SPIReadModeCnfig = 0x400048ec ); +PROVIDE ( SPIUnlock = 0x40004878 ); +PROVIDE ( SPIWrite = 0x40004a4c ); +PROVIDE ( SelectSpiFunction = 0x40003f58 ); +PROVIDE ( SendMsg = 0x40003cf4 ); +PROVIDE ( UartConnCheck = 0x40003230 ); +PROVIDE ( UartConnectProc = 0x400037a0 ); +PROVIDE ( UartDwnLdProc = 0x40003368 ); +PROVIDE ( UartGetCmdLn = 0x40003ef4 ); +PROVIDE ( UartRegReadProc = 0x4000381c ); +PROVIDE ( UartRegWriteProc = 0x400037ac ); +PROVIDE ( UartRxString = 0x40003c30 ); +PROVIDE ( Uart_Init = 0x40003a14 ); +PROVIDE ( _DebugExceptionVector = 0x40000010 ); +PROVIDE ( _DoubleExceptionVector = 0x40000070 ); +PROVIDE ( _KernelExceptionVector = 0x40000030 ); +PROVIDE ( _NMIExceptionVector = 0x40000020 ); +PROVIDE ( _ResetHandler = 0x400000a4 ); +PROVIDE ( _ResetVector = 0x40000080 ); +PROVIDE ( _UserExceptionVector = 0x40000050 ); +PROVIDE ( __adddf3 = 0x4000c538 ); +PROVIDE ( __addsf3 = 0x4000c180 ); +PROVIDE ( __divdf3 = 0x4000cb94 ); +PROVIDE ( __divdi3 = 0x4000ce60 ); +PROVIDE ( __divsi3 = 0x4000dc88 ); +PROVIDE ( __extendsfdf2 = 0x4000cdfc ); +PROVIDE ( __fixdfsi = 0x4000ccb8 ); +PROVIDE ( __fixunsdfsi = 0x4000cd00 ); +PROVIDE ( __fixunssfsi = 0x4000c4c4 ); +PROVIDE ( __floatsidf = 0x4000e2f0 ); +PROVIDE ( __floatsisf = 0x4000e2ac ); +PROVIDE ( __floatunsidf = 0x4000e2e8 ); +PROVIDE ( __floatunsisf = 0x4000e2a4 ); +PROVIDE ( __muldf3 = 0x4000c8f0 ); +PROVIDE ( __muldi3 = 0x40000650 ); +PROVIDE ( __mulsf3 = 0x4000c3dc ); +PROVIDE ( __subdf3 = 0x4000c688 ); +PROVIDE ( __subsf3 = 0x4000c268 ); +PROVIDE ( __truncdfsf2 = 0x4000cd5c ); +PROVIDE ( __udivdi3 = 0x4000d310 ); +PROVIDE ( __udivsi3 = 0x4000e21c ); +PROVIDE ( __umoddi3 = 0x4000d770 ); +PROVIDE ( __umodsi3 = 0x4000e268 ); +PROVIDE ( __umulsidi3 = 0x4000dcf0 ); +PROVIDE ( _rom_store = 0x4000e388 ); +PROVIDE ( _rom_store_table = 0x4000e328 ); +PROVIDE ( _start = 0x4000042c ); +PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); +PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); +PROVIDE ( _xtos_cause3_handler = 0x40000590 ); +PROVIDE ( _xtos_ints_off = 0x4000bda4 ); +PROVIDE ( _xtos_ints_on = 0x4000bd84 ); +PROVIDE ( _xtos_l1int_handler = 0x4000048c ); +PROVIDE ( _xtos_p_none = 0x4000dbf8 ); +PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); +PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); +PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); +PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); +PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); +PROVIDE ( _xtos_set_vpri = 0x40000574 ); +PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); +PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); +PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); +PROVIDE ( aes_decrypt = 0x400092d4 ); +PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); +PROVIDE ( aes_decrypt_init = 0x40008ea4 ); +PROVIDE ( aes_unwrap = 0x40009410 ); +PROVIDE ( base64_decode = 0x40009648 ); +PROVIDE ( base64_encode = 0x400094fc ); +PROVIDE ( bzero = 0x4000de84 ); +PROVIDE ( cmd_parse = 0x40000814 ); +PROVIDE ( conv_str_decimal = 0x40000b24 ); +PROVIDE ( conv_str_hex = 0x40000cb8 ); +PROVIDE ( convert_para_str = 0x40000a60 ); +PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); +PROVIDE ( dtm_params_init = 0x4000269c ); +PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); +PROVIDE ( dtm_set_params = 0x400026dc ); +PROVIDE ( eprintf = 0x40001d14 ); +PROVIDE ( eprintf_init_buf = 0x40001cb8 ); +PROVIDE ( eprintf_to_host = 0x40001d48 ); +PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); +PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); +PROVIDE ( ets_bzero = 0x40002ae8 ); +PROVIDE ( ets_char2xdigit = 0x40002b74 ); +PROVIDE ( ets_delay_us = 0x40002ecc ); +PROVIDE ( ets_enter_sleep = 0x400027b8 ); +PROVIDE ( ets_external_printf = 0x40002578 ); +PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); +PROVIDE ( ets_getc = 0x40002bcc ); +PROVIDE ( ets_install_external_printf = 0x40002450 ); +PROVIDE ( ets_install_putc1 = 0x4000242c ); +PROVIDE ( ets_install_putc2 = 0x4000248c ); +PROVIDE ( ets_install_uart_printf = 0x40002438 ); +PROVIDE ( ets_intr_lock = 0x40000f74 ); +PROVIDE ( ets_intr_unlock = 0x40000f80 ); +PROVIDE ( ets_isr_attach = 0x40000f88 ); +PROVIDE ( ets_isr_mask = 0x40000f98 ); +PROVIDE ( ets_isr_unmask = 0x40000fa8 ); +PROVIDE ( ets_memcmp = 0x400018d4 ); +PROVIDE ( ets_memcpy = 0x400018b4 ); +PROVIDE ( ets_memmove = 0x400018c4 ); +PROVIDE ( ets_memset = 0x400018a4 ); +PROVIDE ( ets_post = 0x40000e24 ); +PROVIDE ( ets_printf = 0x400024cc ); +PROVIDE ( ets_putc = 0x40002be8 ); +PROVIDE ( ets_rtc_int_register = 0x40002a40 ); +PROVIDE ( ets_run = 0x40000e04 ); +PROVIDE ( ets_set_idle_cb = 0x40000dc0 ); +PROVIDE ( ets_set_user_start = 0x40000fbc ); +PROVIDE ( ets_str2macaddr = 0x40002af8 ); +PROVIDE ( ets_strcmp = 0x40002aa8 ); +PROVIDE ( ets_strcpy = 0x40002a88 ); +PROVIDE ( ets_strlen = 0x40002ac8 ); +PROVIDE ( ets_strncmp = 0x40002ab8 ); +PROVIDE ( ets_strncpy = 0x40002a98 ); +PROVIDE ( ets_strstr = 0x40002ad8 ); +PROVIDE ( ets_task = 0x40000dd0 ); +PROVIDE ( ets_timer_arm = 0x40002cc4 ); +PROVIDE ( ets_timer_disarm = 0x40002d40 ); +PROVIDE ( ets_timer_done = 0x40002d80 ); +PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); +PROVIDE ( ets_timer_init = 0x40002e68 ); +PROVIDE ( ets_timer_setfn = 0x40002c48 ); +PROVIDE ( ets_uart_printf = 0x40002544 ); +PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); +PROVIDE ( ets_vprintf = 0x40001f00 ); +PROVIDE ( ets_wdt_disable = 0x400030f0 ); +PROVIDE ( ets_wdt_enable = 0x40002fa0 ); +PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); +PROVIDE ( ets_wdt_init = 0x40003170 ); +PROVIDE ( ets_wdt_restore = 0x40003158 ); +PROVIDE ( ets_write_char = 0x40001da0 ); +PROVIDE ( get_first_seg = 0x4000091c ); +PROVIDE ( gpio_init = 0x40004c50 ); +PROVIDE ( gpio_input_get = 0x40004cf0 ); +PROVIDE ( gpio_intr_ack = 0x40004dcc ); +PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); +PROVIDE ( gpio_intr_pending = 0x40004d88 ); +PROVIDE ( gpio_intr_test = 0x40004efc ); +PROVIDE ( gpio_output_set = 0x40004cd0 ); +PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); +PROVIDE ( gpio_register_get = 0x40004d5c ); +PROVIDE ( gpio_register_set = 0x40004d04 ); +PROVIDE ( hmac_md5 = 0x4000a2cc ); +PROVIDE ( hmac_md5_vector = 0x4000a160 ); +PROVIDE ( hmac_sha1 = 0x4000ba28 ); +PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); +PROVIDE ( lldesc_build_chain = 0x40004f40 ); +PROVIDE ( lldesc_num2link = 0x40005050 ); +PROVIDE ( lldesc_set_owner = 0x4000507c ); +PROVIDE ( main = 0x40000fec ); +PROVIDE ( md5_vector = 0x400097ac ); +PROVIDE ( mem_calloc = 0x40001c2c ); +PROVIDE ( mem_free = 0x400019e0 ); +PROVIDE ( mem_init = 0x40001998 ); +PROVIDE ( mem_malloc = 0x40001b40 ); +PROVIDE ( mem_realloc = 0x40001c6c ); +PROVIDE ( mem_trim = 0x40001a14 ); +PROVIDE ( mem_zalloc = 0x40001c58 ); +PROVIDE ( memcmp = 0x4000dea8 ); +PROVIDE ( memcpy = 0x4000df48 ); +PROVIDE ( memmove = 0x4000e04c ); +PROVIDE ( memset = 0x4000e190 ); +PROVIDE ( multofup = 0x400031c0 ); +PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); +PROVIDE ( phy_get_romfuncs = 0x40006b08 ); +PROVIDE ( rand = 0x40000600 ); +PROVIDE ( rc4_skip = 0x4000dd68 ); +PROVIDE ( recv_packet = 0x40003d08 ); +PROVIDE ( remove_head_space = 0x40000a04 ); +PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); +PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); +PROVIDE ( rom_abs_temp = 0x400060c0 ); +PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); +PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); +PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); +PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); +PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); +PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); +PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); +PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); +PROVIDE ( rom_dc_iq_est = 0x4000615c ); +PROVIDE ( rom_en_pwdet = 0x400061b8 ); +PROVIDE ( rom_get_bb_atten = 0x40006238 ); +PROVIDE ( rom_get_corr_power = 0x40006260 ); +PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); +PROVIDE ( rom_get_noisefloor = 0x40006394 ); +PROVIDE ( rom_get_power_db = 0x400063b0 ); +PROVIDE ( rom_i2c_readReg = 0x40007268 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); +PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); +PROVIDE ( rom_iq_est_disable = 0x40006400 ); +PROVIDE ( rom_iq_est_enable = 0x40006430 ); +PROVIDE ( rom_linear_to_db = 0x40006484 ); +PROVIDE ( rom_mhz2ieee = 0x400065a4 ); +PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); +PROVIDE ( rom_pbus_debugmode = 0x4000737c ); +PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); +PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); +PROVIDE ( rom_pbus_force_test = 0x4000747c ); +PROVIDE ( rom_pbus_rd = 0x400074d8 ); +PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); +PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); +PROVIDE ( rom_pbus_workmode = 0x40007648 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); +PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); +PROVIDE ( rom_phy_reset_req = 0x40007804 ); +PROVIDE ( rom_restart_cal = 0x4000781c ); +PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); +PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); +PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); +PROVIDE ( rom_rfcal_txcap = 0x40008388 ); +PROVIDE ( rom_rfcal_txiq = 0x40008610 ); +PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); +PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); +PROVIDE ( rom_rfpll_reset = 0x40007868 ); +PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); +PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); +PROVIDE ( rom_sar_init = 0x40006738 ); +PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); +PROVIDE ( rom_set_channel_freq = 0x40006c50 ); +PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); +PROVIDE ( rom_set_noise_floor = 0x40006830 ); +PROVIDE ( rom_set_rxclk_en = 0x40006550 ); +PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); +PROVIDE ( rom_set_txclk_en = 0x4000650c ); +PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); +PROVIDE ( rom_start_noisefloor = 0x40006874 ); +PROVIDE ( rom_start_tx_tone = 0x400068b4 ); +PROVIDE ( rom_stop_tx_tone = 0x4000698c ); +PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); +PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); +PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); +PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); +PROVIDE ( roundup2 = 0x400031b4 ); +PROVIDE ( rtc_enter_sleep = 0x40002870 ); +PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); +PROVIDE ( rtc_intr_handler = 0x400029ec ); +PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); +PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); +PROVIDE ( save_tsf_us = 0x400027ac ); +PROVIDE ( send_packet = 0x40003c80 ); +PROVIDE ( sha1_prf = 0x4000ba48 ); +PROVIDE ( sha1_vector = 0x4000a2ec ); +PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); +PROVIDE ( sip_get_ptr = 0x400058a8 ); +PROVIDE ( sip_get_state = 0x40005668 ); +PROVIDE ( sip_init_attach = 0x4000567c ); +PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); +PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); +PROVIDE ( sip_post = 0x400050fc ); +PROVIDE ( sip_post_init = 0x400056c4 ); +PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); +PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); +PROVIDE ( sip_send = 0x40005808 ); +PROVIDE ( sip_to_host_chain_append = 0x40005864 ); +PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); +PROVIDE ( slc_add_credits = 0x400060ac ); +PROVIDE ( slc_enable = 0x40005d90 ); +PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); +PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); +PROVIDE ( slc_init_attach = 0x40005c50 ); +PROVIDE ( slc_init_credit = 0x4000608c ); +PROVIDE ( slc_pause_from_host = 0x40006014 ); +PROVIDE ( slc_reattach = 0x40005c1c ); +PROVIDE ( slc_resume_from_host = 0x4000603c ); +PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); +PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); +PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); +PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); +PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); +PROVIDE ( software_reset = 0x4000264c ); +PROVIDE ( spi_flash_attach = 0x40004644 ); +PROVIDE ( srand = 0x400005f0 ); +PROVIDE ( strcmp = 0x4000bdc8 ); +PROVIDE ( strcpy = 0x4000bec8 ); +PROVIDE ( strlen = 0x4000bf4c ); +PROVIDE ( strncmp = 0x4000bfa8 ); +PROVIDE ( strncpy = 0x4000c0a0 ); +PROVIDE ( strstr = 0x4000e1e0 ); +PROVIDE ( timer_insert = 0x40002c64 ); +PROVIDE ( uartAttach = 0x4000383c ); +PROVIDE ( uart_baudrate_detect = 0x40003924 ); +PROVIDE ( uart_buff_switch = 0x400038a4 ); +PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); +PROVIDE ( uart_rx_one_char = 0x40003b8c ); +PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); +PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); +PROVIDE ( uart_tx_one_char = 0x40003b30 ); +PROVIDE ( wepkey_128 = 0x4000bc40 ); +PROVIDE ( wepkey_64 = 0x4000bb3c ); +PROVIDE ( xthal_bcopy = 0x40000688 ); +PROVIDE ( xthal_copy123 = 0x4000074c ); +PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); +PROVIDE ( xthal_get_ccount = 0x4000dd38 ); +PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); +PROVIDE ( xthal_get_intread = 0x4000dd58 ); +PROVIDE ( xthal_memcpy = 0x400006c4 ); +PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); +PROVIDE ( xthal_set_intclear = 0x4000dd60 ); +PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); +PROVIDE ( xthal_window_spill = 0x4000e324 ); +PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); + +PROVIDE ( Te0 = 0x3fffccf0 ); +PROVIDE ( Td0 = 0x3fffd100 ); +PROVIDE ( Td4s = 0x3fffd500); +PROVIDE ( rcons = 0x3fffd0f0); +PROVIDE ( UartDev = 0x3fffde10 ); +PROVIDE ( flashchip = 0x3fffc714); diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libairkiss.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libairkiss.a new file mode 100644 index 0000000000000000000000000000000000000000..cfdcc842341cb9e41914587dec9f211fad74fc27 GIT binary patch literal 11298 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 literal 0 HcmV?d00001 diff --git a/Sming/third-party/ESP8266_NONOS_SDK/lib/libat.a b/Sming/third-party/ESP8266_NONOS_SDK/lib/libat.a new file mode 100755 index 0000000000000000000000000000000000000000..06e11e62c061b9b35a473a3d952a51cac7bee948 GIT binary patch literal 394948 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�#clPjx;nmrH{bqY-YhYkY^u$FExvQMx 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